-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[Clang][ARM][Sema] Check validity of ldrexd/strexd builtin calls #164919
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Clang][ARM][Sema] Check validity of ldrexd/strexd builtin calls #164919
Conversation
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.
```
If possible, it might be better to remove
`__builtin_arm_ldrexd`/`__builtin_arm_strexd` in favor of the generic versions
which seem to already support double-word length. If this is preferred, I'd be
happy to close this pull-request and open a new one with the intrinsics
removed.
|
@llvm/pr-subscribers-backend-aarch64 @llvm/pr-subscribers-clang Author: Douglas (dgg5503) ChangesThis change enables validation checks against the following two ARM atomic builtins: Previously, no checks existed for these builtins, so under a release compiler, it would be possible to emit For example, the following would compile with errors: > type atomics.c
long long func(void) {
long long num = 0;
__builtin_arm_strex(42, &num);
return __builtin_arm_ldrex(&num);
}However, a similar program would compile without errors: > type atomics.c
long long func(void) {
long long num = 0;
__builtin_arm_strexd(42, &num);
return __builtin_arm_ldrexd(&num);
}With this change, we now have appropriate compile-time errors: If possible, it might be better to remove Full diff: https://github.com/llvm/llvm-project/pull/164919.diff 8 Files Affected:
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/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp
index 1c7c832d7edfa..20cfa09754384 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));
@@ -1013,8 +1023,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..1d7d85a5a7416 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 {{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}}
+ sum += __builtin_arm_ldrexd((unsigned long long *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}}
+ sum += __builtin_arm_ldrexd((float *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}}
+ sum += __builtin_arm_ldrexd((double *)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}}
+ res |= __builtin_arm_strexd(42, (unsigned long long *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}}
+ res |= __builtin_arm_strexd(2.71828f, (float *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}}
+ res |= __builtin_arm_strexd(3.14159, (double *)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-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);
|
|
@llvm/pr-subscribers-backend-arm Author: Douglas (dgg5503) ChangesThis change enables validation checks against the following two ARM atomic builtins: Previously, no checks existed for these builtins, so under a release compiler, it would be possible to emit For example, the following would compile with errors: > type atomics.c
long long func(void) {
long long num = 0;
__builtin_arm_strex(42, &num);
return __builtin_arm_ldrex(&num);
}However, a similar program would compile without errors: > type atomics.c
long long func(void) {
long long num = 0;
__builtin_arm_strexd(42, &num);
return __builtin_arm_ldrexd(&num);
}With this change, we now have appropriate compile-time errors: If possible, it might be better to remove Full diff: https://github.com/llvm/llvm-project/pull/164919.diff 8 Files Affected:
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/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp
index 1c7c832d7edfa..20cfa09754384 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));
@@ -1013,8 +1023,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..1d7d85a5a7416 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 {{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}}
+ sum += __builtin_arm_ldrexd((unsigned long long *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}}
+ sum += __builtin_arm_ldrexd((float *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}}
+ sum += __builtin_arm_ldrexd((double *)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}}
+ res |= __builtin_arm_strexd(42, (unsigned long long *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}}
+ res |= __builtin_arm_strexd(2.71828f, (float *)addr); // expected-error {{load and store exclusive builtins are not available on this architecture}}
+ res |= __builtin_arm_strexd(3.14159, (double *)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-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);
|
Guessing aarch64 doesn't have this problem? |
|
Hi @AZero13 , These builtin functions ( llvm-project/clang/include/clang/Basic/BuiltinsARM.def Lines 128 to 129 in 6a0f392
I do not see them listed in |
statham-arm
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly LGTM, with only one tiny error-reporting quibble.
|
|
||
| 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}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a shame that this case reuses the error message that claims no load/store exclusives are available. I think it might be better to make a separate error message that adds "8-byte" to the wording, and use that when your reduced Mask is zero but the original getARMLDREXMask() was not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @statham-arm
Thanks for the review! I've implemented a tweak to the diagnostic as suggested.
However, attempting to make the diagnostic "%select{|8-byte }0load and store exclusive builtins are not available on this architecture" results in the following error:
error: Diagnostics should not start with a capital letter; '8' is invalid
def err_atomic_exclusive_builtin_pointer_size_none : Error<
^
So I've opted for the word 'eight', is that acceptable? Maybe it could be 'double-word' if spelling out a number is too awkward.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, that's surely a bug in Tablegen!
I especially like the way that the complaint "Diagnostics should not start with a capital letter" starts with a capital letter 🙂
I'm happy with 'eight-byte'. It might not be worded exactly the same as the other messages, but it conveys the important information.
…m#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. ```
…m#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. ```
…m#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. ```
This change enables validation checks against the following two ARM atomic builtins:
Previously, no checks existed for these builtins, so under a release compiler, it would be possible to emit
ldrexd/strexdunder ARM targets which set the LDREX mask (returned viagetARMLDREXMask) to signify these as unsupported instructions.For example, the following would compile with errors:
However, a similar program would compile without errors:
With this change, we now have appropriate compile-time errors:
If possible, it might be better to remove
__builtin_arm_ldrexd/__builtin_arm_strexdin favor of the generic versions which seem to already support double-word length. If this is preferred, I'd be happy to close this pull-request and open a new one with the intrinsics removed.