lebedev.ri updated this revision to Diff 172115.
lebedev.ri edited the summary of this revision.
lebedev.ri added a subscriber: mclow.lists.
lebedev.ri added a comment.

Added test coverage.
Please review :)


Repository:
  rC Clang

https://reviews.llvm.org/D53949

Files:
  lib/CodeGen/CGExprScalar.cpp
  test/CodeGen/catch-implicit-integer-sign-changes-CompoundAssignOperator.c
  test/CodeGen/catch-implicit-integer-truncations-CompoundAssignOperator.c

Index: test/CodeGen/catch-implicit-integer-truncations-CompoundAssignOperator.c
===================================================================
--- /dev/null
+++ test/CodeGen/catch-implicit-integer-truncations-CompoundAssignOperator.c
@@ -0,0 +1,737 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK
+
+// RUN: %clang_cc1 -fsanitize=implicit-unsigned-integer-truncation,implicit-signed-integer-truncation -fno-sanitize-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-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER,CHECK-SANITIZE-UNREACHABLE
+// 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-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER
+// RUN: %clang_cc1 -fsanitize=implicit-unsigned-integer-truncation,implicit-signed-integer-truncation -fsanitize-trap=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-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE
+
+// 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
+
+// RUN: %clang_cc1 -fsanitize=implicit-signed-integer-truncation,implicit-integer-sign-change -fno-sanitize-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-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER,CHECK-SANITIZE-UNREACHABLE
+// 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-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER
+// RUN: %clang_cc1 -fsanitize=implicit-signed-integer-truncation,implicit-integer-sign-change -fsanitize-trap=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-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE
+
+// CHECK-SANITIZE-ANYRECOVER: @[[INT:.*]] = {{.*}} c"'int'\00" }
+// CHECK-SANITIZE-ANYRECOVER: @[[UNSIGNED_CHAR:.*]] = {{.*}} c"'unsigned char'\00" }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[SIGNED_CHAR:.*]] = {{.*}} c"'signed char'\00" }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_200_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 200, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_300_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 300, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_400_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 400, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_500_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 500, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_600_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 600, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_700_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 700, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_800_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 800, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_900_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 900, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1000_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1000, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1100_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1100, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1200_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1200, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1300_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1300, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1400_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1400, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1500_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1500, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1600_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1600, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1700_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1700, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1800_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1800, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1900_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 1900, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 2 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_2000_SIGNED_TRUNCATION:.*]] = {{.*}}, i32 2000, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 2 }
+
+//----------------------------------------------------------------------------//
+// Compound add operator.                                                     //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_add
+void unsigned_char_add(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = add nsw i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = zext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 100
+  (*LHS) += RHS;
+}
+
+// CHECK-LABEL: @signed_char_add
+void signed_char_add(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = add nsw i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = sext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 200
+  (*LHS) += RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound subtract operator.                                                //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_sub
+void unsigned_char_sub(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = sub nsw i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = zext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 300
+  (*LHS) -= RHS;
+}
+
+// CHECK-LABEL: @signed_char_sub
+void signed_char_sub(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = sub nsw i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = sext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 400
+  (*LHS) -= RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound multiply operator.                                                //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_mul
+void unsigned_char_mul(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = mul nsw i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = zext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 500
+  (*LHS) *= RHS;
+}
+
+// CHECK-LABEL: @signed_char_mul
+void signed_char_mul(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = mul nsw i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = sext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_600_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_600_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 600
+  (*LHS) *= RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound divide operator.                                                  //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_div
+void unsigned_char_div(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = sdiv i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = zext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_700_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_700_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 700
+  (*LHS) /= RHS;
+}
+
+// CHECK-LABEL: @signed_char_div
+void signed_char_div(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = sdiv i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = sext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_800_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_800_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 800
+  (*LHS) /= RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound remainder operator.                                                //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_rem
+void unsigned_char_rem(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = srem i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = zext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_900_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_900_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 900
+  (*LHS) %= RHS;
+}
+
+// CHECK-LABEL: @signed_char_rem
+void signed_char_rem(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = srem i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = sext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1000_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1000_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1000
+  (*LHS) %= RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound left-shift operator.                                              //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_shl
+void unsigned_char_shl(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = shl i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = zext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1100_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1100_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1100
+  (*LHS) <<= RHS;
+}
+
+// CHECK-LABEL: @signed_char_shl
+void signed_char_shl(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = shl i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = sext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1200_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1200_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1200
+  (*LHS) <<= RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound right-shift operator.                                              //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_ashr
+void unsigned_char_ashr(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = ashr i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = zext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1300_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1300_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1300
+  (*LHS) >>= RHS;
+}
+
+// CHECK-LABEL: @signed_char_ashr
+void signed_char_ashr(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = ashr i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = sext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1400_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1400_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1400
+  (*LHS) >>= RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound and operator .                                              //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_and
+void unsigned_char_and(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = and i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = zext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1500_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1500_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1500
+  (*LHS) &= RHS;
+}
+
+// CHECK-LABEL: @signed_char_and
+void signed_char_and(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = and i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = sext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1600_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1600_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1600
+  (*LHS) &= RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound xor operator.                                                     //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_xor
+void unsigned_char_xor(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = xor i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = zext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1700_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1700_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1700
+  (*LHS) ^= RHS;
+}
+
+// CHECK-LABEL: @signed_char_xor
+void signed_char_xor(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = xor i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = sext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1800_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1800_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1800
+  (*LHS) ^= RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound or operator.                                                     //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_or
+void unsigned_char_or(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = or i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = zext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1900_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1900_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1900
+  (*LHS) |= RHS;
+}
+
+// CHECK-LABEL: @signed_char_or
+void signed_char_or(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = or i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[ANYEXT:.*]] = sext i8 %[[DST]] to i32, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[TRUNCHECK:.*]] = icmp eq i32 %[[ANYEXT]], %[[SRC]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[TRUNCHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_2000_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_2000_SIGNED_TRUNCATION]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 2000
+  (*LHS) |= RHS;
+}
Index: test/CodeGen/catch-implicit-integer-sign-changes-CompoundAssignOperator.c
===================================================================
--- /dev/null
+++ test/CodeGen/catch-implicit-integer-sign-changes-CompoundAssignOperator.c
@@ -0,0 +1,739 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK
+
+// RUN: %clang_cc1 -fsanitize=implicit-integer-sign-change -fno-sanitize-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-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER,CHECK-SANITIZE-UNREACHABLE
+// 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-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER
+// RUN: %clang_cc1 -fsanitize=implicit-integer-sign-change -fsanitize-trap=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-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE
+
+// CHECK-SANITIZE-ANYRECOVER: @[[INT:.*]] = {{.*}} c"'int'\00" }
+// CHECK-SANITIZE-ANYRECOVER: @[[UNSIGNED_CHAR:.*]] = {{.*}} c"'unsigned char'\00" }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_SIGN_CHANGE:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[SIGNED_CHAR:.*]] = {{.*}} c"'signed char'\00" }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_200_SIGN_CHANGE:.*]] = {{.*}}, i32 200, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_300_SIGN_CHANGE:.*]] = {{.*}}, i32 300, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_400_SIGN_CHANGE:.*]] = {{.*}}, i32 400, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_500_SIGN_CHANGE:.*]] = {{.*}}, i32 500, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_600_SIGN_CHANGE:.*]] = {{.*}}, i32 600, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_700_SIGN_CHANGE:.*]] = {{.*}}, i32 700, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_800_SIGN_CHANGE:.*]] = {{.*}}, i32 800, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_900_SIGN_CHANGE:.*]] = {{.*}}, i32 900, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1000_SIGN_CHANGE:.*]] = {{.*}}, i32 1000, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1100_SIGN_CHANGE:.*]] = {{.*}}, i32 1100, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1200_SIGN_CHANGE:.*]] = {{.*}}, i32 1200, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1300_SIGN_CHANGE:.*]] = {{.*}}, i32 1300, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1400_SIGN_CHANGE:.*]] = {{.*}}, i32 1400, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1500_SIGN_CHANGE:.*]] = {{.*}}, i32 1500, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1600_SIGN_CHANGE:.*]] = {{.*}}, i32 1600, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1700_SIGN_CHANGE:.*]] = {{.*}}, i32 1700, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1800_SIGN_CHANGE:.*]] = {{.*}}, i32 1800, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_1900_SIGN_CHANGE:.*]] = {{.*}}, i32 1900, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[UNSIGNED_CHAR]], i8 3 }
+// CHECK-SANITIZE-ANYRECOVER: @[[LINE_2000_SIGN_CHANGE:.*]] = {{.*}}, i32 2000, i32 10 }, {{.*}}* @[[INT]], {{.*}}* @[[SIGNED_CHAR]], i8 3 }
+
+//----------------------------------------------------------------------------//
+// Compound add operator.                                                     //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_add
+void unsigned_char_add(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = add nsw i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], false, !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_100_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 100
+  (*LHS) += RHS;
+}
+
+// CHECK-LABEL: @signed_char_add
+void signed_char_add(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = add nsw i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[DST]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], %[[DST_NEGATIVITYCHECK]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_200_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 200
+  (*LHS) += RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound subtract operator.                                                //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_sub
+void unsigned_char_sub(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = sub nsw i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], false, !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_300_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 300
+  (*LHS) -= RHS;
+}
+
+// CHECK-LABEL: @signed_char_sub
+void signed_char_sub(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = sub nsw i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[DST]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], %[[DST_NEGATIVITYCHECK]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_400_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 400
+  (*LHS) -= RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound multiply operator.                                                //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_mul
+void unsigned_char_mul(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = mul nsw i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], false, !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_500_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 500
+  (*LHS) *= RHS;
+}
+
+// CHECK-LABEL: @signed_char_mul
+void signed_char_mul(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = mul nsw i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[DST]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], %[[DST_NEGATIVITYCHECK]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_600_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_600_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 600
+  (*LHS) *= RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound divide operator.                                                  //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_div
+void unsigned_char_div(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = sdiv i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], false, !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_700_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_700_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 700
+  (*LHS) /= RHS;
+}
+
+// CHECK-LABEL: @signed_char_div
+void signed_char_div(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = sdiv i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[DST]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], %[[DST_NEGATIVITYCHECK]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_800_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_800_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 800
+  (*LHS) /= RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound remainder operator.                                                //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_rem
+void unsigned_char_rem(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = srem i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], false, !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_900_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_900_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 900
+  (*LHS) %= RHS;
+}
+
+// CHECK-LABEL: @signed_char_rem
+void signed_char_rem(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = srem i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[DST]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], %[[DST_NEGATIVITYCHECK]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1000_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1000_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1000
+  (*LHS) %= RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound left-shift operator.                                              //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_shl
+void unsigned_char_shl(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = shl i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], false, !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1100_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1100_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1100
+  (*LHS) <<= RHS;
+}
+
+// CHECK-LABEL: @signed_char_shl
+void signed_char_shl(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = shl i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[DST]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], %[[DST_NEGATIVITYCHECK]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1200_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1200_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1200
+  (*LHS) <<= RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound right-shift operator.                                              //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_ashr
+void unsigned_char_ashr(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = ashr i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], false, !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1300_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1300_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1300
+  (*LHS) >>= RHS;
+}
+
+// CHECK-LABEL: @signed_char_ashr
+void signed_char_ashr(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = ashr i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[DST]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], %[[DST_NEGATIVITYCHECK]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1400_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1400_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1400
+  (*LHS) >>= RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound and operator .                                              //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_and
+void unsigned_char_and(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = and i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], false, !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1500_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1500_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1500
+  (*LHS) &= RHS;
+}
+
+// CHECK-LABEL: @signed_char_and
+void signed_char_and(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = and i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[DST]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], %[[DST_NEGATIVITYCHECK]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1600_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1600_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1600
+  (*LHS) &= RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound xor operator.                                                     //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_xor
+void unsigned_char_xor(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = xor i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], false, !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1700_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1700_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1700
+  (*LHS) ^= RHS;
+}
+
+// CHECK-LABEL: @signed_char_xor
+void signed_char_xor(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = xor i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[DST]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], %[[DST_NEGATIVITYCHECK]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1800_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1800_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1800
+  (*LHS) ^= RHS;
+}
+
+//----------------------------------------------------------------------------//
+// Compound or operator.                                                     //
+//----------------------------------------------------------------------------//
+
+// CHECK-LABEL: @unsigned_char_or
+void unsigned_char_or(unsigned char *LHS, unsigned char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = zext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = zext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = or i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], false, !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1900_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_1900_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 1900
+  (*LHS) |= RHS;
+}
+
+// CHECK-LABEL: @signed_char_or
+void signed_char_or(signed char *LHS, signed char RHS) {
+  // CHECK: {
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: %[[ADDRESS:.*]] = alloca i8*, align 8
+  // CHECK-NEXT: %[[RHSADDR:.*]] = alloca i8, align 1
+  // CHECK-NEXT: store i8* %[[ARG0:.*]], i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: store i8 %[[ARG1:.*]], i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHS:.*]] = load i8, i8* %[[RHSADDR]], align 1
+  // CHECK-NEXT: %[[RHSEXT:.*]] = sext i8 %[[RHS]] to i32
+  // CHECK-NEXT: %[[LHSADDR:.*]] = load i8*, i8** %[[ADDRESS]], align 8
+  // CHECK-NEXT: %[[LHS:.*]] = load i8, i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: %[[LHSEXT:.*]] = sext i8 %[[LHS]] to i32
+  // CHECK-NEXT: %[[SRC:.*]] = or i32 %[[LHSEXT]], %[[RHSEXT]]
+  // CHECK-NEXT: %[[DST:.*]] = trunc i32 %[[SRC]] to i8
+  // CHECK-SANITIZE-NEXT: %[[SRC_NEGATIVITYCHECK:.*]] = icmp slt i32 %[[SRC]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[DST_NEGATIVITYCHECK:.*]] = icmp slt i8 %[[DST]], 0, !nosanitize
+  // CHECK-SANITIZE-NEXT: %[[SIGNCHANGECHECK:.*]] = icmp eq i1 %[[SRC_NEGATIVITYCHECK]], %[[DST_NEGATIVITYCHECK]], !nosanitize
+  // CHECK-SANITIZE-NEXT: br i1 %[[SIGNCHANGECHECK]], label %[[CONT:.*]], label %[[HANDLER_IMPLICIT_CONVERSION:[^,]+]],{{.*}} !nosanitize
+  // CHECK-SANITIZE: [[HANDLER_IMPLICIT_CONVERSION]]:
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTSRC:.*]] = zext i32 %[[SRC]] to i64, !nosanitize
+  // CHECK-SANITIZE-ANYRECOVER-NEXT: %[[EXTDST:.*]] = zext i8 %[[DST]] to i64, !nosanitize
+  // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_implicit_conversion_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_2000_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_implicit_conversion(i8* bitcast ({ {{{.*}}}, {{{.*}}}*, {{{.*}}}*, i8 }* @[[LINE_2000_SIGN_CHANGE]] to i8*), i64 %[[EXTSRC]], i64 %[[EXTDST]]){{.*}}, !nosanitize
+  // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
+  // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
+  // CHECK-SANITIZE: [[CONT]]:
+  // CHECK-NEXT: store i8 %[[DST]], i8* %[[LHSADDR]], align 1
+  // CHECK-NEXT: ret void
+  // CHECK-NEXT: }
+#line 2000
+  (*LHS) |= RHS;
+}
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp
+++ lib/CodeGen/CGExprScalar.cpp
@@ -332,6 +332,13 @@
         : TreatBooleanAsSigned(false),
           EmitImplicitIntegerTruncationChecks(false),
           EmitImplicitIntegerSignChangeChecks(false) {}
+
+    ScalarConversionOpts(clang::SanitizerSet SanOpts)
+        : TreatBooleanAsSigned(false),
+          EmitImplicitIntegerTruncationChecks(
+              SanOpts.hasOneOf(SanitizerKind::ImplicitIntegerTruncation)),
+          EmitImplicitIntegerSignChangeChecks(
+              SanOpts.has(SanitizerKind::ImplicitIntegerSignChange)) {}
   };
   Value *
   EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy,
@@ -2197,13 +2204,8 @@
   case CK_IntegralCast: {
     ScalarConversionOpts Opts;
     if (auto *ICE = dyn_cast<ImplicitCastExpr>(CE)) {
-      if (CGF.SanOpts.hasOneOf(SanitizerKind::ImplicitConversion) &&
-          !ICE->isPartOfExplicitCast()) {
-        Opts.EmitImplicitIntegerTruncationChecks =
-            CGF.SanOpts.hasOneOf(SanitizerKind::ImplicitIntegerTruncation);
-        Opts.EmitImplicitIntegerSignChangeChecks =
-            CGF.SanOpts.has(SanitizerKind::ImplicitIntegerSignChange);
-      }
+      if (!ICE->isPartOfExplicitCast())
+        Opts = ScalarConversionOpts(CGF.SanOpts);
     }
     return EmitScalarConversion(Visit(E), E->getType(), DestTy,
                                 CE->getExprLoc(), Opts);
@@ -2871,9 +2873,10 @@
   // Expand the binary operator.
   Result = (this->*Func)(OpInfo);
 
-  // Convert the result back to the LHS type.
-  Result =
-      EmitScalarConversion(Result, E->getComputationResultType(), LHSTy, Loc);
+  // Convert the result back to the LHS type,
+  // potentially with Implicit Conversion sanitizer check.
+  Result = EmitScalarConversion(Result, E->getComputationResultType(), LHSTy,
+                                Loc, ScalarConversionOpts(CGF.SanOpts));
 
   if (atomicPHI) {
     llvm::BasicBlock *opBB = Builder.GetInsertBlock();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to