lebedev.ri created this revision.
lebedev.ri added reviewers: rjmccall, erichkeane, rsmith, vsk.
lebedev.ri added a project: LLVM.
Herald added subscribers: llvm-commits, Sanitizers, cfe-commits, dexonsmith, 
mehdi_amini.
Herald added projects: clang, Sanitizers.

Implicit Conversion Sanitizer is *almost* feature complete.
There aren't *that* much unsanitized things left,
two major ones are increment/decrement (this patch) and bit fields.

As it was discussed in PR39519 <https://bugs.llvm.org/show_bug.cgi?id=39519>,
unlike `CompoundAssignOperator` (which is promoted internally),
or `BinaryOperator` (for which we always have promotion/demotion in AST)
or parts of `UnaryOperator` (we have promotion/demotion but only for certain 
operations),
for inc/dec, clang omits promotion/demotion altogether, under as-if rule.

This is technically correct: https://rise4fun.com/Alive/zPgD
As it can be seen in `InstCombineCasts.cpp` `canEvaluateTruncated()`,
`add`/`sub`/`mul`/`and`/`or`/`xor` operators can all arbitrarily be extended or 
truncated:
https://github.com/llvm/llvm-project/blob/901cd3b3f62d0c700e5d2c3f97eff97d634bec5e/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp#L1320-L1334

But that has serious implications:

1. Since we no longer model implicit casts, do we pessimize their AST 
representation and everything that uses it?
2. There is no demotion, so lossy demotion sanitizer does not trigger :]

Now, i'm not going to argue about the first problem here,
but the second one **needs** to be addressed.
As it was stated in the report, this is done intentionally,
so changing this in all modes would be considered a penalization/regression.

Which means, the sanitization-less codegen must not be altered.
It was also suggested to not change the sanitized codegen to the one with 
demotion,
but i quite strongly believe that will not be the wise choice here:

1. One will need to re-engineer the check that the inc/dec was lossy in terms 
of `@llvm.{u,s}{add,sub}.with.overflow` builtins
2. We will still need to compute the result we would lossily demote.
3. I suspect it would need to be done right here, in sanitization. Which kinda 
defeats the point of using `@llvm.{u,s}{add,sub}.with.overflow` builtins.
4. OR, we would need to do that in the compiler-rt handler. Which means we'll 
need a whole new handler. Also doesn't really see all that worthwhile to me.
5. At least X86 (but likely others) pessimizes all sub-`i32` operations (due to 
partial register stalls), so even if we avoid promotion+demotion, the 
computations will //likely// be performed in `i32` anyways.

While looking into this, i have noticed a few more LLVM middle-end missed 
canonicalizations,
and filed PR44100 <https://bugs.llvm.org/show_bug.cgi?id=44100>,
PR44102 <https://bugs.llvm.org/show_bug.cgi?id=44102>.

Those are not specific to inc/dec, we also have them for 
`CompoundAssignOperator`,
and it can happen for normal arithmetics, too.  But if we take some other path 
in the patch,
it will not be applicable here, and we will have most likely played ourselves.

TLDR: front-end should emit canonical, easy-to-optimize yet un-optimized code.
It is middle-end's job to make it optimal.

I'm really hoping reviewers agree with my personal assessment of the path this 
patch should take..

Fixes PR44054 <https://bugs.llvm.org/show_bug.cgi?id=44054>.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D70539

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/CodeGen/CGExprScalar.cpp
  clang/test/CodeGen/catch-implicit-conversions-incdec-basics.c
  
clang/test/CodeGen/catch-implicit-integer-arithmetic-value-change-incdec-basics.c
  clang/test/CodeGen/catch-implicit-integer-conversions-incdec-basics.c
  clang/test/CodeGen/catch-implicit-integer-sign-changes-incdec-basics.c
  clang/test/CodeGen/catch-implicit-integer-truncations-incdec-basics.c
  clang/test/CodeGen/catch-implicit-signed-integer-truncations-incdec-basics.c
  clang/test/CodeGen/catch-implicit-signed-integer-truncations-incdec.c
  clang/test/CodeGen/catch-implicit-unsigned-integer-truncations-incdec-basics.c
  
compiler-rt/test/ubsan/TestCases/ImplicitConversion/signed-integer-truncation-incdec.c

Index: compiler-rt/test/ubsan/TestCases/ImplicitConversion/signed-integer-truncation-incdec.c
===================================================================
--- /dev/null
+++ compiler-rt/test/ubsan/TestCases/ImplicitConversion/signed-integer-truncation-incdec.c
@@ -0,0 +1,122 @@
+// RUN: %clang   -x c   -fsanitize=implicit-signed-integer-truncation -O0 %s -o %t && %run %t 2>&1 | FileCheck %s --implicit-check-not="implicit conversion" --check-prefixes=CHECK
+// RUN: %clang   -x c   -fsanitize=implicit-signed-integer-truncation -O1 %s -o %t && %run %t 2>&1 | FileCheck %s --implicit-check-not="implicit conversion" --check-prefixes=CHECK
+// RUN: %clang   -x c   -fsanitize=implicit-signed-integer-truncation -O2 %s -o %t && %run %t 2>&1 | FileCheck %s --implicit-check-not="implicit conversion" --check-prefixes=CHECK
+// RUN: %clang   -x c   -fsanitize=implicit-signed-integer-truncation -O3 %s -o %t && %run %t 2>&1 | FileCheck %s --implicit-check-not="implicit conversion" --check-prefixes=CHECK
+
+// RUN: %clang   -x c++ -fsanitize=implicit-signed-integer-truncation -O0 %s -o %t && %run %t 2>&1 | FileCheck %s --implicit-check-not="implicit conversion" --check-prefixes=CHECK
+// RUN: %clang   -x c++ -fsanitize=implicit-signed-integer-truncation -O1 %s -o %t && %run %t 2>&1 | FileCheck %s --implicit-check-not="implicit conversion" --check-prefixes=CHECK
+// RUN: %clang   -x c++ -fsanitize=implicit-signed-integer-truncation -O2 %s -o %t && %run %t 2>&1 | FileCheck %s --implicit-check-not="implicit conversion" --check-prefixes=CHECK
+// RUN: %clang   -x c++ -fsanitize=implicit-signed-integer-truncation -O3 %s -o %t && %run %t 2>&1 | FileCheck %s --implicit-check-not="implicit conversion" --check-prefixes=CHECK
+
+void test_unsigned() {
+  unsigned char x;
+
+  x = 0;
+  x++;
+  x = 0;
+  ++x;
+
+  x = 0;
+  x--;
+  // CHECK: {{.*}}signed-integer-truncation-incdec.c:[[@LINE-1]]:4: runtime error: implicit conversion from type 'int' of value -1 (32-bit, signed) to type 'unsigned char' changed the value to 255 (8-bit, unsigned)
+  x = 0;
+  --x;
+  // CHECK: {{.*}}signed-integer-truncation-incdec.c:[[@LINE-1]]:3: runtime error: implicit conversion from type 'int' of value -1 (32-bit, signed) to type 'unsigned char' changed the value to 255 (8-bit, unsigned)
+
+  x = 1;
+  x++;
+  x = 1;
+  ++x;
+
+  x = 1;
+  x--;
+  x = 1;
+  --x;
+
+  x = 254;
+  x++;
+  x = 254;
+  ++x;
+
+  x = 254;
+  x--;
+  x = 254;
+  --x;
+
+  x = 255;
+  x++;
+  // CHECK: {{.*}}signed-integer-truncation-incdec.c:[[@LINE-1]]:4: runtime error: implicit conversion from type 'int' of value 256 (32-bit, signed) to type 'unsigned char' changed the value to 0 (8-bit, unsigned)
+  x = 255;
+  ++x;
+  // CHECK: {{.*}}signed-integer-truncation-incdec.c:[[@LINE-1]]:3: runtime error: implicit conversion from type 'int' of value 256 (32-bit, signed) to type 'unsigned char' changed the value to 0 (8-bit, unsigned)
+
+  x = 255;
+  x--;
+  x = 255;
+  --x;
+}
+
+void test_signed() {
+  signed char x;
+
+  x = -128;
+  x++;
+  x = -128;
+  ++x;
+
+  x = -128;
+  x--;
+  // CHECK: {{.*}}signed-integer-truncation-incdec.c:[[@LINE-1]]:4: runtime error: implicit conversion from type 'int' of value -129 (32-bit, signed) to type 'signed char' changed the value to 127 (8-bit, signed)
+  x = -128;
+  --x;
+  // CHECK: {{.*}}signed-integer-truncation-incdec.c:[[@LINE-1]]:3: runtime error: implicit conversion from type 'int' of value -129 (32-bit, signed) to type 'signed char' changed the value to 127 (8-bit, signed)
+
+  x = -1;
+  x++;
+  x = -1;
+  ++x;
+
+  x = -1;
+  x--;
+  x = -1;
+  --x;
+
+  x = 0;
+  x++;
+  x = 0;
+  ++x;
+
+  x = 0;
+  x--;
+  x = 0;
+  --x;
+
+  x = 1;
+  x++;
+  x = 1;
+  ++x;
+
+  x = 1;
+  x--;
+  x = 1;
+  --x;
+
+  x = 127;
+  x++;
+  // CHECK: {{.*}}signed-integer-truncation-incdec.c:[[@LINE-1]]:4: runtime error: implicit conversion from type 'int' of value 128 (32-bit, signed) to type 'signed char' changed the value to -128 (8-bit, signed)
+  x = 127;
+  ++x;
+  // CHECK: {{.*}}signed-integer-truncation-incdec.c:[[@LINE-1]]:3: runtime error: implicit conversion from type 'int' of value 128 (32-bit, signed) to type 'signed char' changed the value to -128 (8-bit, signed)
+
+  x = 127;
+  x--;
+  x = 127;
+  --x;
+}
+
+int main() {
+  test_unsigned();
+  test_signed();
+
+  return 0;
+}
Index: clang/test/CodeGen/catch-implicit-unsigned-integer-truncations-incdec-basics.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/catch-implicit-unsigned-integer-truncations-incdec-basics.c
@@ -0,0 +1,101 @@
+// RUN: %clang_cc1 -fsanitize=implicit-unsigned-integer-truncation -fsanitize-recover=implicit-unsigned-integer-truncation -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_implicit_conversion" --check-prefixes=CHECK
+
+// CHECK-LABEL: @t0(
+unsigned short t0(unsigned short x) {
+#line 100
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t1(
+unsigned short t1(unsigned short x) {
+#line 200
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t2(
+unsigned short t2(unsigned short x) {
+#line 300
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t3(
+unsigned short t3(unsigned short x) {
+#line 400
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t4(
+signed short t4(signed short x) {
+#line 500
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t5(
+signed short t5(signed short x) {
+#line 600
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t6(
+signed short t6(signed short x) {
+#line 700
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t7(
+signed short t7(signed short x) {
+#line 800
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t8(
+unsigned char t8(unsigned char x) {
+#line 900
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t9(
+unsigned char t9(unsigned char x) {
+#line 1000
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t10(
+unsigned char t10(unsigned char x) {
+#line 1100
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t11(
+unsigned char t11(unsigned char x) {
+#line 1200
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t12(
+signed char t12(signed char x) {
+#line 1300
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t13(
+signed char t13(signed char x) {
+#line 1400
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t14(
+signed char t14(signed char x) {
+#line 1500
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t15(
+signed char t15(signed char x) {
+#line 1600
+  --x;
+  return x;
+}
Index: clang/test/CodeGen/catch-implicit-signed-integer-truncations-incdec.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/catch-implicit-signed-integer-truncations-incdec.c
@@ -0,0 +1,304 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-NOSANITIZE
+
+// RUN: %clang_cc1 -fsanitize=implicit-signed-integer-truncation -fno-sanitize-recover=implicit-signed-integer-truncation -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_implicit_conversion" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER,CHECK-SANITIZE-UNREACHABLE
+// RUN: %clang_cc1 -fsanitize=implicit-signed-integer-truncation -fsanitize-recover=implicit-signed-integer-truncation -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_implicit_conversion" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER
+// RUN: %clang_cc1 -fsanitize=implicit-signed-integer-truncation -fsanitize-trap=implicit-signed-integer-truncation -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_implicit_conversion" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE
+
+// CHECK-SANITIZE-ANYRECOVER-DAG: @[[INT:.*]] = {{.*}} c"'int'\00" }
+// CHECK-SANITIZE-ANYRECOVER-DAG: @[[UNSIGNED_SHORT:.*]] = {{.*}} c"'unsigned short'\00" }
+// CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_100:.*]] = {{.*}}, i32 100, i32 11 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_200:.*]] = {{.*}}, i32 200, i32 11 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_300:.*]] = {{.*}}, i32 300, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_400:.*]] = {{.*}}, i32 400, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER-DAG: @[[SHORT:.*]] = {{.*}} c"'short'\00" }
+// CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_500:.*]] = {{.*}}, i32 500, i32 11 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_600:.*]] = {{.*}}, i32 600, i32 11 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_700:.*]] = {{.*}}, i32 700, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER-DAG: @[[LINE_800:.*]] = {{.*}}, i32 800, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+
+unsigned short t0(unsigned short x) {
+// CHECK-NOSANITIZE-LABEL: @t0(
+// CHECK-NOSANITIZE-NEXT:  entry:
+// CHECK-NOSANITIZE-NEXT:    [[X_ADDR:%.*]] = alloca i16, align 2
+// CHECK-NOSANITIZE-NEXT:    store i16 [[X:%.*]], i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    [[X_RELOADED:%.*]] = load i16, i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    [[INC:%.*]] = add i16 [[X_RELOADED]], 1
+// CHECK-NOSANITIZE-NEXT:    store i16 [[INC]], i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    ret i16 [[X_RELOADED]]
+//
+// CHECK-SANITIZE-LABEL:            @t0(
+// CHECK-SANITIZE-NEXT:             entry:
+// CHECK-SANITIZE-NEXT:               [[X_ADDR:%.*]] = alloca i16, align 2
+// CHECK-SANITIZE-NEXT:               store i16 [[X:%.*]], i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               [[X_RELOADED:%.*]] = load i16, i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED:%.*]] = zext i16 [[X_RELOADED]] to i32
+// CHECK-SANITIZE-NEXT:               [[INC:%.*]] = add i32 [[X_PROMOTED]], 1
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED_DEMOTED:%.*]] = trunc i32 [[INC]] to i16
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED_DEMOTED_PROMOTED:%.*]] = zext i16 [[X_PROMOTED_DEMOTED]] to i32, !nosanitize
+// CHECK-SANITIZE-NEXT:               [[TRUNCHECK:%.*]] = icmp eq i32 [[X_PROMOTED_DEMOTED_PROMOTED]], [[INC]], !nosanitize
+// CHECK-SANITIZE-NEXT:               br i1 [[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_X_PROMOTEDERSION:[^,]+]],{{.*}} !nosanitize
+// CHECK-SANITIZE:                  [[HANDLER_IMPLICIT_X_PROMOTEDERSION]]:
+// CHECK-SANITIZE-TRAP-NEXT:          call void @llvm.trap(){{.*}}, !nosanitize
+// CHECK-SANITIZE-ANYRECOVER-NEXT:    [[TMP1:%.*]] = zext i32 [[INC]] to i64, !nosanitize
+// CHECK-SANITIZE-ANYRECOVER-NEXT:    [[TMP2:%.*]] = zext i16 [[X_PROMOTED_DEMOTED]] to i64, !nosanitize
+// CHECK-SANITIZE-NORECOVER-NEXT:     call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ { [97 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }*, { i16, i16, [17 x i8] }*, i8 }* @[[LINE_100]] to i8*), i64 [[TMP1]], i64 [[TMP2]]) #2, !nosanitize
+// CHECK-SANITIZE-RECOVER-NEXT:       call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ { [97 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }*, { i16, i16, [17 x i8] }*, i8 }* @[[LINE_100]] to i8*), i64 [[TMP1]], i64 [[TMP2]]) #2, !nosanitize
+// CHECK-SANITIZE-UNREACHABLE-NEXT:   unreachable, !nosanitize
+// CHECK-SANITIZE-RECOVER-NEXT:       br label %[[CONT]], !nosanitize
+// CHECK-SANITIZE:                  [[CONT]]:
+// CHECK-SANITIZE-NEXT:               store i16 [[X_PROMOTED_DEMOTED]], i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               ret i16 [[X_RELOADED]]
+#line 100
+  return x++;
+}
+unsigned short t1(unsigned short x) {
+// CHECK-NOSANITIZE-LABEL: @t1(
+// CHECK-NOSANITIZE-NEXT:  entry:
+// CHECK-NOSANITIZE-NEXT:    [[X_ADDR:%.*]] = alloca i16, align 2
+// CHECK-NOSANITIZE-NEXT:    store i16 [[X:%.*]], i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    [[X_RELOADED:%.*]] = load i16, i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    [[INC:%.*]] = add i16 [[X_RELOADED]], -1
+// CHECK-NOSANITIZE-NEXT:    store i16 [[INC]], i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    ret i16 [[X_RELOADED]]
+//
+// CHECK-SANITIZE-LABEL:            @t1(
+// CHECK-SANITIZE-NEXT:             entry:
+// CHECK-SANITIZE-NEXT:               [[X_ADDR:%.*]] = alloca i16, align 2
+// CHECK-SANITIZE-NEXT:               store i16 [[X:%.*]], i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               [[X_RELOADED:%.*]] = load i16, i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED:%.*]] = zext i16 [[X_RELOADED]] to i32
+// CHECK-SANITIZE-NEXT:               [[INC:%.*]] = add i32 [[X_PROMOTED]], -1
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED_DEMOTED:%.*]] = trunc i32 [[INC]] to i16
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED_DEMOTED_PROMOTED:%.*]] = zext i16 [[X_PROMOTED_DEMOTED]] to i32, !nosanitize
+// CHECK-SANITIZE-NEXT:               [[TRUNCHECK:%.*]] = icmp eq i32 [[X_PROMOTED_DEMOTED_PROMOTED]], [[INC]], !nosanitize
+// CHECK-SANITIZE-NEXT:               br i1 [[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_X_PROMOTEDERSION:[^,]+]],{{.*}} !nosanitize
+// CHECK-SANITIZE:                  [[HANDLER_IMPLICIT_X_PROMOTEDERSION]]:
+// CHECK-SANITIZE-TRAP-NEXT:          call void @llvm.trap(){{.*}}, !nosanitize
+// CHECK-SANITIZE-ANYRECOVER-NEXT:    [[TMP1:%.*]] = zext i32 [[INC]] to i64, !nosanitize
+// CHECK-SANITIZE-ANYRECOVER-NEXT:    [[TMP2:%.*]] = zext i16 [[X_PROMOTED_DEMOTED]] to i64, !nosanitize
+// CHECK-SANITIZE-NORECOVER-NEXT:     call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ { [97 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }*, { i16, i16, [17 x i8] }*, i8 }* @[[LINE_200]] to i8*), i64 [[TMP1]], i64 [[TMP2]]) #2, !nosanitize
+// CHECK-SANITIZE-RECOVER-NEXT:       call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ { [97 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }*, { i16, i16, [17 x i8] }*, i8 }* @[[LINE_200]] to i8*), i64 [[TMP1]], i64 [[TMP2]]) #2, !nosanitize
+// CHECK-SANITIZE-UNREACHABLE-NEXT:   unreachable, !nosanitize
+// CHECK-SANITIZE-RECOVER-NEXT:       br label %[[CONT]], !nosanitize
+// CHECK-SANITIZE:                  [[CONT]]:
+// CHECK-SANITIZE-NEXT:               store i16 [[X_PROMOTED_DEMOTED]], i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               ret i16 [[X_RELOADED]]
+#line 200
+  return x--;
+}
+
+unsigned short t2(unsigned short x) {
+// CHECK-NOSANITIZE-LABEL: @t2(
+// CHECK-NOSANITIZE-NEXT:  entry:
+// CHECK-NOSANITIZE-NEXT:    [[X_ADDR:%.*]] = alloca i16, align 2
+// CHECK-NOSANITIZE-NEXT:    store i16 [[X:%.*]], i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    [[X_RELOADED:%.*]] = load i16, i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    [[INC:%.*]] = add i16 [[X_RELOADED]], 1
+// CHECK-NOSANITIZE-NEXT:    store i16 [[INC]], i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    ret i16 [[INC]]
+//
+// CHECK-SANITIZE-LABEL:            @t2(
+// CHECK-SANITIZE-NEXT:             entry:
+// CHECK-SANITIZE-NEXT:               [[X_ADDR:%.*]] = alloca i16, align 2
+// CHECK-SANITIZE-NEXT:               store i16 [[X:%.*]], i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               [[X_RELOADED:%.*]] = load i16, i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED:%.*]] = zext i16 [[X_RELOADED]] to i32
+// CHECK-SANITIZE-NEXT:               [[INC:%.*]] = add i32 [[X_PROMOTED]], 1
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED_DEMOTED:%.*]] = trunc i32 [[INC]] to i16
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED_DEMOTED_PROMOTED:%.*]] = zext i16 [[X_PROMOTED_DEMOTED]] to i32, !nosanitize
+// CHECK-SANITIZE-NEXT:               [[TRUNCHECK:%.*]] = icmp eq i32 [[X_PROMOTED_DEMOTED_PROMOTED]], [[INC]], !nosanitize
+// CHECK-SANITIZE-NEXT:               br i1 [[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_X_PROMOTEDERSION:[^,]+]],{{.*}} !nosanitize
+// CHECK-SANITIZE:                  [[HANDLER_IMPLICIT_X_PROMOTEDERSION]]:
+// CHECK-SANITIZE-TRAP-NEXT:          call void @llvm.trap(){{.*}}, !nosanitize
+// CHECK-SANITIZE-ANYRECOVER-NEXT:    [[TMP1:%.*]] = zext i32 [[INC]] to i64, !nosanitize
+// CHECK-SANITIZE-ANYRECOVER-NEXT:    [[TMP2:%.*]] = zext i16 [[X_PROMOTED_DEMOTED]] to i64, !nosanitize
+// CHECK-SANITIZE-NORECOVER-NEXT:     call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ { [97 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }*, { i16, i16, [17 x i8] }*, i8 }* @[[LINE_300]] to i8*), i64 [[TMP1]], i64 [[TMP2]]) #2, !nosanitize
+// CHECK-SANITIZE-RECOVER-NEXT:       call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ { [97 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }*, { i16, i16, [17 x i8] }*, i8 }* @[[LINE_300]] to i8*), i64 [[TMP1]], i64 [[TMP2]]) #2, !nosanitize
+// CHECK-SANITIZE-UNREACHABLE-NEXT:   unreachable, !nosanitize
+// CHECK-SANITIZE-RECOVER-NEXT:       br label %[[CONT]], !nosanitize
+// CHECK-SANITIZE:                  [[CONT]]:
+// CHECK-SANITIZE-NEXT:               store i16 [[X_PROMOTED_DEMOTED]], i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               ret i16 [[X_PROMOTED_DEMOTED]]
+#line 300
+  return ++x;
+}
+
+unsigned short t3(unsigned short x) {
+// CHECK-NOSANITIZE-LABEL: @t3(
+// CHECK-NOSANITIZE-NEXT:  entry:
+// CHECK-NOSANITIZE-NEXT:    [[X_ADDR:%.*]] = alloca i16, align 2
+// CHECK-NOSANITIZE-NEXT:    store i16 [[X:%.*]], i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    [[X_RELOADED:%.*]] = load i16, i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    [[INC:%.*]] = add i16 [[X_RELOADED]], -1
+// CHECK-NOSANITIZE-NEXT:    store i16 [[INC]], i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    ret i16 [[INC]]
+//
+// CHECK-SANITIZE-LABEL:            @t3(
+// CHECK-SANITIZE-NEXT:             entry:
+// CHECK-SANITIZE-NEXT:               [[X_ADDR:%.*]] = alloca i16, align 2
+// CHECK-SANITIZE-NEXT:               store i16 [[X:%.*]], i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               [[X_RELOADED:%.*]] = load i16, i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED:%.*]] = zext i16 [[X_RELOADED]] to i32
+// CHECK-SANITIZE-NEXT:               [[INC:%.*]] = add i32 [[X_PROMOTED]], -1
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED_DEMOTED:%.*]] = trunc i32 [[INC]] to i16
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED_DEMOTED_PROMOTED:%.*]] = zext i16 [[X_PROMOTED_DEMOTED]] to i32, !nosanitize
+// CHECK-SANITIZE-NEXT:               [[TRUNCHECK:%.*]] = icmp eq i32 [[X_PROMOTED_DEMOTED_PROMOTED]], [[INC]], !nosanitize
+// CHECK-SANITIZE-NEXT:               br i1 [[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_X_PROMOTEDERSION:[^,]+]],{{.*}} !nosanitize
+// CHECK-SANITIZE:                  [[HANDLER_IMPLICIT_X_PROMOTEDERSION]]:
+// CHECK-SANITIZE-TRAP-NEXT:          call void @llvm.trap(){{.*}}, !nosanitize
+// CHECK-SANITIZE-ANYRECOVER-NEXT:    [[TMP1:%.*]] = zext i32 [[INC]] to i64, !nosanitize
+// CHECK-SANITIZE-ANYRECOVER-NEXT:    [[TMP2:%.*]] = zext i16 [[X_PROMOTED_DEMOTED]] to i64, !nosanitize
+// CHECK-SANITIZE-NORECOVER-NEXT:     call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ { [97 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }*, { i16, i16, [17 x i8] }*, i8 }* @[[LINE_400]] to i8*), i64 [[TMP1]], i64 [[TMP2]]) #2, !nosanitize
+// CHECK-SANITIZE-RECOVER-NEXT:       call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ { [97 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }*, { i16, i16, [17 x i8] }*, i8 }* @[[LINE_400]] to i8*), i64 [[TMP1]], i64 [[TMP2]]) #2, !nosanitize
+// CHECK-SANITIZE-UNREACHABLE-NEXT:   unreachable, !nosanitize
+// CHECK-SANITIZE-RECOVER-NEXT:       br label %[[CONT]], !nosanitize
+// CHECK-SANITIZE:                  [[CONT]]:
+// CHECK-SANITIZE-NEXT:               store i16 [[X_PROMOTED_DEMOTED]], i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               ret i16 [[X_PROMOTED_DEMOTED]]
+#line 400
+  return --x;
+}
+
+signed short t4(signed short x) {
+// CHECK-NOSANITIZE-LABEL: @t4(
+// CHECK-NOSANITIZE-NEXT:  entry:
+// CHECK-NOSANITIZE-NEXT:    [[X_ADDR:%.*]] = alloca i16, align 2
+// CHECK-NOSANITIZE-NEXT:    store i16 [[X:%.*]], i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    [[X_RELOADED:%.*]] = load i16, i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    [[INC:%.*]] = add i16 [[X_RELOADED]], 1
+// CHECK-NOSANITIZE-NEXT:    store i16 [[INC]], i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    ret i16 [[X_RELOADED]]
+//
+// CHECK-SANITIZE-LABEL:            @t4(
+// CHECK-SANITIZE-NEXT:             entry:
+// CHECK-SANITIZE-NEXT:               [[X_ADDR:%.*]] = alloca i16, align 2
+// CHECK-SANITIZE-NEXT:               store i16 [[X:%.*]], i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               [[X_RELOADED:%.*]] = load i16, i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED:%.*]] = sext i16 [[X_RELOADED]] to i32
+// CHECK-SANITIZE-NEXT:               [[INC:%.*]] = add i32 [[X_PROMOTED]], 1
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED_DEMOTED:%.*]] = trunc i32 [[INC]] to i16
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED_DEMOTED_PROMOTED:%.*]] = sext i16 [[X_PROMOTED_DEMOTED]] to i32, !nosanitize
+// CHECK-SANITIZE-NEXT:               [[TRUNCHECK:%.*]] = icmp eq i32 [[X_PROMOTED_DEMOTED_PROMOTED]], [[INC]], !nosanitize
+// CHECK-SANITIZE-NEXT:               br i1 [[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_X_PROMOTEDERSION:[^,]+]],{{.*}} !nosanitize
+// CHECK-SANITIZE:                  [[HANDLER_IMPLICIT_X_PROMOTEDERSION]]:
+// CHECK-SANITIZE-TRAP-NEXT:          call void @llvm.trap(){{.*}}, !nosanitize
+// CHECK-SANITIZE-ANYRECOVER-NEXT:    [[TMP1:%.*]] = zext i32 [[INC]] to i64, !nosanitize
+// CHECK-SANITIZE-ANYRECOVER-NEXT:    [[TMP2:%.*]] = zext i16 [[X_PROMOTED_DEMOTED]] to i64, !nosanitize
+// CHECK-SANITIZE-NORECOVER-NEXT:     call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ { [97 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }*, { i16, i16, [8 x i8] }*, i8 }* @[[LINE_500]] to i8*), i64 [[TMP1]], i64 [[TMP2]]) #2, !nosanitize
+// CHECK-SANITIZE-RECOVER-NEXT:       call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ { [97 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }*, { i16, i16, [8 x i8] }*, i8 }* @[[LINE_500]] to i8*), i64 [[TMP1]], i64 [[TMP2]]) #2, !nosanitize
+// CHECK-SANITIZE-UNREACHABLE-NEXT:   unreachable, !nosanitize
+// CHECK-SANITIZE-RECOVER-NEXT:       br label %[[CONT]], !nosanitize
+// CHECK-SANITIZE:                  [[CONT]]:
+// CHECK-SANITIZE-NEXT:               store i16 [[X_PROMOTED_DEMOTED]], i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               ret i16 [[X_RELOADED]]
+#line 500
+  return x++;
+}
+signed short t5(signed short x) {
+// CHECK-NOSANITIZE-LABEL: @t5(
+// CHECK-NOSANITIZE-NEXT:  entry:
+// CHECK-NOSANITIZE-NEXT:    [[X_ADDR:%.*]] = alloca i16, align 2
+// CHECK-NOSANITIZE-NEXT:    store i16 [[X:%.*]], i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    [[X_RELOADED:%.*]] = load i16, i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    [[INC:%.*]] = add i16 [[X_RELOADED]], -1
+// CHECK-NOSANITIZE-NEXT:    store i16 [[INC]], i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    ret i16 [[X_RELOADED]]
+//
+// CHECK-SANITIZE-LABEL:            @t5(
+// CHECK-SANITIZE-NEXT:             entry:
+// CHECK-SANITIZE-NEXT:               [[X_ADDR:%.*]] = alloca i16, align 2
+// CHECK-SANITIZE-NEXT:               store i16 [[X:%.*]], i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               [[X_RELOADED:%.*]] = load i16, i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED:%.*]] = sext i16 [[X_RELOADED]] to i32
+// CHECK-SANITIZE-NEXT:               [[INC:%.*]] = add i32 [[X_PROMOTED]], -1
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED_DEMOTED:%.*]] = trunc i32 [[INC]] to i16
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED_DEMOTED_PROMOTED:%.*]] = sext i16 [[X_PROMOTED_DEMOTED]] to i32, !nosanitize
+// CHECK-SANITIZE-NEXT:               [[TRUNCHECK:%.*]] = icmp eq i32 [[X_PROMOTED_DEMOTED_PROMOTED]], [[INC]], !nosanitize
+// CHECK-SANITIZE-NEXT:               br i1 [[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_X_PROMOTEDERSION:[^,]+]],{{.*}} !nosanitize
+// CHECK-SANITIZE:                  [[HANDLER_IMPLICIT_X_PROMOTEDERSION]]:
+// CHECK-SANITIZE-TRAP-NEXT:          call void @llvm.trap(){{.*}}, !nosanitize
+// CHECK-SANITIZE-ANYRECOVER-NEXT:    [[TMP1:%.*]] = zext i32 [[INC]] to i64, !nosanitize
+// CHECK-SANITIZE-ANYRECOVER-NEXT:    [[TMP2:%.*]] = zext i16 [[X_PROMOTED_DEMOTED]] to i64, !nosanitize
+// CHECK-SANITIZE-NORECOVER-NEXT:     call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ { [97 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }*, { i16, i16, [8 x i8] }*, i8 }* @[[LINE_600]] to i8*), i64 [[TMP1]], i64 [[TMP2]]) #2, !nosanitize
+// CHECK-SANITIZE-RECOVER-NEXT:       call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ { [97 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }*, { i16, i16, [8 x i8] }*, i8 }* @[[LINE_600]] to i8*), i64 [[TMP1]], i64 [[TMP2]]) #2, !nosanitize
+// CHECK-SANITIZE-UNREACHABLE-NEXT:   unreachable, !nosanitize
+// CHECK-SANITIZE-RECOVER-NEXT:       br label %[[CONT]], !nosanitize
+// CHECK-SANITIZE:                  [[CONT]]:
+// CHECK-SANITIZE-NEXT:               store i16 [[X_PROMOTED_DEMOTED]], i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               ret i16 [[X_RELOADED]]
+#line 600
+  return x--;
+}
+
+signed short t6(signed short x) {
+// CHECK-NOSANITIZE-LABEL: @t6(
+// CHECK-NOSANITIZE-NEXT:  entry:
+// CHECK-NOSANITIZE-NEXT:    [[X_ADDR:%.*]] = alloca i16, align 2
+// CHECK-NOSANITIZE-NEXT:    store i16 [[X:%.*]], i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    [[X_RELOADED:%.*]] = load i16, i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    [[INC:%.*]] = add i16 [[X_RELOADED]], 1
+// CHECK-NOSANITIZE-NEXT:    store i16 [[INC]], i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    ret i16 [[INC]]
+//
+// CHECK-SANITIZE-LABEL:            @t6(
+// CHECK-SANITIZE-NEXT:             entry:
+// CHECK-SANITIZE-NEXT:               [[X_ADDR:%.*]] = alloca i16, align 2
+// CHECK-SANITIZE-NEXT:               store i16 [[X:%.*]], i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               [[X_RELOADED:%.*]] = load i16, i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED:%.*]] = sext i16 [[X_RELOADED]] to i32
+// CHECK-SANITIZE-NEXT:               [[INC:%.*]] = add i32 [[X_PROMOTED]], 1
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED_DEMOTED:%.*]] = trunc i32 [[INC]] to i16
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED_DEMOTED_PROMOTED:%.*]] = sext i16 [[X_PROMOTED_DEMOTED]] to i32, !nosanitize
+// CHECK-SANITIZE-NEXT:               [[TRUNCHECK:%.*]] = icmp eq i32 [[X_PROMOTED_DEMOTED_PROMOTED]], [[INC]], !nosanitize
+// CHECK-SANITIZE-NEXT:               br i1 [[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_X_PROMOTEDERSION:[^,]+]],{{.*}} !nosanitize
+// CHECK-SANITIZE:                  [[HANDLER_IMPLICIT_X_PROMOTEDERSION]]:
+// CHECK-SANITIZE-TRAP-NEXT:          call void @llvm.trap(){{.*}}, !nosanitize
+// CHECK-SANITIZE-ANYRECOVER-NEXT:    [[TMP1:%.*]] = zext i32 [[INC]] to i64, !nosanitize
+// CHECK-SANITIZE-ANYRECOVER-NEXT:    [[TMP2:%.*]] = zext i16 [[X_PROMOTED_DEMOTED]] to i64, !nosanitize
+// CHECK-SANITIZE-NORECOVER-NEXT:     call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ { [97 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }*, { i16, i16, [8 x i8] }*, i8 }* @[[LINE_700]] to i8*), i64 [[TMP1]], i64 [[TMP2]]) #2, !nosanitize
+// CHECK-SANITIZE-RECOVER-NEXT:       call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ { [97 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }*, { i16, i16, [8 x i8] }*, i8 }* @[[LINE_700]] to i8*), i64 [[TMP1]], i64 [[TMP2]]) #2, !nosanitize
+// CHECK-SANITIZE-UNREACHABLE-NEXT:   unreachable, !nosanitize
+// CHECK-SANITIZE-RECOVER-NEXT:       br label %[[CONT]], !nosanitize
+// CHECK-SANITIZE:                  [[CONT]]:
+// CHECK-SANITIZE-NEXT:               store i16 [[X_PROMOTED_DEMOTED]], i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               ret i16 [[X_PROMOTED_DEMOTED]]
+#line 700
+  return ++x;
+}
+
+signed short t7(signed short x) {
+// CHECK-NOSANITIZE-LABEL: @t7(
+// CHECK-NOSANITIZE-NEXT:  entry:
+// CHECK-NOSANITIZE-NEXT:    [[X_ADDR:%.*]] = alloca i16, align 2
+// CHECK-NOSANITIZE-NEXT:    store i16 [[X:%.*]], i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    [[X_RELOADED:%.*]] = load i16, i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    [[INC:%.*]] = add i16 [[X_RELOADED]], -1
+// CHECK-NOSANITIZE-NEXT:    store i16 [[INC]], i16* [[X_ADDR]], align 2
+// CHECK-NOSANITIZE-NEXT:    ret i16 [[INC]]
+//
+// CHECK-SANITIZE-LABEL:            @t7(
+// CHECK-SANITIZE-NEXT:             entry:
+// CHECK-SANITIZE-NEXT:               [[X_ADDR:%.*]] = alloca i16, align 2
+// CHECK-SANITIZE-NEXT:               store i16 [[X:%.*]], i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               [[X_RELOADED:%.*]] = load i16, i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED:%.*]] = sext i16 [[X_RELOADED]] to i32
+// CHECK-SANITIZE-NEXT:               [[INC:%.*]] = add i32 [[X_PROMOTED]], -1
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED_DEMOTED:%.*]] = trunc i32 [[INC]] to i16
+// CHECK-SANITIZE-NEXT:               [[X_PROMOTED_DEMOTED_PROMOTED:%.*]] = sext i16 [[X_PROMOTED_DEMOTED]] to i32, !nosanitize
+// CHECK-SANITIZE-NEXT:               [[TRUNCHECK:%.*]] = icmp eq i32 [[X_PROMOTED_DEMOTED_PROMOTED]], [[INC]], !nosanitize
+// CHECK-SANITIZE-NEXT:               br i1 [[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_X_PROMOTEDERSION:[^,]+]],{{.*}} !nosanitize
+// CHECK-SANITIZE:                  [[HANDLER_IMPLICIT_X_PROMOTEDERSION]]:
+// CHECK-SANITIZE-TRAP-NEXT:          call void @llvm.trap(){{.*}}, !nosanitize
+// CHECK-SANITIZE-ANYRECOVER-NEXT:    [[TMP1:%.*]] = zext i32 [[INC]] to i64, !nosanitize
+// CHECK-SANITIZE-ANYRECOVER-NEXT:    [[TMP2:%.*]] = zext i16 [[X_PROMOTED_DEMOTED]] to i64, !nosanitize
+// CHECK-SANITIZE-NORECOVER-NEXT:     call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ { [97 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }*, { i16, i16, [8 x i8] }*, i8 }* @[[LINE_800]] to i8*), i64 [[TMP1]], i64 [[TMP2]]) #2, !nosanitize
+// CHECK-SANITIZE-RECOVER-NEXT:       call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ { [97 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }*, { i16, i16, [8 x i8] }*, i8 }* @[[LINE_800]] to i8*), i64 [[TMP1]], i64 [[TMP2]]) #2, !nosanitize
+// CHECK-SANITIZE-UNREACHABLE-NEXT:   unreachable, !nosanitize
+// CHECK-SANITIZE-RECOVER-NEXT:       br label %[[CONT]], !nosanitize
+// CHECK-SANITIZE:                  [[CONT]]:
+// CHECK-SANITIZE-NEXT:               store i16 [[X_PROMOTED_DEMOTED]], i16* [[X_ADDR]], align 2
+// CHECK-SANITIZE-NEXT:               ret i16 [[X_PROMOTED_DEMOTED]]
+#line 800
+  return --x;
+}
Index: clang/test/CodeGen/catch-implicit-signed-integer-truncations-incdec-basics.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/catch-implicit-signed-integer-truncations-incdec-basics.c
@@ -0,0 +1,139 @@
+// RUN: %clang_cc1 -fsanitize=implicit-signed-integer-truncation -fsanitize-recover=implicit-signed-integer-truncation -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_implicit_conversion" --check-prefixes=CHECK
+
+// CHECK-DAG: @[[INT:.*]] = {{.*}} c"'int'\00" }
+// CHECK-DAG: @[[UNSIGNED_SHORT:.*]] = {{.*}} c"'unsigned short'\00" }
+// CHECK-DAG: @[[LINE_100:.*]] = {{.*}}, i32 100, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_200:.*]] = {{.*}}, i32 200, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_300:.*]] = {{.*}}, i32 300, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_400:.*]] = {{.*}}, i32 400, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[SHORT:.*]] = {{.*}} c"'short'\00" }
+// CHECK-DAG: @[[LINE_500:.*]] = {{.*}}, i32 500, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_600:.*]] = {{.*}}, i32 600, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_700:.*]] = {{.*}}, i32 700, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_800:.*]] = {{.*}}, i32 800, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[UNSIGNED_CHAR:.*]] = {{.*}} c"'unsigned char'\00" }
+// CHECK-DAG: @[[LINE_900:.*]] = {{.*}}, i32 900, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1000:.*]] = {{.*}}, i32 1000, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1100:.*]] = {{.*}}, i32 1100, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1200:.*]] = {{.*}}, i32 1200, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[SIGNED_CHAR:.*]] = {{.*}} c"'signed char'\00" }
+// CHECK-DAG: @[[LINE_1300:.*]] = {{.*}}, i32 1300, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1400:.*]] = {{.*}}, i32 1400, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1500:.*]] = {{.*}}, i32 1500, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1600:.*]] = {{.*}}, i32 1600, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+
+// CHECK-LABEL: @t0(
+unsigned short t0(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100]] to i8*)
+#line 100
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t1(
+unsigned short t1(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200]] to i8*)
+#line 200
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t2(
+unsigned short t2(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300]] to i8*)
+#line 300
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t3(
+unsigned short t3(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400]] to i8*)
+#line 400
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t4(
+signed short t4(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500]] to i8*)
+#line 500
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t5(
+signed short t5(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_600]] to i8*)
+#line 600
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t6(
+signed short t6(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_700]] to i8*)
+#line 700
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t7(
+signed short t7(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_800]] to i8*)
+#line 800
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t8(
+unsigned char t8(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_900]] to i8*)
+#line 900
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t9(
+unsigned char t9(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1000]] to i8*)
+#line 1000
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t10(
+unsigned char t10(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1100]] to i8*)
+#line 1100
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t11(
+unsigned char t11(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1200]] to i8*)
+#line 1200
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t12(
+signed char t12(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1300]] to i8*)
+#line 1300
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t13(
+signed char t13(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1400]] to i8*)
+#line 1400
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t14(
+signed char t14(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1500]] to i8*)
+#line 1500
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t15(
+signed char t15(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1600]] to i8*)
+#line 1600
+  --x;
+  return x;
+}
Index: clang/test/CodeGen/catch-implicit-integer-truncations-incdec-basics.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/catch-implicit-integer-truncations-incdec-basics.c
@@ -0,0 +1,139 @@
+// RUN: %clang_cc1 -fsanitize=implicit-unsigned-integer-truncation,implicit-signed-integer-truncation -fsanitize-recover=implicit-unsigned-integer-truncation,implicit-signed-integer-truncation -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_implicit_conversion" --check-prefixes=CHECK
+
+// CHECK-DAG: @[[INT:.*]] = {{.*}} c"'int'\00" }
+// CHECK-DAG: @[[UNSIGNED_SHORT:.*]] = {{.*}} c"'unsigned short'\00" }
+// CHECK-DAG: @[[LINE_100:.*]] = {{.*}}, i32 100, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_200:.*]] = {{.*}}, i32 200, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_300:.*]] = {{.*}}, i32 300, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_400:.*]] = {{.*}}, i32 400, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[SHORT:.*]] = {{.*}} c"'short'\00" }
+// CHECK-DAG: @[[LINE_500:.*]] = {{.*}}, i32 500, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_600:.*]] = {{.*}}, i32 600, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_700:.*]] = {{.*}}, i32 700, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_800:.*]] = {{.*}}, i32 800, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[UNSIGNED_CHAR:.*]] = {{.*}} c"'unsigned char'\00" }
+// CHECK-DAG: @[[LINE_900:.*]] = {{.*}}, i32 900, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1000:.*]] = {{.*}}, i32 1000, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1100:.*]] = {{.*}}, i32 1100, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1200:.*]] = {{.*}}, i32 1200, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[SIGNED_CHAR:.*]] = {{.*}} c"'signed char'\00" }
+// CHECK-DAG: @[[LINE_1300:.*]] = {{.*}}, i32 1300, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1400:.*]] = {{.*}}, i32 1400, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1500:.*]] = {{.*}}, i32 1500, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1600:.*]] = {{.*}}, i32 1600, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+
+// CHECK-LABEL: @t0(
+unsigned short t0(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100]] to i8*)
+#line 100
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t1(
+unsigned short t1(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200]] to i8*)
+#line 200
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t2(
+unsigned short t2(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300]] to i8*)
+#line 300
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t3(
+unsigned short t3(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400]] to i8*)
+#line 400
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t4(
+signed short t4(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500]] to i8*)
+#line 500
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t5(
+signed short t5(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_600]] to i8*)
+#line 600
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t6(
+signed short t6(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_700]] to i8*)
+#line 700
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t7(
+signed short t7(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_800]] to i8*)
+#line 800
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t8(
+unsigned char t8(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_900]] to i8*)
+#line 900
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t9(
+unsigned char t9(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1000]] to i8*)
+#line 1000
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t10(
+unsigned char t10(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1100]] to i8*)
+#line 1100
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t11(
+unsigned char t11(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1200]] to i8*)
+#line 1200
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t12(
+signed char t12(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1300]] to i8*)
+#line 1300
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t13(
+signed char t13(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1400]] to i8*)
+#line 1400
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t14(
+signed char t14(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1500]] to i8*)
+#line 1500
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t15(
+signed char t15(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1600]] to i8*)
+#line 1600
+  --x;
+  return x;
+}
Index: clang/test/CodeGen/catch-implicit-integer-sign-changes-incdec-basics.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/catch-implicit-integer-sign-changes-incdec-basics.c
@@ -0,0 +1,101 @@
+// RUN: %clang_cc1 -fsanitize=implicit-integer-sign-change -fsanitize-recover=implicit-integer-sign-change -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_implicit_conversion" --check-prefixes=CHECK
+
+// CHECK-LABEL: @t0(
+unsigned short t0(unsigned short x) {
+#line 100
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t1(
+unsigned short t1(unsigned short x) {
+#line 200
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t2(
+unsigned short t2(unsigned short x) {
+#line 300
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t3(
+unsigned short t3(unsigned short x) {
+#line 400
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t4(
+signed short t4(signed short x) {
+#line 500
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t5(
+signed short t5(signed short x) {
+#line 600
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t6(
+signed short t6(signed short x) {
+#line 700
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t7(
+signed short t7(signed short x) {
+#line 800
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t8(
+unsigned char t8(unsigned char x) {
+#line 900
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t9(
+unsigned char t9(unsigned char x) {
+#line 1000
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t10(
+unsigned char t10(unsigned char x) {
+#line 1100
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t11(
+unsigned char t11(unsigned char x) {
+#line 1200
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t12(
+signed char t12(signed char x) {
+#line 1300
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t13(
+signed char t13(signed char x) {
+#line 1400
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t14(
+signed char t14(signed char x) {
+#line 1500
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t15(
+signed char t15(signed char x) {
+#line 1600
+  --x;
+  return x;
+}
Index: clang/test/CodeGen/catch-implicit-integer-conversions-incdec-basics.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/catch-implicit-integer-conversions-incdec-basics.c
@@ -0,0 +1,139 @@
+// RUN: %clang_cc1 -fsanitize=implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change -fsanitize-recover=implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_implicit_conversion" --check-prefixes=CHECK
+
+// CHECK-DAG: @[[INT:.*]] = {{.*}} c"'int'\00" }
+// CHECK-DAG: @[[UNSIGNED_SHORT:.*]] = {{.*}} c"'unsigned short'\00" }
+// CHECK-DAG: @[[LINE_100:.*]] = {{.*}}, i32 100, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_200:.*]] = {{.*}}, i32 200, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_300:.*]] = {{.*}}, i32 300, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_400:.*]] = {{.*}}, i32 400, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[SHORT:.*]] = {{.*}} c"'short'\00" }
+// CHECK-DAG: @[[LINE_500:.*]] = {{.*}}, i32 500, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_600:.*]] = {{.*}}, i32 600, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_700:.*]] = {{.*}}, i32 700, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_800:.*]] = {{.*}}, i32 800, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[UNSIGNED_CHAR:.*]] = {{.*}} c"'unsigned char'\00" }
+// CHECK-DAG: @[[LINE_900:.*]] = {{.*}}, i32 900, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1000:.*]] = {{.*}}, i32 1000, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1100:.*]] = {{.*}}, i32 1100, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1200:.*]] = {{.*}}, i32 1200, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[SIGNED_CHAR:.*]] = {{.*}} c"'signed char'\00" }
+// CHECK-DAG: @[[LINE_1300:.*]] = {{.*}}, i32 1300, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1400:.*]] = {{.*}}, i32 1400, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1500:.*]] = {{.*}}, i32 1500, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1600:.*]] = {{.*}}, i32 1600, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+
+// CHECK-LABEL: @t0(
+unsigned short t0(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100]] to i8*)
+#line 100
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t1(
+unsigned short t1(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200]] to i8*)
+#line 200
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t2(
+unsigned short t2(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300]] to i8*)
+#line 300
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t3(
+unsigned short t3(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400]] to i8*)
+#line 400
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t4(
+signed short t4(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500]] to i8*)
+#line 500
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t5(
+signed short t5(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_600]] to i8*)
+#line 600
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t6(
+signed short t6(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_700]] to i8*)
+#line 700
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t7(
+signed short t7(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_800]] to i8*)
+#line 800
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t8(
+unsigned char t8(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_900]] to i8*)
+#line 900
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t9(
+unsigned char t9(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1000]] to i8*)
+#line 1000
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t10(
+unsigned char t10(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1100]] to i8*)
+#line 1100
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t11(
+unsigned char t11(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1200]] to i8*)
+#line 1200
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t12(
+signed char t12(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1300]] to i8*)
+#line 1300
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t13(
+signed char t13(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1400]] to i8*)
+#line 1400
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t14(
+signed char t14(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1500]] to i8*)
+#line 1500
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t15(
+signed char t15(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1600]] to i8*)
+#line 1600
+  --x;
+  return x;
+}
Index: clang/test/CodeGen/catch-implicit-integer-arithmetic-value-change-incdec-basics.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/catch-implicit-integer-arithmetic-value-change-incdec-basics.c
@@ -0,0 +1,139 @@
+// RUN: %clang_cc1 -fsanitize=implicit-signed-integer-truncation,implicit-integer-sign-change -fsanitize-recover=implicit-signed-integer-truncation,implicit-integer-sign-change -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_implicit_conversion" --check-prefixes=CHECK
+
+// CHECK-DAG: @[[INT:.*]] = {{.*}} c"'int'\00" }
+// CHECK-DAG: @[[UNSIGNED_SHORT:.*]] = {{.*}} c"'unsigned short'\00" }
+// CHECK-DAG: @[[LINE_100:.*]] = {{.*}}, i32 100, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_200:.*]] = {{.*}}, i32 200, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_300:.*]] = {{.*}}, i32 300, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_400:.*]] = {{.*}}, i32 400, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[SHORT:.*]] = {{.*}} c"'short'\00" }
+// CHECK-DAG: @[[LINE_500:.*]] = {{.*}}, i32 500, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_600:.*]] = {{.*}}, i32 600, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_700:.*]] = {{.*}}, i32 700, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_800:.*]] = {{.*}}, i32 800, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[UNSIGNED_CHAR:.*]] = {{.*}} c"'unsigned char'\00" }
+// CHECK-DAG: @[[LINE_900:.*]] = {{.*}}, i32 900, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1000:.*]] = {{.*}}, i32 1000, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1100:.*]] = {{.*}}, i32 1100, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1200:.*]] = {{.*}}, i32 1200, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[SIGNED_CHAR:.*]] = {{.*}} c"'signed char'\00" }
+// CHECK-DAG: @[[LINE_1300:.*]] = {{.*}}, i32 1300, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1400:.*]] = {{.*}}, i32 1400, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1500:.*]] = {{.*}}, i32 1500, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1600:.*]] = {{.*}}, i32 1600, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+
+// CHECK-LABEL: @t0(
+unsigned short t0(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100]] to i8*)
+#line 100
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t1(
+unsigned short t1(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200]] to i8*)
+#line 200
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t2(
+unsigned short t2(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300]] to i8*)
+#line 300
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t3(
+unsigned short t3(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400]] to i8*)
+#line 400
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t4(
+signed short t4(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500]] to i8*)
+#line 500
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t5(
+signed short t5(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_600]] to i8*)
+#line 600
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t6(
+signed short t6(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_700]] to i8*)
+#line 700
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t7(
+signed short t7(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_800]] to i8*)
+#line 800
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t8(
+unsigned char t8(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_900]] to i8*)
+#line 900
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t9(
+unsigned char t9(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1000]] to i8*)
+#line 1000
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t10(
+unsigned char t10(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1100]] to i8*)
+#line 1100
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t11(
+unsigned char t11(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1200]] to i8*)
+#line 1200
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t12(
+signed char t12(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1300]] to i8*)
+#line 1300
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t13(
+signed char t13(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1400]] to i8*)
+#line 1400
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t14(
+signed char t14(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1500]] to i8*)
+#line 1500
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t15(
+signed char t15(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1600]] to i8*)
+#line 1600
+  --x;
+  return x;
+}
Index: clang/test/CodeGen/catch-implicit-conversions-incdec-basics.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/catch-implicit-conversions-incdec-basics.c
@@ -0,0 +1,139 @@
+// RUN: %clang_cc1 -fsanitize=implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change -fsanitize-recover=implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_implicit_conversion" --check-prefixes=CHECK
+
+// CHECK-DAG: @[[INT:.*]] = {{.*}} c"'int'\00" }
+// CHECK-DAG: @[[UNSIGNED_SHORT:.*]] = {{.*}} c"'unsigned short'\00" }
+// CHECK-DAG: @[[LINE_100:.*]] = {{.*}}, i32 100, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_200:.*]] = {{.*}}, i32 200, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_300:.*]] = {{.*}}, i32 300, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_400:.*]] = {{.*}}, i32 400, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_SHORT]], i8 2 }
+// CHECK-DAG: @[[SHORT:.*]] = {{.*}} c"'short'\00" }
+// CHECK-DAG: @[[LINE_500:.*]] = {{.*}}, i32 500, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_600:.*]] = {{.*}}, i32 600, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_700:.*]] = {{.*}}, i32 700, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[LINE_800:.*]] = {{.*}}, i32 800, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SHORT]], i8 2 }
+// CHECK-DAG: @[[UNSIGNED_CHAR:.*]] = {{.*}} c"'unsigned char'\00" }
+// CHECK-DAG: @[[LINE_900:.*]] = {{.*}}, i32 900, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1000:.*]] = {{.*}}, i32 1000, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1100:.*]] = {{.*}}, i32 1100, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1200:.*]] = {{.*}}, i32 1200, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[SIGNED_CHAR:.*]] = {{.*}} c"'signed char'\00" }
+// CHECK-DAG: @[[LINE_1300:.*]] = {{.*}}, i32 1300, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1400:.*]] = {{.*}}, i32 1400, i32 4 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1500:.*]] = {{.*}}, i32 1500, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-DAG: @[[LINE_1600:.*]] = {{.*}}, i32 1600, i32 3 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+
+// CHECK-LABEL: @t0(
+unsigned short t0(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100]] to i8*)
+#line 100
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t1(
+unsigned short t1(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200]] to i8*)
+#line 200
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t2(
+unsigned short t2(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300]] to i8*)
+#line 300
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t3(
+unsigned short t3(unsigned short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400]] to i8*)
+#line 400
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t4(
+signed short t4(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500]] to i8*)
+#line 500
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t5(
+signed short t5(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_600]] to i8*)
+#line 600
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t6(
+signed short t6(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_700]] to i8*)
+#line 700
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t7(
+signed short t7(signed short x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_800]] to i8*)
+#line 800
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t8(
+unsigned char t8(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_900]] to i8*)
+#line 900
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t9(
+unsigned char t9(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1000]] to i8*)
+#line 1000
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t10(
+unsigned char t10(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1100]] to i8*)
+#line 1100
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t11(
+unsigned char t11(unsigned char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1200]] to i8*)
+#line 1200
+  --x;
+  return x;
+}
+
+// CHECK-LABEL: @t12(
+signed char t12(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1300]] to i8*)
+#line 1300
+  x++;
+  return x;
+}
+// CHECK-LABEL: @t13(
+signed char t13(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1400]] to i8*)
+#line 1400
+  x--;
+  return x;
+}
+// CHECK-LABEL: @t14(
+signed char t14(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1500]] to i8*)
+#line 1500
+  ++x;
+  return x;
+}
+// CHECK-LABEL: @t15(
+signed char t15(signed char x) {
+  // CHECK: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1600]] to i8*)
+#line 1600
+  --x;
+  return x;
+}
Index: clang/lib/CodeGen/CGExprScalar.cpp
===================================================================
--- clang/lib/CodeGen/CGExprScalar.cpp
+++ clang/lib/CodeGen/CGExprScalar.cpp
@@ -2419,9 +2419,30 @@
 
   // Most common case by far: integer increment.
   } else if (type->isIntegerType()) {
-    // Note that signed integer inc/dec with width less than int can't
-    // overflow because of promotion rules; we're just eliding a few steps here.
-    if (E->canOverflow() && type->isSignedIntegerOrEnumerationType()) {
+    if (CGF.SanOpts.hasOneOf(SanitizerKind::ImplicitIntegerTruncation) &&
+        type->isPromotableIntegerType()) {
+      // While `x += 1` (for `x` with width less than int) is modelled as
+      // promotion+arithmetics+demotion, and we can catch lossy demotion with
+      // ease; inc/dec with width less than int can't overflow because of
+      // promotion rules, so we omit promotion+demotion, which means that we can
+      // not catch lossy "demotion". Since we still want to catch those cases,
+      // if the sanitizer is enabled, let's perform the promotion, perform
+      // increment/decrement in wider type, and perform demotion which *will*
+      // catch lossy demotions.
+      QualType promotedType = CGF.getContext().getPromotedIntegerType(type);
+      assert(promotedType != type && "Shouldn't promote to the same type.");
+      value = EmitScalarConversion(value, type, promotedType, E->getExprLoc());
+      Value *amt = llvm::ConstantInt::get(value->getType(), amount, true);
+      value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
+      // Do pass non-default ScalarConversionOpts so that sanitizer check is
+      // emitted.
+      value = EmitScalarConversion(value, promotedType, type, E->getExprLoc(),
+                                   ScalarConversionOpts(CGF.SanOpts));
+
+      // Note that signed integer inc/dec with width less than int can't
+      // overflow because of promotion rules; we're just eliding a few steps
+      // here.
+    } else if (E->canOverflow() && type->isSignedIntegerOrEnumerationType()) {
       value = EmitIncDecConsiderOverflowBehavior(E, value, isInc);
     } else if (E->canOverflow() && type->isUnsignedIntegerType() &&
                CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) {
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -78,6 +78,10 @@
   been extended to detect these cases, so that code relying on them can be
   detected and fixed.
 
+* The Implicit Conversion Sanitizer (``-fsanitize=implicit-conversion``) has
+  learned to sanitize pre/post increment/decrement of types with bit width
+  smaller than ``int``.
+
 - For X86 target, -march=skylake-avx512, -march=icelake-client,
   -march=icelake-server, -march=cascadelake, -march=cooperlake will default to
   not using 512-bit zmm registers in vectorized code unless 512-bit intrinsics
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to