Author: Douglas Date: 2025-10-27T08:03:33-07:00 New Revision: 6bf6babb30488df340337923573c562553128706
URL: https://github.com/llvm/llvm-project/commit/6bf6babb30488df340337923573c562553128706 DIFF: https://github.com/llvm/llvm-project/commit/6bf6babb30488df340337923573c562553128706.diff LOG: [Clang][ARM][Sema] Check validity of ldrexd/strexd builtin calls (#164919) This change enables validation checks against the following two ARM atomic builtins: ``` __builtin_arm_ldrexd __builtin_arm_strexd ``` Previously, no checks existed for these builtins, so under a release compiler, it would be possible to emit `ldrexd`/`strexd` under ARM targets which set the LDREX mask (returned via `getARMLDREXMask`) to signify these as unsupported instructions. For example, the following would compile with errors: ```c > type atomics.c long long func(void) { long long num = 0; __builtin_arm_strex(42, &num); return __builtin_arm_ldrex(&num); } ``` ``` > clang --target=armv7m-linux-gnueabi -S atomics.c -o - atomics.c:3:5: error: address argument to load or store exclusive builtin must be a pointer to 1,2 or 4 byte type ('volatile long long *' invalid) 3 | __builtin_arm_strex(42, &num); | ^ atomics.c:4:12: error: address argument to load or store exclusive builtin must be a pointer to 1,2 or 4 byte type ('const volatile long long *' invalid) 4 | return __builtin_arm_ldrex(&num); | ^ 2 errors generated. ``` However, a similar program would compile without errors: ```c > type atomics.c long long func(void) { long long num = 0; __builtin_arm_strexd(42, &num); return __builtin_arm_ldrexd(&num); } ``` ``` > clang --target=armv7m-linux-gnueabi -S atomics.c -o - ... strexd r1, r2, r3, [r0] ldrexd r0, r1, [r0] ... ``` With this change, we now have appropriate compile-time errors: ``` > clang --target=armv7m-linux-gnueabi -S atomics.c -o - atomics.c:3:5: error: load and store exclusive builtins are not available on this architecture 3 | __builtin_arm_strexd(42, &num); | ^ ~~~~ atomics.c:4:12: error: load and store exclusive builtins are not available on this architecture 4 | return __builtin_arm_ldrexd(&num); | ^ ~~~~ 2 errors generated. ``` Added: Modified: clang/include/clang/Basic/BuiltinsARM.def clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Sema/SemaARM.cpp clang/test/CodeGen/builtins-arm-exclusive.c clang/test/CodeGenCXX/builtins-arm-exclusive.cpp clang/test/Sema/builtins-arm-exclusive-124.c clang/test/Sema/builtins-arm-exclusive-4.c clang/test/Sema/builtins-arm-exclusive-none.c clang/test/Sema/builtins-arm-exclusive.c Removed: ################################################################################ diff --git a/clang/include/clang/Basic/BuiltinsARM.def b/clang/include/clang/Basic/BuiltinsARM.def index 2592e25e95c37..cdcc0d0d65e20 100644 --- a/clang/include/clang/Basic/BuiltinsARM.def +++ b/clang/include/clang/Basic/BuiltinsARM.def @@ -125,8 +125,8 @@ BUILTIN(__builtin_arm_cls, "UiZUi", "nc") BUILTIN(__builtin_arm_cls64, "UiWUi", "nc") // Store and load exclusive -BUILTIN(__builtin_arm_ldrexd, "LLUiv*", "") -BUILTIN(__builtin_arm_strexd, "iLLUiv*", "") +BUILTIN(__builtin_arm_ldrexd, "v.", "t") +BUILTIN(__builtin_arm_strexd, "i.", "t") BUILTIN(__builtin_arm_ldrex, "v.", "t") BUILTIN(__builtin_arm_ldaex, "v.", "t") diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6087893874e8b..4e369be0bbb92 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9405,7 +9405,7 @@ def err_atomic_exclusive_builtin_pointer_size : Error< "%select{|,| or }7%select{|8}8" " byte type (%0 invalid)">; def err_atomic_exclusive_builtin_pointer_size_none : Error< - "load and store exclusive builtins are not available on this architecture">; + "%select{|eight-byte }0load and store exclusive builtins are not available on this architecture">; def err_atomic_builtin_ext_int_size : Error< "atomic memory operand must have a power-of-two size">; def err_atomic_builtin_bit_int_prohibit : Error< diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp index 1c7c832d7edfa..ab37394cd5f98 100644 --- a/clang/lib/Sema/SemaARM.cpp +++ b/clang/lib/Sema/SemaARM.cpp @@ -850,8 +850,10 @@ bool SemaARM::CheckARMBuiltinExclusiveCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall) { assert((BuiltinID == ARM::BI__builtin_arm_ldrex || + BuiltinID == ARM::BI__builtin_arm_ldrexd || BuiltinID == ARM::BI__builtin_arm_ldaex || BuiltinID == ARM::BI__builtin_arm_strex || + BuiltinID == ARM::BI__builtin_arm_strexd || BuiltinID == ARM::BI__builtin_arm_stlex || BuiltinID == AArch64::BI__builtin_arm_ldrex || BuiltinID == AArch64::BI__builtin_arm_ldaex || @@ -859,9 +861,12 @@ bool SemaARM::CheckARMBuiltinExclusiveCall(const TargetInfo &TI, BuiltinID == AArch64::BI__builtin_arm_stlex) && "unexpected ARM builtin"); bool IsLdrex = BuiltinID == ARM::BI__builtin_arm_ldrex || + BuiltinID == ARM::BI__builtin_arm_ldrexd || BuiltinID == ARM::BI__builtin_arm_ldaex || BuiltinID == AArch64::BI__builtin_arm_ldrex || BuiltinID == AArch64::BI__builtin_arm_ldaex; + bool IsDoubleWord = BuiltinID == ARM::BI__builtin_arm_ldrexd || + BuiltinID == ARM::BI__builtin_arm_strexd; ASTContext &Context = getASTContext(); DeclRefExpr *DRE = @@ -928,6 +933,11 @@ bool SemaARM::CheckARMBuiltinExclusiveCall(const TargetInfo &TI, if (!TI.getTriple().isAArch64()) { unsigned Mask = TI.getARMLDREXMask(); unsigned Bits = Context.getTypeSize(ValType); + if (IsDoubleWord) { + // Explicit request for ldrexd/strexd means only double word sizes + // supported if the target supports them. + Mask &= TargetInfo::ARM_LDREX_D; + } bool Supported = (llvm::isPowerOf2_64(Bits)) && Bits >= 8 && (Mask & (Bits / 8)); @@ -968,8 +978,11 @@ bool SemaARM::CheckARMBuiltinExclusiveCall(const TargetInfo &TI, } } } else { + bool EmitDoubleWordDiagnostic = + IsDoubleWord && !Mask && TI.getARMLDREXMask(); Diag(DRE->getBeginLoc(), diag::err_atomic_exclusive_builtin_pointer_size_none) + << (EmitDoubleWordDiagnostic ? 1 : 0) << PointerArg->getSourceRange(); } } @@ -1013,8 +1026,10 @@ bool SemaARM::CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall) { if (BuiltinID == ARM::BI__builtin_arm_ldrex || + BuiltinID == ARM::BI__builtin_arm_ldrexd || BuiltinID == ARM::BI__builtin_arm_ldaex || BuiltinID == ARM::BI__builtin_arm_strex || + BuiltinID == ARM::BI__builtin_arm_strexd || BuiltinID == ARM::BI__builtin_arm_stlex) { return CheckARMBuiltinExclusiveCall(TI, BuiltinID, TheCall); } diff --git a/clang/test/CodeGen/builtins-arm-exclusive.c b/clang/test/CodeGen/builtins-arm-exclusive.c index d2aaf26502a3d..f27dcfc81f34b 100644 --- a/clang/test/CodeGen/builtins-arm-exclusive.c +++ b/clang/test/CodeGen/builtins-arm-exclusive.c @@ -312,3 +312,49 @@ int test_stlex_128(__int128 *addr, __int128 val) { } #endif + +#ifdef __arm__ +// ARM exclusive atomic builtins + +int test_ldrexd(char *addr, long long *addr64, float *addrfloat) { +// CHECK-LABEL: @test_ldrexd + int sum = 0; + sum += __builtin_arm_ldrexd((long long *)addr); +// CHECK: call { i32, i32 } @llvm.arm.ldrexd(ptr %addr) + + sum += __builtin_arm_ldrexd(addr64); +// CHECK: call { i32, i32 } @llvm.arm.ldrexd(ptr %addr64) + + sum += __builtin_arm_ldrexd((double *)addr); +// CHECK: [[STRUCTRES:%.*]] = call { i32, i32 } @llvm.arm.ldrexd(ptr %addr) +// CHECK: [[RESHI:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 1 +// CHECK: [[RESLO:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 0 +// CHECK: [[RESHI64:%.*]] = zext i32 [[RESHI]] to i64 +// CHECK: [[RESLO64:%.*]] = zext i32 [[RESLO]] to i64 +// CHECK: [[RESHIHI:%.*]] = shl nuw i64 [[RESHI64]], 32 +// CHECK: [[INTRES:%.*]] = or i64 [[RESHIHI]], [[RESLO64]] + + return sum; +} + +int test_strexd(char *addr) { +// CHECK-LABEL: @test_strexd + int res = 0; + res |= __builtin_arm_strexd(42, (long long *)addr); +// CHECK: store i64 42, ptr [[TMP:%.*]], align 8 +// CHECK: [[LOHI:%.*]] = load { i32, i32 }, ptr [[TMP]] +// CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0 +// CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1 +// CHECK: call i32 @llvm.arm.strexd(i32 [[LO]], i32 [[HI]], ptr %addr) + + res |= __builtin_arm_strexd(3.14159, (double *)addr); +// CHECK: store double 3.141590e+00, ptr [[TMP:%.*]], align 8 +// CHECK: [[LOHI:%.*]] = load { i32, i32 }, ptr [[TMP]] +// CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0 +// CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1 +// CHECK: call i32 @llvm.arm.strexd(i32 [[LO]], i32 [[HI]], ptr %addr) + + return res; +} + +#endif diff --git a/clang/test/CodeGenCXX/builtins-arm-exclusive.cpp b/clang/test/CodeGenCXX/builtins-arm-exclusive.cpp index d30631f6ad3bd..ca271935a90f1 100644 --- a/clang/test/CodeGenCXX/builtins-arm-exclusive.cpp +++ b/clang/test/CodeGenCXX/builtins-arm-exclusive.cpp @@ -22,3 +22,35 @@ void test_ldrex() { void tset_strex() { __builtin_arm_strex(true, &b); } + +#ifdef __arm__ +// ARM exclusive atomic builtins + +long long c; + +// CHECK-LABEL: @_Z11test_ldrexdv() +// CHECK: [[STRUCTRES:%.*]] = call { i32, i32 } @llvm.arm.ldrexd(ptr @c) +// CHECK: [[RESHI:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 1 +// CHECK: [[RESLO:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 0 +// CHECK: [[RESHI64:%.*]] = zext i32 [[RESHI]] to i64 +// CHECK: [[RESLO64:%.*]] = zext i32 [[RESLO]] to i64 +// CHECK: [[RESHIHI:%.*]] = shl nuw i64 [[RESHI64]], 32 +// CHECK: [[INTRES:%.*]] = or i64 [[RESHIHI]], [[RESLO64]] +// CHECK: store i64 [[INTRES]], ptr @c, align 8 + +void test_ldrexd() { + c = __builtin_arm_ldrexd(&c); +} + +// CHECK-LABEL: @_Z11tset_strexdv() +// CHECK: store i64 42, ptr [[TMP:%.*]], align 8 +// CHECK: [[LOHI:%.*]] = load { i32, i32 }, ptr [[TMP]] +// CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0 +// CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1 +// CHECK: %{{.*}} = call i32 @llvm.arm.strexd(i32 [[LO]], i32 [[HI]], ptr @c) + +void tset_strexd() { + __builtin_arm_strexd(42, &c); +} + +#endif diff --git a/clang/test/Sema/builtins-arm-exclusive-124.c b/clang/test/Sema/builtins-arm-exclusive-124.c index 013ae3f41ee7f..b35ac181f0887 100644 --- a/clang/test/Sema/builtins-arm-exclusive-124.c +++ b/clang/test/Sema/builtins-arm-exclusive-124.c @@ -24,3 +24,27 @@ int test_strex(char *addr) { res |= __builtin_arm_strex(42, (long long *)addr); // expected-error {{address argument to load or store exclusive builtin must be a pointer to 1,2 or 4 byte type}} return res; } + +int test_ldrexd(char *addr) { + int sum = 0; + sum += __builtin_arm_ldrexd(addr); // expected-error {{eight-byte load and store exclusive builtins are not available on this architecture}} + sum += __builtin_arm_ldrexd((short *)addr); // expected-error {{eight-byte load and store exclusive builtins are not available on this architecture}} + sum += __builtin_arm_ldrexd((int *)addr); // expected-error {{eight-byte load and store exclusive builtins are not available on this architecture}} + sum += __builtin_arm_ldrexd((long long *)addr); // expected-error {{eight-byte load and store exclusive builtins are not available on this architecture}} + sum += __builtin_arm_ldrexd((unsigned long long *)addr); // expected-error {{eight-byte load and store exclusive builtins are not available on this architecture}} + sum += __builtin_arm_ldrexd((float *)addr); // expected-error {{eight-byte load and store exclusive builtins are not available on this architecture}} + sum += __builtin_arm_ldrexd((double *)addr); // expected-error {{eight-byte load and store exclusive builtins are not available on this architecture}} + return sum; +} + +int test_strexd(char *addr) { + int res = 0; + res |= __builtin_arm_strexd(4, addr); // expected-error {{eight-byte load and store exclusive builtins are not available on this architecture}} + res |= __builtin_arm_strexd(42, (short *)addr); // expected-error {{eight-byte load and store exclusive builtins are not available on this architecture}} + res |= __builtin_arm_strexd(42, (int *)addr); // expected-error {{eight-byte load and store exclusive builtins are not available on this architecture}} + res |= __builtin_arm_strexd(42, (long long *)addr); // expected-error {{eight-byte load and store exclusive builtins are not available on this architecture}} + res |= __builtin_arm_strexd(42, (unsigned long long *)addr); // expected-error {{eight-byte load and store exclusive builtins are not available on this architecture}} + res |= __builtin_arm_strexd(2.71828f, (float *)addr); // expected-error {{eight-byte load and store exclusive builtins are not available on this architecture}} + res |= __builtin_arm_strexd(3.14159, (double *)addr); // expected-error {{eight-byte load and store exclusive builtins are not available on this architecture}} + return res; +} diff --git a/clang/test/Sema/builtins-arm-exclusive-4.c b/clang/test/Sema/builtins-arm-exclusive-4.c index 68f01f5416616..0d31ce6f03769 100644 --- a/clang/test/Sema/builtins-arm-exclusive-4.c +++ b/clang/test/Sema/builtins-arm-exclusive-4.c @@ -20,3 +20,21 @@ int test_strex(char *addr) { res |= __builtin_arm_strex(42, (long long *)addr); // expected-error {{address argument to load or store exclusive builtin must be a pointer to 4 byte type}} return res; } + +int test_ldrexd(char *addr) { + int sum = 0; + sum += __builtin_arm_ldrexd(addr); // expected-error {{load and store exclusive builtins are not available on this architecture}} + sum += __builtin_arm_ldrexd((short *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}} + sum += __builtin_arm_ldrexd((int *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}} + sum += __builtin_arm_ldrexd((long long *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}} + return sum; +} + +int test_strexd(char *addr) { + int res = 0; + res |= __builtin_arm_strexd(4, addr); // expected-error {{load and store exclusive builtins are not available on this architecture}} + res |= __builtin_arm_strexd(42, (short *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}} + res |= __builtin_arm_strexd(42, (int *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}} + res |= __builtin_arm_strexd(42, (long long *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}} + return res; +} diff --git a/clang/test/Sema/builtins-arm-exclusive-none.c b/clang/test/Sema/builtins-arm-exclusive-none.c index 76d327f0111c3..2ef910dd99aaf 100644 --- a/clang/test/Sema/builtins-arm-exclusive-none.c +++ b/clang/test/Sema/builtins-arm-exclusive-none.c @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -triple armv6m -fsyntax-only -verify %s // Armv6-M does not support exclusive loads/stores at all, so all uses of -// __builtin_arm_ldrex and __builtin_arm_strex is forbidden. +// __builtin_arm_ldrex[d] and __builtin_arm_strex[d] is forbidden. int test_ldrex(char *addr) { int sum = 0; @@ -20,3 +20,21 @@ int test_strex(char *addr) { res |= __builtin_arm_strex(42, (long long *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}} return res; } + +int test_ldrexd(char *addr) { + int sum = 0; + sum += __builtin_arm_ldrexd(addr); // expected-error {{load and store exclusive builtins are not available on this architecture}} + sum += __builtin_arm_ldrexd((short *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}} + sum += __builtin_arm_ldrexd((int *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}} + sum += __builtin_arm_ldrexd((long long *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}} + return sum; +} + +int test_strexd(char *addr) { + int res = 0; + res |= __builtin_arm_strexd(4, addr); // expected-error {{load and store exclusive builtins are not available on this architecture}} + res |= __builtin_arm_strexd(42, (short *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}} + res |= __builtin_arm_strexd(42, (int *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}} + res |= __builtin_arm_strexd(42, (long long *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}} + return res; +} diff --git a/clang/test/Sema/builtins-arm-exclusive.c b/clang/test/Sema/builtins-arm-exclusive.c index 49aea1506f25c..dbb3de51be419 100644 --- a/clang/test/Sema/builtins-arm-exclusive.c +++ b/clang/test/Sema/builtins-arm-exclusive.c @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -triple armv7 -fsyntax-only -verify %s -// General tests of __builtin_arm_ldrex and __builtin_arm_strex error checking. +// General tests of __builtin_arm_ldrex[d] and __builtin_arm_strex[d] error checking. // // This test is compiled for Armv7-A, which provides exclusive load/store // instructions for 1-, 2-, 4- and 8-byte quantities. Other Arm architecture @@ -63,6 +63,57 @@ int test_strex(char *addr) { return res; } +int test_ldrexd(char *addr) { + int sum = 0; + sum += __builtin_arm_ldrexd(addr); // expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + sum += __builtin_arm_ldrexd((short *)addr); // expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + sum += __builtin_arm_ldrexd((int *)addr); // expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + sum += __builtin_arm_ldrexd((long long *)addr); + sum += __builtin_arm_ldrexd((float *)addr); // expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + sum += __builtin_arm_ldrexd((double *)addr); + sum += *__builtin_arm_ldrexd((int **)addr); // expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + sum += __builtin_arm_ldrexd((struct Simple **)addr)->a; // expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + sum += __builtin_arm_ldrexd((volatile char *)addr); // expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + sum += __builtin_arm_ldrexd((const volatile char *)addr); // expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + + // In principle this might be valid, but stick to ints and floats for scalar + // types at the moment. + sum += __builtin_arm_ldrexd((struct Simple *)addr).a; // expected-error {{address argument to atomic builtin must be a pointer to}} + + sum += __builtin_arm_ldrexd((__int128 *)addr); // expected-error {{__int128 is not supported on this target}} expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + + __builtin_arm_ldrexd(); // expected-error {{too few arguments to function call}} + __builtin_arm_ldrexd(1, 2); // expected-error {{too many arguments to function call}} + return sum; +} + +int test_strexd(char *addr) { + int res = 0; + struct Simple var = {0}; + res |= __builtin_arm_strexd(4, addr); // expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + res |= __builtin_arm_strexd(42, (short *)addr); // expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + res |= __builtin_arm_strexd(42, (int *)addr); // expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + res |= __builtin_arm_strexd(42, (long long *)addr); + res |= __builtin_arm_strexd(2.71828f, (float *)addr); // expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + res |= __builtin_arm_strexd(3.14159, (double *)addr); + res |= __builtin_arm_strexd(&var, (struct Simple **)addr); // expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + + res |= __builtin_arm_strexd(42, (volatile char *)addr); // expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + res |= __builtin_arm_strexd(42, (char *const)addr); // expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + res |= __builtin_arm_strexd(42, (const char *)addr); // expected-warning {{passing 'const char *' to parameter of type 'volatile char *' discards qualifiers}} expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + + + res |= __builtin_arm_strexd(var, (struct Simple *)addr); // expected-error {{address argument to atomic builtin must be a pointer to}} + res |= __builtin_arm_strexd(var, (struct Simple **)addr); // expected-error {{passing 'struct Simple' to parameter of incompatible type 'struct Simple *'}} expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + res |= __builtin_arm_strexd(&var, (struct Simple **)addr).a; // expected-error {{is not a structure or union}} expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + + res |= __builtin_arm_strexd(1, (__int128 *)addr); // expected-error {{__int128 is not supported on this target}} expected-error {{address argument to load or store exclusive builtin must be a pointer to 8 byte type}} + + __builtin_arm_strexd(1); // expected-error {{too few arguments to function call}} + __builtin_arm_strexd(1, 2, 3); // expected-error {{too many arguments to function call}} + return res; +} + int test_ldaex(char *addr) { int sum = 0; sum += __builtin_arm_ldaex(addr); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
