diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -388,6 +388,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 diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2317,6 +2317,9 @@ def mcmse : Flag<["-"], "mcmse">, Group, Flags<[DriverOption,CC1Option]>, HelpText<"Allow use of CMSE (Armv8-M Security Extensions)">; +def ForceAAPCSBitfieldLoad : Flag<["-"], "fAAPCSBitfieldLoad">, 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, HelpText<"Generate code which only uses the general purpose registers (AArch64 only)">; diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -2080,6 +2080,14 @@ SrcVal = Builder.CreateOr(Val, SrcVal, "bf.set"); } else { assert(Offset == 0); + // Acording 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. diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1442,6 +1442,7 @@ Opts.SymbolPartition = std::string(Args.getLastArgValue(OPT_fsymbol_partition_EQ)); + Opts.ForceAAPCSBitfieldLoad = Args.hasArg(OPT_ForceAAPCSBitfieldLoad); return Success; } diff --git a/clang/test/CodeGen/aapcs-bitfield.c b/clang/test/CodeGen/aapcs-bitfield.c --- a/clang/test/CodeGen/aapcs-bitfield.c +++ b/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; @@ -680,12 +682,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 // @@ -698,6 +702,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 // @@ -706,6 +711,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 // @@ -882,6 +888,7 @@ // 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 // @@ -890,6 +897,7 @@ // 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 // @@ -906,6 +914,7 @@ // 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 // @@ -914,6 +923,7 @@ // 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 // @@ -1061,6 +1071,7 @@ // LE-NEXT: [[TMP0:%.*]] = bitcast %struct.st16* [[S:%.*]] to i32* // LE-NEXT: [[BF_LOAD:%.*]] = load volatile i32, i32* [[TMP0]], align 4 // LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, i32* [[TMP0]], align 4 // LE-NEXT: store volatile i32 [[INC]], i32* [[TMP0]], align 4 // LE-NEXT: ret void // @@ -1069,6 +1080,7 @@ // BE-NEXT: [[TMP0:%.*]] = bitcast %struct.st16* [[S:%.*]] to i32* // BE-NEXT: [[BF_LOAD:%.*]] = load volatile i32, i32* [[TMP0]], align 4 // BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, i32* [[TMP0]], align 4 // BE-NEXT: store volatile i32 [[INC]], i32* [[TMP0]], align 4 // BE-NEXT: ret void // @@ -1112,6 +1124,7 @@ // LE-NEXT: [[TMP1:%.*]] = bitcast i48* [[TMP0]] to i32* // LE-NEXT: [[BF_LOAD:%.*]] = load volatile i32, i32* [[TMP1]], align 4 // LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, i32* [[TMP1]], align 4 // LE-NEXT: store volatile i32 [[INC]], i32* [[TMP1]], align 4 // LE-NEXT: ret void // @@ -1121,6 +1134,7 @@ // BE-NEXT: [[TMP1:%.*]] = bitcast i48* [[TMP0]] to i32* // BE-NEXT: [[BF_LOAD:%.*]] = load volatile i32, i32* [[TMP1]], align 4 // BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, i32* [[TMP1]], align 4 // BE-NEXT: store volatile i32 [[INC]], i32* [[TMP1]], align 4 // BE-NEXT: ret void // @@ -1201,6 +1215,7 @@ // LE-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_ST17:%.*]], %struct.st17* [[S:%.*]], i32 0, i32 0, i32 4 // 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 // @@ -1209,6 +1224,7 @@ // BE-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_ST17:%.*]], %struct.st17* [[S:%.*]], i32 0, i32 0, i32 4 // 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 //