Skip to content

Commit d083adb

Browse files
jtmott-intelErich Keane
authored andcommitted
Prohibit use of _ExtInt in atomic intrinsic
The _ExtInt type allows custom width integers, but the atomic memory access's operand must have a power-of-two size. _ExtInts with non-power-of-two size should not be allowed for atomic intrinsic. Before this change: $ cat test.c typedef unsigned _ExtInt(42) dtype; void verify_binary_op_nand(dtype* pval1, dtype val2) { __sync_nand_and_fetch(pval1, val2); } $ clang test.c clang-11: /home/ubuntu/llvm_workspace/llvm/clang/lib/CodeGen/CGBuiltin.cpp:117: llvm::Value* EmitToInt(clang::CodeGen::CodeGenFunction&, llvm::Value*, clang::QualType, llvm::IntegerType*): Assertion `V->getType() == IntType' failed. PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace, preprocessed source, and associated run script. After this change: $ clang test.c test.c:3:30: error: Atomic memory operand must have a power-of-two size { __sync_nand_and_fetch(pval1, val2); } ^ List of the atomic intrinsics that have this problem: __sync_fetch_and_add __sync_fetch_and_sub __sync_fetch_and_or __sync_fetch_and_and __sync_fetch_and_xor __sync_fetch_and_nand __sync_nand_and_fetch __sync_and_and_fetch __sync_add_and_fetch __sync_sub_and_fetch __sync_or_and_fetch __sync_xor_and_fetch __sync_fetch_and_min __sync_fetch_and_max __sync_fetch_and_umin __sync_fetch_and_umax __sync_val_compare_and_swap __sync_bool_compare_and_swap Differential Revision: https://reviews.llvm.org/D83340
1 parent 0cbdd2a commit d083adb

File tree

3 files changed

+47
-0
lines changed

3 files changed

+47
-0
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7939,6 +7939,8 @@ def err_atomic_builtin_pointer_size : Error<
79397939
def err_atomic_exclusive_builtin_pointer_size : Error<
79407940
"address argument to load or store exclusive builtin must be a pointer to"
79417941
" 1,2,4 or 8 byte type (%0 invalid)">;
7942+
def err_atomic_builtin_ext_int_size : Error<
7943+
"Atomic memory operand must have a power-of-two size">;
79427944
def err_atomic_op_needs_atomic : Error<
79437945
"address argument to atomic operation must be a pointer to _Atomic "
79447946
"type (%0 invalid)">;

clang/lib/Sema/SemaChecking.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5349,6 +5349,15 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
53495349
// gracefully.
53505350
TheCall->setType(ResultType);
53515351

5352+
// Prohibit use of _ExtInt with atomic builtins.
5353+
// The arguments would have already been converted to the first argument's
5354+
// type, so only need to check the first argument.
5355+
const auto *ExtIntValType = ValType->getAs<ExtIntType>();
5356+
if (ExtIntValType && !llvm::isPowerOf2_64(ExtIntValType->getNumBits())) {
5357+
Diag(FirstArg->getExprLoc(), diag::err_atomic_builtin_ext_int_size);
5358+
return ExprError();
5359+
}
5360+
53525361
return TheCallResult;
53535362
}
53545363

clang/test/Sema/builtins.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,42 @@ void test21(const int *ptr) {
281281
__atomic_fetch_add(ptr, 1, 0); // expected-error {{address argument to atomic operation must be a pointer to non-const type ('const int *' invalid)}}
282282
}
283283

284+
void test_ei_i42i(_ExtInt(42) *ptr, int value) {
285+
__sync_fetch_and_add(ptr, value); // expected-error {{Atomic memory operand must have a power-of-two size}}
286+
// expected-warning@+1 {{the semantics of this intrinsic changed with GCC version 4.4 - the newer semantics are provided here}}
287+
__sync_nand_and_fetch(ptr, value); // expected-error {{Atomic memory operand must have a power-of-two size}}
288+
}
289+
290+
void test_ei_i64i(_ExtInt(64) *ptr, int value) {
291+
__sync_fetch_and_add(ptr, value); // expect success
292+
// expected-warning@+1 {{the semantics of this intrinsic changed with GCC version 4.4 - the newer semantics are provided here}}
293+
__sync_nand_and_fetch(ptr, value); // expect success
294+
}
295+
296+
void test_ei_ii42(int *ptr, _ExtInt(42) value) {
297+
__sync_fetch_and_add(ptr, value); // expect success
298+
// expected-warning@+1 {{the semantics of this intrinsic changed with GCC version 4.4 - the newer semantics are provided here}}
299+
__sync_nand_and_fetch(ptr, value); // expect success
300+
}
301+
302+
void test_ei_ii64(int *ptr, _ExtInt(64) value) {
303+
__sync_fetch_and_add(ptr, value); // expect success
304+
// expected-warning@+1 {{the semantics of this intrinsic changed with GCC version 4.4 - the newer semantics are provided here}}
305+
__sync_nand_and_fetch(ptr, value); // expect success
306+
}
307+
308+
void test_ei_i42i42(_ExtInt(42) *ptr, _ExtInt(42) value) {
309+
__sync_fetch_and_add(ptr, value); // expected-error {{Atomic memory operand must have a power-of-two size}}
310+
// expected-warning@+1 {{the semantics of this intrinsic changed with GCC version 4.4 - the newer semantics are provided here}}
311+
__sync_nand_and_fetch(ptr, value); // expected-error {{Atomic memory operand must have a power-of-two size}}
312+
}
313+
314+
void test_ei_i64i64(_ExtInt(64) *ptr, _ExtInt(64) value) {
315+
__sync_fetch_and_add(ptr, value); // expect success
316+
// expected-warning@+1 {{the semantics of this intrinsic changed with GCC version 4.4 - the newer semantics are provided here}}
317+
__sync_nand_and_fetch(ptr, value); // expect success
318+
}
319+
284320
void test22(void) {
285321
(void)__builtin_signbit(); // expected-error{{too few arguments to function call, expected 1, have 0}}
286322
(void)__builtin_signbit(1.0, 2.0, 3.0); // expected-error{{too many arguments to function call, expected 1, have 3}}

0 commit comments

Comments
 (0)