This revision was automatically updated to reflect the committed changes.
Closed by commit rG9d869180c4ad: [ARM] Follow AACPS for preserving number of 
loads/stores of volatile bit-fields (authored by dnsampaio).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D67399/new/

https://reviews.llvm.org/D67399

Files:
  clang/include/clang/Basic/CodeGenOptions.def
  clang/include/clang/Driver/Options.td
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/test/CodeGen/aapcs-bitfield.c

Index: clang/test/CodeGen/aapcs-bitfield.c
===================================================================
--- clang/test/CodeGen/aapcs-bitfield.c
+++ clang/test/CodeGen/aapcs-bitfield.c
@@ -1,6 +1,8 @@
 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
 // RUN: %clang_cc1 -triple armv8-none-linux-eabi %s -emit-llvm -o - -O3 | FileCheck %s -check-prefix=LE
 // RUN: %clang_cc1 -triple armebv8-none-linux-eabi %s -emit-llvm -o - -O3 | FileCheck %s -check-prefix=BE
+// RUN: %clang_cc1 -triple armv8-none-linux-eabi %s -emit-llvm -o - -O3 -fAAPCSBitfieldLoad | FileCheck %s -check-prefixes=LE,LENUMLOADS
+// RUN: %clang_cc1 -triple armebv8-none-linux-eabi %s -emit-llvm -o - -O3 -fAAPCSBitfieldLoad | FileCheck %s -check-prefixes=BE,BENUMLOADS
 
 struct st0 {
   short c : 7;
@@ -144,7 +146,7 @@
 void st2_check_store(struct st2 *m) {
   m->c = 1;
 }
-
+// Volatile access is allowed to use 16 bits
 struct st3 {
   volatile short c : 7;
 };
@@ -191,7 +193,7 @@
 void st3_check_store(struct st3 *m) {
   m->c = 1;
 }
-
+// Volatile access to st4.c should use a char ld/st
 struct st4 {
   int b : 9;
   volatile char c : 5;
@@ -324,16 +326,16 @@
 // LE-LABEL: @st6_check_load(
 // LE-NEXT:  entry:
 // LE-NEXT:    [[TMP0:%.*]] = getelementptr [[STRUCT_ST6:%.*]], %struct.st6* [[M:%.*]], i32 0, i32 0
-// LE-NEXT:    [[BF_LOAD:%.*]] = load i16, i16* [[TMP0]], align 4
+// LE-NEXT:    [[BF_LOAD:%.*]] = load volatile i16, i16* [[TMP0]], align 4
 // LE-NEXT:    [[BF_SHL:%.*]] = shl i16 [[BF_LOAD]], 4
 // LE-NEXT:    [[BF_ASHR:%.*]] = ashr exact i16 [[BF_SHL]], 4
 // LE-NEXT:    [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32
 // LE-NEXT:    [[B:%.*]] = getelementptr inbounds [[STRUCT_ST6]], %struct.st6* [[M]], i32 0, i32 1
-// LE-NEXT:    [[TMP1:%.*]] = load i8, i8* [[B]], align 2, !tbaa !3
+// LE-NEXT:    [[TMP1:%.*]] = load volatile i8, i8* [[B]], align 2
 // LE-NEXT:    [[CONV:%.*]] = sext i8 [[TMP1]] to i32
 // LE-NEXT:    [[ADD:%.*]] = add nsw i32 [[BF_CAST]], [[CONV]]
 // LE-NEXT:    [[C:%.*]] = getelementptr inbounds [[STRUCT_ST6]], %struct.st6* [[M]], i32 0, i32 2
-// LE-NEXT:    [[BF_LOAD1:%.*]] = load i8, i8* [[C]], align 1
+// LE-NEXT:    [[BF_LOAD1:%.*]] = load volatile i8, i8* [[C]], align 1
 // LE-NEXT:    [[BF_SHL2:%.*]] = shl i8 [[BF_LOAD1]], 3
 // LE-NEXT:    [[BF_ASHR3:%.*]] = ashr exact i8 [[BF_SHL2]], 3
 // LE-NEXT:    [[BF_CAST4:%.*]] = sext i8 [[BF_ASHR3]] to i32
@@ -343,21 +345,21 @@
 // BE-LABEL: @st6_check_load(
 // BE-NEXT:  entry:
 // BE-NEXT:    [[TMP0:%.*]] = getelementptr [[STRUCT_ST6:%.*]], %struct.st6* [[M:%.*]], i32 0, i32 0
-// BE-NEXT:    [[BF_LOAD:%.*]] = load i16, i16* [[TMP0]], align 4
+// BE-NEXT:    [[BF_LOAD:%.*]] = load volatile i16, i16* [[TMP0]], align 4
 // BE-NEXT:    [[BF_ASHR:%.*]] = ashr i16 [[BF_LOAD]], 4
 // BE-NEXT:    [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32
 // BE-NEXT:    [[B:%.*]] = getelementptr inbounds [[STRUCT_ST6]], %struct.st6* [[M]], i32 0, i32 1
-// BE-NEXT:    [[TMP1:%.*]] = load i8, i8* [[B]], align 2, !tbaa !3
+// BE-NEXT:    [[TMP1:%.*]] = load volatile i8, i8* [[B]], align 2
 // BE-NEXT:    [[CONV:%.*]] = sext i8 [[TMP1]] to i32
 // BE-NEXT:    [[ADD:%.*]] = add nsw i32 [[BF_CAST]], [[CONV]]
 // BE-NEXT:    [[C:%.*]] = getelementptr inbounds [[STRUCT_ST6]], %struct.st6* [[M]], i32 0, i32 2
-// BE-NEXT:    [[BF_LOAD1:%.*]] = load i8, i8* [[C]], align 1
+// BE-NEXT:    [[BF_LOAD1:%.*]] = load volatile i8, i8* [[C]], align 1
 // BE-NEXT:    [[BF_ASHR2:%.*]] = ashr i8 [[BF_LOAD1]], 3
 // BE-NEXT:    [[BF_CAST3:%.*]] = sext i8 [[BF_ASHR2]] to i32
 // BE-NEXT:    [[ADD4:%.*]] = add nsw i32 [[ADD]], [[BF_CAST3]]
 // BE-NEXT:    ret i32 [[ADD4]]
 //
-int st6_check_load(struct st6 *m) {
+int st6_check_load(volatile struct st6 *m) {
   int x = m->a;
   x += m->b;
   x += m->c;
@@ -372,7 +374,7 @@
 // LE-NEXT:    [[BF_SET:%.*]] = or i16 [[BF_CLEAR]], 1
 // LE-NEXT:    store i16 [[BF_SET]], i16* [[TMP0]], align 4
 // LE-NEXT:    [[B:%.*]] = getelementptr inbounds [[STRUCT_ST6]], %struct.st6* [[M]], i32 0, i32 1
-// LE-NEXT:    store i8 2, i8* [[B]], align 2, !tbaa !3
+// LE-NEXT:    store i8 2, i8* [[B]], align 2
 // LE-NEXT:    [[C:%.*]] = getelementptr inbounds [[STRUCT_ST6]], %struct.st6* [[M]], i32 0, i32 2
 // LE-NEXT:    [[BF_LOAD1:%.*]] = load i8, i8* [[C]], align 1
 // LE-NEXT:    [[BF_CLEAR2:%.*]] = and i8 [[BF_LOAD1]], -32
@@ -388,7 +390,7 @@
 // BE-NEXT:    [[BF_SET:%.*]] = or i16 [[BF_CLEAR]], 16
 // BE-NEXT:    store i16 [[BF_SET]], i16* [[TMP0]], align 4
 // BE-NEXT:    [[B:%.*]] = getelementptr inbounds [[STRUCT_ST6]], %struct.st6* [[M]], i32 0, i32 1
-// BE-NEXT:    store i8 2, i8* [[B]], align 2, !tbaa !3
+// BE-NEXT:    store i8 2, i8* [[B]], align 2
 // BE-NEXT:    [[C:%.*]] = getelementptr inbounds [[STRUCT_ST6]], %struct.st6* [[M]], i32 0, i32 2
 // BE-NEXT:    [[BF_LOAD1:%.*]] = load i8, i8* [[C]], align 1
 // BE-NEXT:    [[BF_CLEAR2:%.*]] = and i8 [[BF_LOAD1]], 7
@@ -410,20 +412,20 @@
 
 struct st7b {
   char x;
-  struct st7a y;
+  volatile struct st7a y;
 };
 
 // LE-LABEL: @st7_check_load(
 // LE-NEXT:  entry:
 // LE-NEXT:    [[X:%.*]] = getelementptr inbounds [[STRUCT_ST7B:%.*]], %struct.st7b* [[M:%.*]], i32 0, i32 0
-// LE-NEXT:    [[TMP0:%.*]] = load i8, i8* [[X]], align 4, !tbaa !8
+// LE-NEXT:    [[TMP0:%.*]] = load i8, i8* [[X]], align 4
 // LE-NEXT:    [[CONV:%.*]] = sext i8 [[TMP0]] to i32
 // LE-NEXT:    [[A:%.*]] = getelementptr inbounds [[STRUCT_ST7B]], %struct.st7b* [[M]], i32 0, i32 2, i32 0
-// LE-NEXT:    [[TMP1:%.*]] = load i8, i8* [[A]], align 4, !tbaa !11
+// LE-NEXT:    [[TMP1:%.*]] = load volatile i8, i8* [[A]], align 4
 // LE-NEXT:    [[CONV1:%.*]] = sext i8 [[TMP1]] to i32
 // LE-NEXT:    [[ADD:%.*]] = add nsw i32 [[CONV1]], [[CONV]]
 // LE-NEXT:    [[B:%.*]] = getelementptr inbounds [[STRUCT_ST7B]], %struct.st7b* [[M]], i32 0, i32 2, i32 1
-// LE-NEXT:    [[BF_LOAD:%.*]] = load i8, i8* [[B]], align 1
+// LE-NEXT:    [[BF_LOAD:%.*]] = load volatile i8, i8* [[B]], align 1
 // LE-NEXT:    [[BF_SHL:%.*]] = shl i8 [[BF_LOAD]], 3
 // LE-NEXT:    [[BF_ASHR:%.*]] = ashr exact i8 [[BF_SHL]], 3
 // LE-NEXT:    [[BF_CAST:%.*]] = sext i8 [[BF_ASHR]] to i32
@@ -433,14 +435,14 @@
 // BE-LABEL: @st7_check_load(
 // BE-NEXT:  entry:
 // BE-NEXT:    [[X:%.*]] = getelementptr inbounds [[STRUCT_ST7B:%.*]], %struct.st7b* [[M:%.*]], i32 0, i32 0
-// BE-NEXT:    [[TMP0:%.*]] = load i8, i8* [[X]], align 4, !tbaa !8
+// BE-NEXT:    [[TMP0:%.*]] = load i8, i8* [[X]], align 4
 // BE-NEXT:    [[CONV:%.*]] = sext i8 [[TMP0]] to i32
 // BE-NEXT:    [[A:%.*]] = getelementptr inbounds [[STRUCT_ST7B]], %struct.st7b* [[M]], i32 0, i32 2, i32 0
-// BE-NEXT:    [[TMP1:%.*]] = load i8, i8* [[A]], align 4, !tbaa !11
+// BE-NEXT:    [[TMP1:%.*]] = load volatile i8, i8* [[A]], align 4
 // BE-NEXT:    [[CONV1:%.*]] = sext i8 [[TMP1]] to i32
 // BE-NEXT:    [[ADD:%.*]] = add nsw i32 [[CONV1]], [[CONV]]
 // BE-NEXT:    [[B:%.*]] = getelementptr inbounds [[STRUCT_ST7B]], %struct.st7b* [[M]], i32 0, i32 2, i32 1
-// BE-NEXT:    [[BF_LOAD:%.*]] = load i8, i8* [[B]], align 1
+// BE-NEXT:    [[BF_LOAD:%.*]] = load volatile i8, i8* [[B]], align 1
 // BE-NEXT:    [[BF_ASHR:%.*]] = ashr i8 [[BF_LOAD]], 3
 // BE-NEXT:    [[BF_CAST:%.*]] = sext i8 [[BF_ASHR]] to i32
 // BE-NEXT:    [[ADD3:%.*]] = add nsw i32 [[ADD]], [[BF_CAST]]
@@ -456,27 +458,27 @@
 // LE-LABEL: @st7_check_store(
 // LE-NEXT:  entry:
 // LE-NEXT:    [[X:%.*]] = getelementptr inbounds [[STRUCT_ST7B:%.*]], %struct.st7b* [[M:%.*]], i32 0, i32 0
-// LE-NEXT:    store i8 1, i8* [[X]], align 4, !tbaa !8
+// LE-NEXT:    store i8 1, i8* [[X]], align 4
 // LE-NEXT:    [[A:%.*]] = getelementptr inbounds [[STRUCT_ST7B]], %struct.st7b* [[M]], i32 0, i32 2, i32 0
-// LE-NEXT:    store i8 2, i8* [[A]], align 4, !tbaa !11
+// LE-NEXT:    store volatile i8 2, i8* [[A]], align 4
 // LE-NEXT:    [[B:%.*]] = getelementptr inbounds [[STRUCT_ST7B]], %struct.st7b* [[M]], i32 0, i32 2, i32 1
-// LE-NEXT:    [[BF_LOAD:%.*]] = load i8, i8* [[B]], align 1
+// LE-NEXT:    [[BF_LOAD:%.*]] = load volatile i8, i8* [[B]], align 1
 // LE-NEXT:    [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], -32
 // LE-NEXT:    [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 3
-// LE-NEXT:    store i8 [[BF_SET]], i8* [[B]], align 1
+// LE-NEXT:    store volatile i8 [[BF_SET]], i8* [[B]], align 1
 // LE-NEXT:    ret void
 //
 // BE-LABEL: @st7_check_store(
 // BE-NEXT:  entry:
 // BE-NEXT:    [[X:%.*]] = getelementptr inbounds [[STRUCT_ST7B:%.*]], %struct.st7b* [[M:%.*]], i32 0, i32 0
-// BE-NEXT:    store i8 1, i8* [[X]], align 4, !tbaa !8
+// BE-NEXT:    store i8 1, i8* [[X]], align 4
 // BE-NEXT:    [[A:%.*]] = getelementptr inbounds [[STRUCT_ST7B]], %struct.st7b* [[M]], i32 0, i32 2, i32 0
-// BE-NEXT:    store i8 2, i8* [[A]], align 4, !tbaa !11
+// BE-NEXT:    store volatile i8 2, i8* [[A]], align 4
 // BE-NEXT:    [[B:%.*]] = getelementptr inbounds [[STRUCT_ST7B]], %struct.st7b* [[M]], i32 0, i32 2, i32 1
-// BE-NEXT:    [[BF_LOAD:%.*]] = load i8, i8* [[B]], align 1
+// BE-NEXT:    [[BF_LOAD:%.*]] = load volatile i8, i8* [[B]], align 1
 // BE-NEXT:    [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], 7
 // BE-NEXT:    [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 24
-// BE-NEXT:    store i8 [[BF_SET]], i8* [[B]], align 1
+// BE-NEXT:    store volatile i8 [[BF_SET]], i8* [[B]], align 1
 // BE-NEXT:    ret void
 //
 void st7_check_store(struct st7b *m) {
@@ -531,12 +533,14 @@
 // LE-LABEL: @store_st9(
 // LE-NEXT:  entry:
 // LE-NEXT:    [[TMP0:%.*]] = getelementptr [[STRUCT_ST9:%.*]], %struct.st9* [[M:%.*]], i32 0, i32 0
+// LENUMLOADS-NEXT:    [[BF_LOAD:%.*]] = load volatile i8, i8* [[TMP0]], align 4
 // LE-NEXT:    store volatile i8 1, i8* [[TMP0]], align 4
 // LE-NEXT:    ret void
 //
 // BE-LABEL: @store_st9(
 // BE-NEXT:  entry:
 // BE-NEXT:    [[TMP0:%.*]] = getelementptr [[STRUCT_ST9:%.*]], %struct.st9* [[M:%.*]], i32 0, i32 0
+// BENUMLOADS-NEXT:    [[BF_LOAD:%.*]] = load volatile i8, i8* [[TMP0]], align 4
 // BE-NEXT:    store volatile i8 1, i8* [[TMP0]], align 4
 // BE-NEXT:    ret void
 //
@@ -549,6 +553,7 @@
 // LE-NEXT:    [[TMP0:%.*]] = getelementptr [[STRUCT_ST9:%.*]], %struct.st9* [[M:%.*]], i32 0, i32 0
 // LE-NEXT:    [[BF_LOAD:%.*]] = load volatile i8, i8* [[TMP0]], align 4
 // LE-NEXT:    [[INC:%.*]] = add i8 [[BF_LOAD]], 1
+// LENUMLOADS-NEXT:    [[BF_LOAD1:%.*]] = load volatile i8, i8* [[TMP0]], align 4
 // LE-NEXT:    store volatile i8 [[INC]], i8* [[TMP0]], align 4
 // LE-NEXT:    ret void
 //
@@ -557,6 +562,7 @@
 // BE-NEXT:    [[TMP0:%.*]] = getelementptr [[STRUCT_ST9:%.*]], %struct.st9* [[M:%.*]], i32 0, i32 0
 // BE-NEXT:    [[BF_LOAD:%.*]] = load volatile i8, i8* [[TMP0]], align 4
 // BE-NEXT:    [[INC:%.*]] = add i8 [[BF_LOAD]], 1
+// BENUMLOADS-NEXT:    [[BF_LOAD1:%.*]] = load volatile i8, i8* [[TMP0]], align 4
 // BE-NEXT:    store volatile i8 [[INC]], i8* [[TMP0]], align 4
 // BE-NEXT:    ret void
 //
@@ -667,12 +673,14 @@
 // LE-LABEL: @store_st11(
 // LE-NEXT:  entry:
 // LE-NEXT:    [[F:%.*]] = getelementptr inbounds [[STRUCT_ST11:%.*]], %struct.st11* [[M:%.*]], i32 0, i32 1
+// LENUMLOADS-NEXT:    [[BF_LOAD:%.*]] = load volatile i16, i16* [[F]], align 1
 // LE-NEXT:    store volatile i16 1, i16* [[F]], align 1
 // LE-NEXT:    ret void
 //
 // BE-LABEL: @store_st11(
 // BE-NEXT:  entry:
 // BE-NEXT:    [[F:%.*]] = getelementptr inbounds [[STRUCT_ST11:%.*]], %struct.st11* [[M:%.*]], i32 0, i32 1
+// BENUMLOADS-NEXT:    [[BF_LOAD:%.*]] = load volatile i16, i16* [[F]], align 1
 // BE-NEXT:    store volatile i16 1, i16* [[F]], align 1
 // BE-NEXT:    ret void
 //
@@ -685,6 +693,7 @@
 // LE-NEXT:    [[F:%.*]] = getelementptr inbounds [[STRUCT_ST11:%.*]], %struct.st11* [[M:%.*]], i32 0, i32 1
 // LE-NEXT:    [[BF_LOAD:%.*]] = load volatile i16, i16* [[F]], align 1
 // LE-NEXT:    [[INC:%.*]] = add i16 [[BF_LOAD]], 1
+// LENUMLOADS-NEXT:    [[BF_LOAD1:%.*]] = load volatile i16, i16* [[F]], align 1
 // LE-NEXT:    store volatile i16 [[INC]], i16* [[F]], align 1
 // LE-NEXT:    ret void
 //
@@ -693,6 +702,7 @@
 // BE-NEXT:    [[F:%.*]] = getelementptr inbounds [[STRUCT_ST11:%.*]], %struct.st11* [[M:%.*]], i32 0, i32 1
 // BE-NEXT:    [[BF_LOAD:%.*]] = load volatile i16, i16* [[F]], align 1
 // BE-NEXT:    [[INC:%.*]] = add i16 [[BF_LOAD]], 1
+// BENUMLOADS-NEXT:    [[BF_LOAD1:%.*]] = load volatile i16, i16* [[F]], align 1
 // BE-NEXT:    store volatile i16 [[INC]], i16* [[F]], align 1
 // BE-NEXT:    ret void
 //
@@ -703,17 +713,17 @@
 // LE-LABEL: @increment_e_st11(
 // LE-NEXT:  entry:
 // LE-NEXT:    [[E:%.*]] = getelementptr inbounds [[STRUCT_ST11:%.*]], %struct.st11* [[M:%.*]], i32 0, i32 0
-// LE-NEXT:    [[TMP0:%.*]] = load volatile i8, i8* [[E]], align 4, !tbaa !12
+// LE-NEXT:    [[TMP0:%.*]] = load volatile i8, i8* [[E]], align 4
 // LE-NEXT:    [[INC:%.*]] = add i8 [[TMP0]], 1
-// LE-NEXT:    store volatile i8 [[INC]], i8* [[E]], align 4, !tbaa !12
+// LE-NEXT:    store volatile i8 [[INC]], i8* [[E]], align 4
 // LE-NEXT:    ret void
 //
 // BE-LABEL: @increment_e_st11(
 // BE-NEXT:  entry:
 // BE-NEXT:    [[E:%.*]] = getelementptr inbounds [[STRUCT_ST11:%.*]], %struct.st11* [[M:%.*]], i32 0, i32 0
-// BE-NEXT:    [[TMP0:%.*]] = load volatile i8, i8* [[E]], align 4, !tbaa !12
+// BE-NEXT:    [[TMP0:%.*]] = load volatile i8, i8* [[E]], align 4
 // BE-NEXT:    [[INC:%.*]] = add i8 [[TMP0]], 1
-// BE-NEXT:    store volatile i8 [[INC]], i8* [[E]], align 4, !tbaa !12
+// BE-NEXT:    store volatile i8 [[INC]], i8* [[E]], align 4
 // BE-NEXT:    ret void
 //
 void increment_e_st11(volatile struct st11 *m) {
@@ -822,3 +832,433 @@
 void increment_e_st12(volatile struct st12 *m) {
   ++m->e;
 }
+
+struct st13 {
+  char a : 8;
+  int b : 32;
+} __attribute__((packed));
+
+// LE-LABEL: @increment_b_st13(
+// LE-NEXT:  entry:
+// LE-NEXT:    [[TMP0:%.*]] = bitcast %struct.st13* [[S:%.*]] to i40*
+// LE-NEXT:    [[BF_LOAD:%.*]] = load volatile i40, i40* [[TMP0]], align 1
+// LE-NEXT:    [[TMP1:%.*]] = lshr i40 [[BF_LOAD]], 8
+// LE-NEXT:    [[BF_CAST:%.*]] = trunc i40 [[TMP1]] to i32
+// LE-NEXT:    [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1
+// LE-NEXT:    [[TMP2:%.*]] = zext i32 [[INC]] to i40
+// LE-NEXT:    [[BF_LOAD1:%.*]] = load volatile i40, i40* [[TMP0]], align 1
+// LE-NEXT:    [[BF_SHL:%.*]] = shl nuw i40 [[TMP2]], 8
+// LE-NEXT:    [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], 255
+// LE-NEXT:    [[BF_SET:%.*]] = or i40 [[BF_SHL]], [[BF_CLEAR]]
+// LE-NEXT:    store volatile i40 [[BF_SET]], i40* [[TMP0]], align 1
+// LE-NEXT:    ret void
+//
+// BE-LABEL: @increment_b_st13(
+// BE-NEXT:  entry:
+// BE-NEXT:    [[TMP0:%.*]] = bitcast %struct.st13* [[S:%.*]] to i40*
+// BE-NEXT:    [[BF_LOAD:%.*]] = load volatile i40, i40* [[TMP0]], align 1
+// BE-NEXT:    [[BF_CAST:%.*]] = trunc i40 [[BF_LOAD]] to i32
+// BE-NEXT:    [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1
+// BE-NEXT:    [[TMP1:%.*]] = zext i32 [[INC]] to i40
+// BE-NEXT:    [[BF_LOAD1:%.*]] = load volatile i40, i40* [[TMP0]], align 1
+// BE-NEXT:    [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], -4294967296
+// BE-NEXT:    [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[TMP1]]
+// BE-NEXT:    store volatile i40 [[BF_SET]], i40* [[TMP0]], align 1
+// BE-NEXT:    ret void
+//
+void increment_b_st13(volatile struct st13 *s) {
+  s->b++;
+}
+
+struct st14 {
+  char a : 8;
+} __attribute__((packed));
+
+// LE-LABEL: @increment_a_st14(
+// LE-NEXT:  entry:
+// LE-NEXT:    [[TMP0:%.*]] = getelementptr [[STRUCT_ST14:%.*]], %struct.st14* [[S:%.*]], i32 0, i32 0
+// LE-NEXT:    [[BF_LOAD:%.*]] = load volatile i8, i8* [[TMP0]], align 1
+// LE-NEXT:    [[INC:%.*]] = add i8 [[BF_LOAD]], 1
+// LENUMLOADS-NEXT:    [[BF_LOAD1:%.*]] = load volatile i8, i8* [[TMP0]], align 1
+// LE-NEXT:    store volatile i8 [[INC]], i8* [[TMP0]], align 1
+// LE-NEXT:    ret void
+//
+// BE-LABEL: @increment_a_st14(
+// BE-NEXT:  entry:
+// BE-NEXT:    [[TMP0:%.*]] = getelementptr [[STRUCT_ST14:%.*]], %struct.st14* [[S:%.*]], i32 0, i32 0
+// BE-NEXT:    [[BF_LOAD:%.*]] = load volatile i8, i8* [[TMP0]], align 1
+// BE-NEXT:    [[INC:%.*]] = add i8 [[BF_LOAD]], 1
+// BENUMLOADS-NEXT:    [[BF_LOAD1:%.*]] = load volatile i8, i8* [[TMP0]], align 1
+// BE-NEXT:    store volatile i8 [[INC]], i8* [[TMP0]], align 1
+// BE-NEXT:    ret void
+//
+void increment_a_st14(volatile struct st14 *s) {
+  s->a++;
+}
+
+struct st15 {
+  short a : 8;
+} __attribute__((packed));
+
+// LE-LABEL: @increment_a_st15(
+// LE-NEXT:  entry:
+// LE-NEXT:    [[TMP0:%.*]] = getelementptr [[STRUCT_ST15:%.*]], %struct.st15* [[S:%.*]], i32 0, i32 0
+// LE-NEXT:    [[BF_LOAD:%.*]] = load volatile i8, i8* [[TMP0]], align 1
+// LE-NEXT:    [[INC:%.*]] = add i8 [[BF_LOAD]], 1
+// LENUMLOADS-NEXT:    [[BF_LOAD1:%.*]] = load volatile i8, i8* [[TMP0]], align 1
+// LE-NEXT:    store volatile i8 [[INC]], i8* [[TMP0]], align 1
+// LE-NEXT:    ret void
+//
+// BE-LABEL: @increment_a_st15(
+// BE-NEXT:  entry:
+// BE-NEXT:    [[TMP0:%.*]] = getelementptr [[STRUCT_ST15:%.*]], %struct.st15* [[S:%.*]], i32 0, i32 0
+// BE-NEXT:    [[BF_LOAD:%.*]] = load volatile i8, i8* [[TMP0]], align 1
+// BE-NEXT:    [[INC:%.*]] = add i8 [[BF_LOAD]], 1
+// BENUMLOADS-NEXT:    [[BF_LOAD1:%.*]] = load volatile i8, i8* [[TMP0]], align 1
+// BE-NEXT:    store volatile i8 [[INC]], i8* [[TMP0]], align 1
+// BE-NEXT:    ret void
+//
+void increment_a_st15(volatile struct st15 *s) {
+  s->a++;
+}
+
+struct st16 {
+  int a : 32;
+  int b : 16;
+  int c : 32;
+  int d : 16;
+};
+
+// LE-LABEL: @increment_a_st16(
+// LE-NEXT:  entry:
+// LE-NEXT:    [[TMP0:%.*]] = bitcast %struct.st16* [[S:%.*]] to i64*
+// LE-NEXT:    [[BF_LOAD:%.*]] = load i64, i64* [[TMP0]], align 4
+// LE-NEXT:    [[BF_CAST:%.*]] = trunc i64 [[BF_LOAD]] to i32
+// LE-NEXT:    [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1
+// LE-NEXT:    [[TMP1:%.*]] = zext i32 [[INC]] to i64
+// LE-NEXT:    [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD]], -4294967296
+// LE-NEXT:    [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[TMP1]]
+// LE-NEXT:    store i64 [[BF_SET]], i64* [[TMP0]], align 4
+// LE-NEXT:    ret void
+//
+// BE-LABEL: @increment_a_st16(
+// BE-NEXT:  entry:
+// BE-NEXT:    [[TMP0:%.*]] = bitcast %struct.st16* [[S:%.*]] to i64*
+// BE-NEXT:    [[BF_LOAD:%.*]] = load i64, i64* [[TMP0]], align 4
+// BE-NEXT:    [[TMP1:%.*]] = lshr i64 [[BF_LOAD]], 32
+// BE-NEXT:    [[BF_CAST:%.*]] = trunc i64 [[TMP1]] to i32
+// BE-NEXT:    [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1
+// BE-NEXT:    [[TMP2:%.*]] = zext i32 [[INC]] to i64
+// BE-NEXT:    [[BF_SHL:%.*]] = shl nuw i64 [[TMP2]], 32
+// BE-NEXT:    [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD]], 4294967295
+// BE-NEXT:    [[BF_SET:%.*]] = or i64 [[BF_SHL]], [[BF_CLEAR]]
+// BE-NEXT:    store i64 [[BF_SET]], i64* [[TMP0]], align 4
+// BE-NEXT:    ret void
+//
+void increment_a_st16(struct st16 *s) {
+  s->a++;
+}
+
+// LE-LABEL: @increment_b_st16(
+// LE-NEXT:  entry:
+// LE-NEXT:    [[TMP0:%.*]] = bitcast %struct.st16* [[S:%.*]] to i64*
+// LE-NEXT:    [[BF_LOAD:%.*]] = load i64, i64* [[TMP0]], align 4
+// LE-NEXT:    [[TMP1:%.*]] = lshr i64 [[BF_LOAD]], 32
+// LE-NEXT:    [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32
+// LE-NEXT:    [[INC:%.*]] = add i32 [[TMP2]], 1
+// LE-NEXT:    [[TMP3:%.*]] = and i32 [[INC]], 65535
+// LE-NEXT:    [[BF_VALUE:%.*]] = zext i32 [[TMP3]] to i64
+// LE-NEXT:    [[BF_SHL2:%.*]] = shl nuw nsw i64 [[BF_VALUE]], 32
+// LE-NEXT:    [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD]], -281470681743361
+// LE-NEXT:    [[BF_SET:%.*]] = or i64 [[BF_SHL2]], [[BF_CLEAR]]
+// LE-NEXT:    store i64 [[BF_SET]], i64* [[TMP0]], align 4
+// LE-NEXT:    ret void
+//
+// BE-LABEL: @increment_b_st16(
+// BE-NEXT:  entry:
+// BE-NEXT:    [[TMP0:%.*]] = bitcast %struct.st16* [[S:%.*]] to i64*
+// BE-NEXT:    [[BF_LOAD:%.*]] = load i64, i64* [[TMP0]], align 4
+// BE-NEXT:    [[TMP1:%.*]] = trunc i64 [[BF_LOAD]] to i32
+// BE-NEXT:    [[INC4:%.*]] = add i32 [[TMP1]], 65536
+// BE-NEXT:    [[TMP2:%.*]] = and i32 [[INC4]], -65536
+// BE-NEXT:    [[BF_SHL2:%.*]] = zext i32 [[TMP2]] to i64
+// BE-NEXT:    [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD]], -4294901761
+// BE-NEXT:    [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]]
+// BE-NEXT:    store i64 [[BF_SET]], i64* [[TMP0]], align 4
+// BE-NEXT:    ret void
+//
+void increment_b_st16(struct st16 *s) {
+  s->b++;
+}
+
+// LE-LABEL: @increment_c_st16(
+// LE-NEXT:  entry:
+// LE-NEXT:    [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], %struct.st16* [[S:%.*]], i32 0, i32 1
+// LE-NEXT:    [[TMP0:%.*]] = bitcast i48* [[C]] to i64*
+// LE-NEXT:    [[BF_LOAD:%.*]] = load i64, i64* [[TMP0]], align 4
+// LE-NEXT:    [[BF_CAST:%.*]] = trunc i64 [[BF_LOAD]] to i32
+// LE-NEXT:    [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1
+// LE-NEXT:    [[TMP1:%.*]] = zext i32 [[INC]] to i64
+// LE-NEXT:    [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD]], -4294967296
+// LE-NEXT:    [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[TMP1]]
+// LE-NEXT:    store i64 [[BF_SET]], i64* [[TMP0]], align 4
+// LE-NEXT:    ret void
+//
+// BE-LABEL: @increment_c_st16(
+// BE-NEXT:  entry:
+// BE-NEXT:    [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], %struct.st16* [[S:%.*]], i32 0, i32 1
+// BE-NEXT:    [[TMP0:%.*]] = bitcast i48* [[C]] to i64*
+// BE-NEXT:    [[BF_LOAD:%.*]] = load i64, i64* [[TMP0]], align 4
+// BE-NEXT:    [[TMP1:%.*]] = lshr i64 [[BF_LOAD]], 32
+// BE-NEXT:    [[BF_CAST:%.*]] = trunc i64 [[TMP1]] to i32
+// BE-NEXT:    [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1
+// BE-NEXT:    [[TMP2:%.*]] = zext i32 [[INC]] to i64
+// BE-NEXT:    [[BF_SHL:%.*]] = shl nuw i64 [[TMP2]], 32
+// BE-NEXT:    [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD]], 4294967295
+// BE-NEXT:    [[BF_SET:%.*]] = or i64 [[BF_SHL]], [[BF_CLEAR]]
+// BE-NEXT:    store i64 [[BF_SET]], i64* [[TMP0]], align 4
+// BE-NEXT:    ret void
+//
+void increment_c_st16(struct st16 *s) {
+  s->c++;
+}
+
+// LE-LABEL: @increment_d_st16(
+// LE-NEXT:  entry:
+// LE-NEXT:    [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], %struct.st16* [[S:%.*]], i32 0, i32 1
+// LE-NEXT:    [[TMP0:%.*]] = bitcast i48* [[D]] to i64*
+// LE-NEXT:    [[BF_LOAD:%.*]] = load i64, i64* [[TMP0]], align 4
+// LE-NEXT:    [[TMP1:%.*]] = lshr i64 [[BF_LOAD]], 32
+// LE-NEXT:    [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32
+// LE-NEXT:    [[INC:%.*]] = add i32 [[TMP2]], 1
+// LE-NEXT:    [[TMP3:%.*]] = and i32 [[INC]], 65535
+// LE-NEXT:    [[BF_VALUE:%.*]] = zext i32 [[TMP3]] to i64
+// LE-NEXT:    [[BF_SHL2:%.*]] = shl nuw nsw i64 [[BF_VALUE]], 32
+// LE-NEXT:    [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD]], -281470681743361
+// LE-NEXT:    [[BF_SET:%.*]] = or i64 [[BF_SHL2]], [[BF_CLEAR]]
+// LE-NEXT:    store i64 [[BF_SET]], i64* [[TMP0]], align 4
+// LE-NEXT:    ret void
+//
+// BE-LABEL: @increment_d_st16(
+// BE-NEXT:  entry:
+// BE-NEXT:    [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], %struct.st16* [[S:%.*]], i32 0, i32 1
+// BE-NEXT:    [[TMP0:%.*]] = bitcast i48* [[D]] to i64*
+// BE-NEXT:    [[BF_LOAD:%.*]] = load i64, i64* [[TMP0]], align 4
+// BE-NEXT:    [[TMP1:%.*]] = trunc i64 [[BF_LOAD]] to i32
+// BE-NEXT:    [[INC4:%.*]] = add i32 [[TMP1]], 65536
+// BE-NEXT:    [[TMP2:%.*]] = and i32 [[INC4]], -65536
+// BE-NEXT:    [[BF_SHL2:%.*]] = zext i32 [[TMP2]] to i64
+// BE-NEXT:    [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD]], -4294901761
+// BE-NEXT:    [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]]
+// BE-NEXT:    store i64 [[BF_SET]], i64* [[TMP0]], align 4
+// BE-NEXT:    ret void
+//
+void increment_d_st16(struct st16 *s) {
+  s->d++;
+}
+
+// LE-LABEL: @increment_v_a_st16(
+// LE-NEXT:  entry:
+// LE-NEXT:    [[TMP0:%.*]] = bitcast %struct.st16* [[S:%.*]] to i64*
+// LE-NEXT:    [[BF_LOAD:%.*]] = load volatile i64, i64* [[TMP0]], align 4
+// LE-NEXT:    [[BF_CAST:%.*]] = trunc i64 [[BF_LOAD]] to i32
+// LE-NEXT:    [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1
+// LE-NEXT:    [[TMP1:%.*]] = zext i32 [[INC]] to i64
+// LE-NEXT:    [[BF_LOAD1:%.*]] = load volatile i64, i64* [[TMP0]], align 4
+// LE-NEXT:    [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294967296
+// LE-NEXT:    [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[TMP1]]
+// LE-NEXT:    store volatile i64 [[BF_SET]], i64* [[TMP0]], align 4
+// LE-NEXT:    ret void
+//
+// BE-LABEL: @increment_v_a_st16(
+// BE-NEXT:  entry:
+// BE-NEXT:    [[TMP0:%.*]] = bitcast %struct.st16* [[S:%.*]] to i64*
+// BE-NEXT:    [[BF_LOAD:%.*]] = load volatile i64, i64* [[TMP0]], align 4
+// BE-NEXT:    [[TMP1:%.*]] = lshr i64 [[BF_LOAD]], 32
+// BE-NEXT:    [[BF_CAST:%.*]] = trunc i64 [[TMP1]] to i32
+// BE-NEXT:    [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1
+// BE-NEXT:    [[TMP2:%.*]] = zext i32 [[INC]] to i64
+// BE-NEXT:    [[BF_LOAD1:%.*]] = load volatile i64, i64* [[TMP0]], align 4
+// BE-NEXT:    [[BF_SHL:%.*]] = shl nuw i64 [[TMP2]], 32
+// BE-NEXT:    [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], 4294967295
+// BE-NEXT:    [[BF_SET:%.*]] = or i64 [[BF_SHL]], [[BF_CLEAR]]
+// BE-NEXT:    store volatile i64 [[BF_SET]], i64* [[TMP0]], align 4
+// BE-NEXT:    ret void
+//
+void increment_v_a_st16(volatile struct st16 *s) {
+  s->a++;
+}
+
+// LE-LABEL: @increment_v_b_st16(
+// LE-NEXT:  entry:
+// LE-NEXT:    [[TMP0:%.*]] = bitcast %struct.st16* [[S:%.*]] to i64*
+// LE-NEXT:    [[BF_LOAD:%.*]] = load volatile i64, i64* [[TMP0]], align 4
+// LE-NEXT:    [[TMP1:%.*]] = lshr i64 [[BF_LOAD]], 32
+// LE-NEXT:    [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32
+// LE-NEXT:    [[INC:%.*]] = add i32 [[TMP2]], 1
+// LE-NEXT:    [[BF_LOAD1:%.*]] = load volatile i64, i64* [[TMP0]], align 4
+// LE-NEXT:    [[TMP3:%.*]] = and i32 [[INC]], 65535
+// LE-NEXT:    [[BF_VALUE:%.*]] = zext i32 [[TMP3]] to i64
+// LE-NEXT:    [[BF_SHL2:%.*]] = shl nuw nsw i64 [[BF_VALUE]], 32
+// LE-NEXT:    [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -281470681743361
+// LE-NEXT:    [[BF_SET:%.*]] = or i64 [[BF_SHL2]], [[BF_CLEAR]]
+// LE-NEXT:    store volatile i64 [[BF_SET]], i64* [[TMP0]], align 4
+// LE-NEXT:    ret void
+//
+// BE-LABEL: @increment_v_b_st16(
+// BE-NEXT:  entry:
+// BE-NEXT:    [[TMP0:%.*]] = bitcast %struct.st16* [[S:%.*]] to i64*
+// BE-NEXT:    [[BF_LOAD:%.*]] = load volatile i64, i64* [[TMP0]], align 4
+// BE-NEXT:    [[BF_LOAD1:%.*]] = load volatile i64, i64* [[TMP0]], align 4
+// BE-NEXT:    [[TMP1:%.*]] = trunc i64 [[BF_LOAD]] to i32
+// BE-NEXT:    [[INC4:%.*]] = add i32 [[TMP1]], 65536
+// BE-NEXT:    [[TMP2:%.*]] = and i32 [[INC4]], -65536
+// BE-NEXT:    [[BF_SHL2:%.*]] = zext i32 [[TMP2]] to i64
+// BE-NEXT:    [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294901761
+// BE-NEXT:    [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]]
+// BE-NEXT:    store volatile i64 [[BF_SET]], i64* [[TMP0]], align 4
+// BE-NEXT:    ret void
+//
+void increment_v_b_st16(volatile struct st16 *s) {
+  s->b++;
+}
+
+// LE-LABEL: @increment_v_c_st16(
+// LE-NEXT:  entry:
+// LE-NEXT:    [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], %struct.st16* [[S:%.*]], i32 0, i32 1
+// LE-NEXT:    [[TMP0:%.*]] = bitcast i48* [[C]] to i64*
+// LE-NEXT:    [[BF_LOAD:%.*]] = load volatile i64, i64* [[TMP0]], align 4
+// LE-NEXT:    [[BF_CAST:%.*]] = trunc i64 [[BF_LOAD]] to i32
+// LE-NEXT:    [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1
+// LE-NEXT:    [[TMP1:%.*]] = zext i32 [[INC]] to i64
+// LE-NEXT:    [[BF_LOAD1:%.*]] = load volatile i64, i64* [[TMP0]], align 4
+// LE-NEXT:    [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294967296
+// LE-NEXT:    [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[TMP1]]
+// LE-NEXT:    store volatile i64 [[BF_SET]], i64* [[TMP0]], align 4
+// LE-NEXT:    ret void
+//
+// BE-LABEL: @increment_v_c_st16(
+// BE-NEXT:  entry:
+// BE-NEXT:    [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], %struct.st16* [[S:%.*]], i32 0, i32 1
+// BE-NEXT:    [[TMP0:%.*]] = bitcast i48* [[C]] to i64*
+// BE-NEXT:    [[BF_LOAD:%.*]] = load volatile i64, i64* [[TMP0]], align 4
+// BE-NEXT:    [[TMP1:%.*]] = lshr i64 [[BF_LOAD]], 32
+// BE-NEXT:    [[BF_CAST:%.*]] = trunc i64 [[TMP1]] to i32
+// BE-NEXT:    [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1
+// BE-NEXT:    [[TMP2:%.*]] = zext i32 [[INC]] to i64
+// BE-NEXT:    [[BF_LOAD1:%.*]] = load volatile i64, i64* [[TMP0]], align 4
+// BE-NEXT:    [[BF_SHL:%.*]] = shl nuw i64 [[TMP2]], 32
+// BE-NEXT:    [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], 4294967295
+// BE-NEXT:    [[BF_SET:%.*]] = or i64 [[BF_SHL]], [[BF_CLEAR]]
+// BE-NEXT:    store volatile i64 [[BF_SET]], i64* [[TMP0]], align 4
+// BE-NEXT:    ret void
+//
+void increment_v_c_st16(volatile struct st16 *s) {
+  s->c++;
+}
+
+// LE-LABEL: @increment_v_d_st16(
+// LE-NEXT:  entry:
+// LE-NEXT:    [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], %struct.st16* [[S:%.*]], i32 0, i32 1
+// LE-NEXT:    [[TMP0:%.*]] = bitcast i48* [[D]] to i64*
+// LE-NEXT:    [[BF_LOAD:%.*]] = load volatile i64, i64* [[TMP0]], align 4
+// LE-NEXT:    [[TMP1:%.*]] = lshr i64 [[BF_LOAD]], 32
+// LE-NEXT:    [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32
+// LE-NEXT:    [[INC:%.*]] = add i32 [[TMP2]], 1
+// LE-NEXT:    [[BF_LOAD1:%.*]] = load volatile i64, i64* [[TMP0]], align 4
+// LE-NEXT:    [[TMP3:%.*]] = and i32 [[INC]], 65535
+// LE-NEXT:    [[BF_VALUE:%.*]] = zext i32 [[TMP3]] to i64
+// LE-NEXT:    [[BF_SHL2:%.*]] = shl nuw nsw i64 [[BF_VALUE]], 32
+// LE-NEXT:    [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -281470681743361
+// LE-NEXT:    [[BF_SET:%.*]] = or i64 [[BF_SHL2]], [[BF_CLEAR]]
+// LE-NEXT:    store volatile i64 [[BF_SET]], i64* [[TMP0]], align 4
+// LE-NEXT:    ret void
+//
+// BE-LABEL: @increment_v_d_st16(
+// BE-NEXT:  entry:
+// BE-NEXT:    [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], %struct.st16* [[S:%.*]], i32 0, i32 1
+// BE-NEXT:    [[TMP0:%.*]] = bitcast i48* [[D]] to i64*
+// BE-NEXT:    [[BF_LOAD:%.*]] = load volatile i64, i64* [[TMP0]], align 4
+// BE-NEXT:    [[BF_LOAD1:%.*]] = load volatile i64, i64* [[TMP0]], align 4
+// BE-NEXT:    [[TMP1:%.*]] = trunc i64 [[BF_LOAD]] to i32
+// BE-NEXT:    [[INC4:%.*]] = add i32 [[TMP1]], 65536
+// BE-NEXT:    [[TMP2:%.*]] = and i32 [[INC4]], -65536
+// BE-NEXT:    [[BF_SHL2:%.*]] = zext i32 [[TMP2]] to i64
+// BE-NEXT:    [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294901761
+// BE-NEXT:    [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]]
+// BE-NEXT:    store volatile i64 [[BF_SET]], i64* [[TMP0]], align 4
+// BE-NEXT:    ret void
+//
+void increment_v_d_st16(volatile struct st16 *s) {
+  s->d++;
+}
+// st17 has alignment = 1, the AAPCS defines nothing for the
+// accessing of b, but accessing c should use char
+struct st17 {
+int b : 32;
+char c : 8;
+} __attribute__((packed));
+
+// LE-LABEL: @increment_v_b_st17(
+// LE-NEXT:  entry:
+// LE-NEXT:    [[TMP0:%.*]] = bitcast %struct.st17* [[S:%.*]] to i40*
+// LE-NEXT:    [[BF_LOAD:%.*]] = load volatile i40, i40* [[TMP0]], align 1
+// LE-NEXT:    [[BF_CAST:%.*]] = trunc i40 [[BF_LOAD]] to i32
+// LE-NEXT:    [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1
+// LE-NEXT:    [[TMP1:%.*]] = zext i32 [[INC]] to i40
+// LE-NEXT:    [[BF_LOAD1:%.*]] = load volatile i40, i40* [[TMP0]], align 1
+// LE-NEXT:    [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], -4294967296
+// LE-NEXT:    [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[TMP1]]
+// LE-NEXT:    store volatile i40 [[BF_SET]], i40* [[TMP0]], align 1
+// LE-NEXT:    ret void
+//
+// BE-LABEL: @increment_v_b_st17(
+// BE-NEXT:  entry:
+// BE-NEXT:    [[TMP0:%.*]] = bitcast %struct.st17* [[S:%.*]] to i40*
+// BE-NEXT:    [[BF_LOAD:%.*]] = load volatile i40, i40* [[TMP0]], align 1
+// BE-NEXT:    [[TMP1:%.*]] = lshr i40 [[BF_LOAD]], 8
+// BE-NEXT:    [[BF_CAST:%.*]] = trunc i40 [[TMP1]] to i32
+// BE-NEXT:    [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1
+// BE-NEXT:    [[TMP2:%.*]] = zext i32 [[INC]] to i40
+// BE-NEXT:    [[BF_LOAD1:%.*]] = load volatile i40, i40* [[TMP0]], align 1
+// BE-NEXT:    [[BF_SHL:%.*]] = shl nuw i40 [[TMP2]], 8
+// BE-NEXT:    [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], 255
+// BE-NEXT:    [[BF_SET:%.*]] = or i40 [[BF_SHL]], [[BF_CLEAR]]
+// BE-NEXT:    store volatile i40 [[BF_SET]], i40* [[TMP0]], align 1
+// BE-NEXT:    ret void
+//
+void increment_v_b_st17(volatile struct st17 *s) {
+  s->b++;
+}
+
+// LE-LABEL: @increment_v_c_st17(
+// LE-NEXT:  entry:
+// LE-NEXT:    [[TMP0:%.*]] = bitcast %struct.st17* [[S:%.*]] to i40*
+// LE-NEXT:    [[BF_LOAD:%.*]] = load volatile i40, i40* [[TMP0]], align 1
+// LE-NEXT:    [[TMP1:%.*]] = lshr i40 [[BF_LOAD]], 32
+// LE-NEXT:    [[BF_CAST:%.*]] = trunc i40 [[TMP1]] to i8
+// LE-NEXT:    [[INC:%.*]] = add i8 [[BF_CAST]], 1
+// LE-NEXT:    [[TMP2:%.*]] = zext i8 [[INC]] to i40
+// LE-NEXT:    [[BF_LOAD1:%.*]] = load volatile i40, i40* [[TMP0]], align 1
+// LE-NEXT:    [[BF_SHL:%.*]] = shl nuw i40 [[TMP2]], 32
+// LE-NEXT:    [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], 4294967295
+// LE-NEXT:    [[BF_SET:%.*]] = or i40 [[BF_SHL]], [[BF_CLEAR]]
+// LE-NEXT:    store volatile i40 [[BF_SET]], i40* [[TMP0]], align 1
+// LE-NEXT:    ret void
+//
+// BE-LABEL: @increment_v_c_st17(
+// BE-NEXT:  entry:
+// BE-NEXT:    [[TMP0:%.*]] = bitcast %struct.st17* [[S:%.*]] to i40*
+// BE-NEXT:    [[BF_LOAD:%.*]] = load volatile i40, i40* [[TMP0]], align 1
+// BE-NEXT:    [[BF_CAST:%.*]] = trunc i40 [[BF_LOAD]] to i8
+// BE-NEXT:    [[INC:%.*]] = add i8 [[BF_CAST]], 1
+// BE-NEXT:    [[TMP1:%.*]] = zext i8 [[INC]] to i40
+// BE-NEXT:    [[BF_LOAD1:%.*]] = load volatile i40, i40* [[TMP0]], align 1
+// BE-NEXT:    [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], -256
+// BE-NEXT:    [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[TMP1]]
+// BE-NEXT:    store volatile i40 [[BF_SET]], i40* [[TMP0]], align 1
+// BE-NEXT:    ret void
+//
+void increment_v_c_st17(volatile struct st17 *s) {
+  s->c++;
+}
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -1439,6 +1439,7 @@
   Opts.SymbolPartition =
       std::string(Args.getLastArgValue(OPT_fsymbol_partition_EQ));
 
+  Opts.ForceAAPCSBitfieldLoad = Args.hasArg(OPT_ForceAAPCSBitfieldLoad);
   return Success;
 }
 
Index: clang/lib/CodeGen/CGExpr.cpp
===================================================================
--- clang/lib/CodeGen/CGExpr.cpp
+++ clang/lib/CodeGen/CGExpr.cpp
@@ -415,6 +415,11 @@
   llvm_unreachable("unknown storage duration");
 }
 
+/// Helper method to check if the underlying ABI is AAPCS
+static bool isAAPCS(const TargetInfo &TargetInfo) {
+  return TargetInfo.getABI().startswith("aapcs");
+}
+
 LValue CodeGenFunction::
 EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
   const Expr *E = M->getSubExpr();
@@ -2068,6 +2073,14 @@
     SrcVal = Builder.CreateOr(Val, SrcVal, "bf.set");
   } else {
     assert(Info.Offset == 0);
+    // According to the AACPS:
+    // When a volatile bit-field is written, and its container does not overlap
+    // with any non-bit-field member, its container must be read exactly once and
+    // written exactly once using the access width appropriate to the type of the
+    // container. The two accesses are not atomic.
+    if (Dst.isVolatileQualified() && isAAPCS(CGM.getTarget()) &&
+        CGM.getCodeGenOpts().ForceAAPCSBitfieldLoad)
+      Builder.CreateLoad(Ptr, true, "bf.load");
   }
 
   // Write the new value back out.
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -2326,6 +2326,9 @@
 def mcmse : Flag<["-"], "mcmse">, Group<m_arm_Features_Group>,
   Flags<[DriverOption,CC1Option]>,
   HelpText<"Allow use of CMSE (Armv8-M Security Extensions)">;
+def ForceAAPCSBitfieldLoad : Flag<["-"], "fAAPCSBitfieldLoad">, Group<m_arm_Features_Group>,
+  Flags<[DriverOption,CC1Option]>,
+  HelpText<"Follows the AAPCS standard that all volatile bit-field write generates at least one load. (ARM only).">;
 
 def mgeneral_regs_only : Flag<["-"], "mgeneral-regs-only">, Group<m_aarch64_Features_Group>,
   HelpText<"Generate code which only uses the general purpose registers (AArch64 only)">;
Index: clang/include/clang/Basic/CodeGenOptions.def
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.def
+++ clang/include/clang/Basic/CodeGenOptions.def
@@ -389,6 +389,9 @@
 /// Whether to emit unused static constants.
 CODEGENOPT(KeepStaticConsts, 1, 0)
 
+/// Whether to not follow the AAPCS that enforce at least one read before storing to a volatile bitfield
+CODEGENOPT(ForceAAPCSBitfieldLoad, 1, 0)
+
 #undef CODEGENOPT
 #undef ENUM_CODEGENOPT
 #undef VALUE_CODEGENOPT
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to