diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def index bb6975c49462..72843f1fb6a6 100644 --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -541,6 +541,12 @@ BUILTIN(__sync_fetch_and_xor_4, "iiD*i.", "tn") BUILTIN(__sync_fetch_and_xor_8, "LLiLLiD*LLi.", "tn") BUILTIN(__sync_fetch_and_xor_16, "LLLiLLLiD*LLLi.", "tn") +BUILTIN(__sync_fetch_and_nand, "v.", "t") +BUILTIN(__sync_fetch_and_nand_1, "ccD*c.", "tn") +BUILTIN(__sync_fetch_and_nand_2, "ssD*s.", "tn") +BUILTIN(__sync_fetch_and_nand_4, "iiD*i.", "tn") +BUILTIN(__sync_fetch_and_nand_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_fetch_and_nand_16, "LLLiLLLiD*LLLi.", "tn") BUILTIN(__sync_add_and_fetch, "v.", "t") BUILTIN(__sync_add_and_fetch_1, "ccD*c.", "tn") @@ -577,6 +583,13 @@ BUILTIN(__sync_xor_and_fetch_4, "iiD*i.", "tn") BUILTIN(__sync_xor_and_fetch_8, "LLiLLiD*LLi.", "tn") BUILTIN(__sync_xor_and_fetch_16, "LLLiLLLiD*LLLi.", "tn") +BUILTIN(__sync_nand_and_fetch, "v.", "t") +BUILTIN(__sync_nand_and_fetch_1, "ccD*c.", "tn") +BUILTIN(__sync_nand_and_fetch_2, "ssD*s.", "tn") +BUILTIN(__sync_nand_and_fetch_4, "iiD*i.", "tn") +BUILTIN(__sync_nand_and_fetch_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_nand_and_fetch_16, "LLLiLLLiD*LLLi.", "tn") + BUILTIN(__sync_bool_compare_and_swap, "v.", "t") BUILTIN(__sync_bool_compare_and_swap_1, "bcD*cc.", "tn") BUILTIN(__sync_bool_compare_and_swap_2, "bsD*ss.", "tn") diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 06a22045ea8a..c811db33bc89 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6898,6 +6898,11 @@ def warn_duplicate_attribute : Warning< "attribute %0 is already applied with different parameters">, InGroup; +def warn_sync_fetch_and_nand_semantics_change : Warning< + "the semantics of this intrinsic changed with GCC " + "version 4.4 - the newer semantics are provided here">, + InGroup>; + // Type def ext_invalid_sign_spec : Extension<"'%0' cannot be signed or unsigned">; def warn_receiver_forward_class : Warning< diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 9238aae88cd6..f59cbaa4b8ad 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -113,7 +113,8 @@ static RValue EmitBinaryAtomic(CodeGenFunction &CGF, static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF, llvm::AtomicRMWInst::BinOp Kind, const CallExpr *E, - Instruction::BinaryOps Op) { + Instruction::BinaryOps Op, + bool Invert = false) { QualType T = E->getType(); assert(E->getArg(0)->getType()->isPointerType()); assert(CGF.getContext().hasSameUnqualifiedType(T, @@ -138,6 +139,9 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF, CGF.Builder.CreateAtomicRMW(Kind, Args[0], Args[1], llvm::SequentiallyConsistent); Result = CGF.Builder.CreateBinOp(Op, Result, Args[1]); + if (Invert) + Result = CGF.Builder.CreateBinOp(llvm::Instruction::Xor, Result, + llvm::ConstantInt::get(IntType, -1)); Result = EmitFromInt(CGF, Result, T, ValueType); return RValue::get(Result); } @@ -879,11 +883,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_fetch_and_or: case Builtin::BI__sync_fetch_and_and: case Builtin::BI__sync_fetch_and_xor: + case Builtin::BI__sync_fetch_and_nand: case Builtin::BI__sync_add_and_fetch: case Builtin::BI__sync_sub_and_fetch: case Builtin::BI__sync_and_and_fetch: case Builtin::BI__sync_or_and_fetch: case Builtin::BI__sync_xor_and_fetch: + case Builtin::BI__sync_nand_and_fetch: case Builtin::BI__sync_val_compare_and_swap: case Builtin::BI__sync_bool_compare_and_swap: case Builtin::BI__sync_lock_test_and_set: @@ -920,6 +926,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_fetch_and_xor_8: case Builtin::BI__sync_fetch_and_xor_16: return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Xor, E); + case Builtin::BI__sync_fetch_and_nand_1: + case Builtin::BI__sync_fetch_and_nand_2: + case Builtin::BI__sync_fetch_and_nand_4: + case Builtin::BI__sync_fetch_and_nand_8: + case Builtin::BI__sync_fetch_and_nand_16: + return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Nand, E); // Clang extensions: not overloaded yet. case Builtin::BI__sync_fetch_and_min: @@ -966,6 +978,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_xor_and_fetch_16: return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::Xor, E, llvm::Instruction::Xor); + case Builtin::BI__sync_nand_and_fetch_1: + case Builtin::BI__sync_nand_and_fetch_2: + case Builtin::BI__sync_nand_and_fetch_4: + case Builtin::BI__sync_nand_and_fetch_8: + case Builtin::BI__sync_nand_and_fetch_16: + return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::Nand, E, + llvm::Instruction::And, true); case Builtin::BI__sync_val_compare_and_swap_1: case Builtin::BI__sync_val_compare_and_swap_2: diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index b4f90d3b4f60..a856c98bf052 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -273,6 +273,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__sync_fetch_and_xor_4: case Builtin::BI__sync_fetch_and_xor_8: case Builtin::BI__sync_fetch_and_xor_16: + case Builtin::BI__sync_fetch_and_nand: + case Builtin::BI__sync_fetch_and_nand_1: + case Builtin::BI__sync_fetch_and_nand_2: + case Builtin::BI__sync_fetch_and_nand_4: + case Builtin::BI__sync_fetch_and_nand_8: + case Builtin::BI__sync_fetch_and_nand_16: case Builtin::BI__sync_add_and_fetch: case Builtin::BI__sync_add_and_fetch_1: case Builtin::BI__sync_add_and_fetch_2: @@ -303,6 +309,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__sync_xor_and_fetch_4: case Builtin::BI__sync_xor_and_fetch_8: case Builtin::BI__sync_xor_and_fetch_16: + case Builtin::BI__sync_nand_and_fetch: + case Builtin::BI__sync_nand_and_fetch_1: + case Builtin::BI__sync_nand_and_fetch_2: + case Builtin::BI__sync_nand_and_fetch_4: + case Builtin::BI__sync_nand_and_fetch_8: + case Builtin::BI__sync_nand_and_fetch_16: case Builtin::BI__sync_val_compare_and_swap: case Builtin::BI__sync_val_compare_and_swap_1: case Builtin::BI__sync_val_compare_and_swap_2: @@ -1518,12 +1530,14 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { BUILTIN_ROW(__sync_fetch_and_or), BUILTIN_ROW(__sync_fetch_and_and), BUILTIN_ROW(__sync_fetch_and_xor), + BUILTIN_ROW(__sync_fetch_and_nand), BUILTIN_ROW(__sync_add_and_fetch), BUILTIN_ROW(__sync_sub_and_fetch), BUILTIN_ROW(__sync_and_and_fetch), BUILTIN_ROW(__sync_or_and_fetch), BUILTIN_ROW(__sync_xor_and_fetch), + BUILTIN_ROW(__sync_nand_and_fetch), BUILTIN_ROW(__sync_val_compare_and_swap), BUILTIN_ROW(__sync_bool_compare_and_swap), @@ -1553,6 +1567,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { // as the number of fixed args. unsigned BuiltinID = FDecl->getBuiltinID(); unsigned BuiltinIndex, NumFixed = 1; + bool WarnAboutSemanticsChange = false; switch (BuiltinID) { default: llvm_unreachable("Unknown overloaded atomic builtin!"); case Builtin::BI__sync_fetch_and_add: @@ -1600,13 +1615,23 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { BuiltinIndex = 4; break; + case Builtin::BI__sync_fetch_and_nand: + case Builtin::BI__sync_fetch_and_nand_1: + case Builtin::BI__sync_fetch_and_nand_2: + case Builtin::BI__sync_fetch_and_nand_4: + case Builtin::BI__sync_fetch_and_nand_8: + case Builtin::BI__sync_fetch_and_nand_16: + BuiltinIndex = 5; + WarnAboutSemanticsChange = true; + break; + case Builtin::BI__sync_add_and_fetch: case Builtin::BI__sync_add_and_fetch_1: case Builtin::BI__sync_add_and_fetch_2: case Builtin::BI__sync_add_and_fetch_4: case Builtin::BI__sync_add_and_fetch_8: case Builtin::BI__sync_add_and_fetch_16: - BuiltinIndex = 5; + BuiltinIndex = 6; break; case Builtin::BI__sync_sub_and_fetch: @@ -1615,7 +1640,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_sub_and_fetch_4: case Builtin::BI__sync_sub_and_fetch_8: case Builtin::BI__sync_sub_and_fetch_16: - BuiltinIndex = 6; + BuiltinIndex = 7; break; case Builtin::BI__sync_and_and_fetch: @@ -1624,7 +1649,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_and_and_fetch_4: case Builtin::BI__sync_and_and_fetch_8: case Builtin::BI__sync_and_and_fetch_16: - BuiltinIndex = 7; + BuiltinIndex = 8; break; case Builtin::BI__sync_or_and_fetch: @@ -1633,7 +1658,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_or_and_fetch_4: case Builtin::BI__sync_or_and_fetch_8: case Builtin::BI__sync_or_and_fetch_16: - BuiltinIndex = 8; + BuiltinIndex = 9; break; case Builtin::BI__sync_xor_and_fetch: @@ -1642,7 +1667,17 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_xor_and_fetch_4: case Builtin::BI__sync_xor_and_fetch_8: case Builtin::BI__sync_xor_and_fetch_16: - BuiltinIndex = 9; + BuiltinIndex = 10; + break; + + case Builtin::BI__sync_nand_and_fetch: + case Builtin::BI__sync_nand_and_fetch_1: + case Builtin::BI__sync_nand_and_fetch_2: + case Builtin::BI__sync_nand_and_fetch_4: + case Builtin::BI__sync_nand_and_fetch_8: + case Builtin::BI__sync_nand_and_fetch_16: + BuiltinIndex = 11; + WarnAboutSemanticsChange = true; break; case Builtin::BI__sync_val_compare_and_swap: @@ -1651,7 +1686,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_val_compare_and_swap_4: case Builtin::BI__sync_val_compare_and_swap_8: case Builtin::BI__sync_val_compare_and_swap_16: - BuiltinIndex = 10; + BuiltinIndex = 12; NumFixed = 2; break; @@ -1661,7 +1696,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_bool_compare_and_swap_4: case Builtin::BI__sync_bool_compare_and_swap_8: case Builtin::BI__sync_bool_compare_and_swap_16: - BuiltinIndex = 11; + BuiltinIndex = 13; NumFixed = 2; ResultType = Context.BoolTy; break; @@ -1672,7 +1707,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_lock_test_and_set_4: case Builtin::BI__sync_lock_test_and_set_8: case Builtin::BI__sync_lock_test_and_set_16: - BuiltinIndex = 12; + BuiltinIndex = 14; break; case Builtin::BI__sync_lock_release: @@ -1681,7 +1716,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_lock_release_4: case Builtin::BI__sync_lock_release_8: case Builtin::BI__sync_lock_release_16: - BuiltinIndex = 13; + BuiltinIndex = 15; NumFixed = 0; ResultType = Context.VoidTy; break; @@ -1692,7 +1727,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_swap_4: case Builtin::BI__sync_swap_8: case Builtin::BI__sync_swap_16: - BuiltinIndex = 14; + BuiltinIndex = 16; break; } @@ -1705,6 +1740,11 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { return ExprError(); } + if (WarnAboutSemanticsChange) { + Diag(TheCall->getLocEnd(), diag::warn_sync_fetch_and_nand_semantics_change) + << TheCall->getCallee()->getSourceRange(); + } + // Get the decl for the concrete builtin from this, we can tell what the // concrete integer type we should convert to is. unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex]; diff --git a/clang/test/CodeGen/Atomics.c b/clang/test/CodeGen/Atomics.c index 684f36d40440..f957883575de 100644 --- a/clang/test/CodeGen/Atomics.c +++ b/clang/test/CodeGen/Atomics.c @@ -49,6 +49,15 @@ void test_op_ignore (void) // CHECK-LABEL: define void @test_op_ignore (void) __sync_fetch_and_xor (&sll, 1); // CHECK: atomicrmw xor i64 (void) __sync_fetch_and_xor (&ull, 1); // CHECK: atomicrmw xor i64 + (void) __sync_fetch_and_nand (&sc, 1); // CHECK: atomicrmw nand i8 + (void) __sync_fetch_and_nand (&uc, 1); // CHECK: atomicrmw nand i8 + (void) __sync_fetch_and_nand (&ss, 1); // CHECK: atomicrmw nand i16 + (void) __sync_fetch_and_nand (&us, 1); // CHECK: atomicrmw nand i16 + (void) __sync_fetch_and_nand (&si, 1); // CHECK: atomicrmw nand i32 + (void) __sync_fetch_and_nand (&ui, 1); // CHECK: atomicrmw nand i32 + (void) __sync_fetch_and_nand (&sll, 1); // CHECK: atomicrmw nand i64 + (void) __sync_fetch_and_nand (&ull, 1); // CHECK: atomicrmw nand i64 + (void) __sync_fetch_and_and (&sc, 1); // CHECK: atomicrmw and i8 (void) __sync_fetch_and_and (&uc, 1); // CHECK: atomicrmw and i8 (void) __sync_fetch_and_and (&ss, 1); // CHECK: atomicrmw and i16 @@ -98,6 +107,15 @@ void test_fetch_and_op (void) // CHECK-LABEL: define void @test_fetch_and_op sll = __sync_fetch_and_xor (&sll, 11); // CHECK: atomicrmw xor ull = __sync_fetch_and_xor (&ull, 11); // CHECK: atomicrmw xor + sc = __sync_fetch_and_nand (&sc, 11); // CHECK: atomicrmw nand + uc = __sync_fetch_and_nand (&uc, 11); // CHECK: atomicrmw nand + ss = __sync_fetch_and_nand (&ss, 11); // CHECK: atomicrmw nand + us = __sync_fetch_and_nand (&us, 11); // CHECK: atomicrmw nand + si = __sync_fetch_and_nand (&si, 11); // CHECK: atomicrmw nand + ui = __sync_fetch_and_nand (&ui, 11); // CHECK: atomicrmw nand + sll = __sync_fetch_and_nand (&sll, 11); // CHECK: atomicrmw nand + ull = __sync_fetch_and_nand (&ull, 11); // CHECK: atomicrmw nand + sc = __sync_fetch_and_and (&sc, 11); // CHECK: atomicrmw and uc = __sync_fetch_and_and (&uc, 11); // CHECK: atomicrmw and ss = __sync_fetch_and_and (&ss, 11); // CHECK: atomicrmw and @@ -147,6 +165,31 @@ void test_op_and_fetch (void) sll = __sync_xor_and_fetch (&sll, uc); // CHECK: atomicrmw xor ull = __sync_xor_and_fetch (&ull, uc); // CHECK: atomicrmw xor + sc = __sync_nand_and_fetch (&sc, uc); // CHECK: atomicrmw nand + // CHECK: and + // CHECK: xor + uc = __sync_nand_and_fetch (&uc, uc); // CHECK: atomicrmw nand + // CHECK: and + // CHECK: xor + ss = __sync_nand_and_fetch (&ss, uc); // CHECK: atomicrmw nand + // CHECK: and + // CHECK: xor + us = __sync_nand_and_fetch (&us, uc); // CHECK: atomicrmw nand + // CHECK: and + // CHECK: xor + si = __sync_nand_and_fetch (&si, uc); // CHECK: atomicrmw nand + // CHECK: and + // CHECK: xor + ui = __sync_nand_and_fetch (&ui, uc); // CHECK: atomicrmw nand + // CHECK: and + // CHECK: xor + sll = __sync_nand_and_fetch (&sll, uc); // CHECK: atomicrmw nand + // CHECK: and + // CHECK: xor + ull = __sync_nand_and_fetch (&ull, uc); // CHECK: atomicrmw nand + // CHECK: and + // CHECK: xor + sc = __sync_and_and_fetch (&sc, uc); // CHECK: atomicrmw and uc = __sync_and_and_fetch (&uc, uc); // CHECK: atomicrmw and ss = __sync_and_and_fetch (&ss, uc); // CHECK: atomicrmw and diff --git a/clang/test/CodeGen/atomic.c b/clang/test/CodeGen/atomic.c index 43f5bc81ee98..4db3c8e6d69c 100644 --- a/clang/test/CodeGen/atomic.c +++ b/clang/test/CodeGen/atomic.c @@ -50,7 +50,10 @@ int atomic(void) { old = __sync_fetch_and_xor(&val, 0xb); // CHECK: atomicrmw xor i32* %val, i32 11 seq_cst - + + old = __sync_fetch_and_nand(&val, 0xc); + // CHECK: atomicrmw nand i32* %val, i32 12 seq_cst + old = __sync_add_and_fetch(&val, 1); // CHECK: atomicrmw add i32* %val, i32 1 seq_cst @@ -65,7 +68,10 @@ int atomic(void) { old = __sync_xor_and_fetch(&valc, 5); // CHECK: atomicrmw xor i8* %valc, i8 5 seq_cst - + + old = __sync_nand_and_fetch(&valc, 6); + // CHECK: atomicrmw nand i8* %valc, i8 6 seq_cst + __sync_val_compare_and_swap((void **)0, (void *)0, (void *)0); // CHECK: [[PAIR:%[a-z0-9_.]+]] = cmpxchg i32* null, i32 0, i32 0 seq_cst // CHECK: extractvalue { i32, i1 } [[PAIR]], 0 diff --git a/clang/test/Sema/builtins.c b/clang/test/Sema/builtins.c index f8df2f85cf64..0e2925e0748d 100644 --- a/clang/test/Sema/builtins.c +++ b/clang/test/Sema/builtins.c @@ -66,6 +66,11 @@ void test9_3(volatile int* ptr, int val) { __sync_fetch_and_add_4(ptr, val); } +void test9_4(volatile int* ptr, int val) { + // expected-warning@+1 {{the semantics of this intrinsic changed with GCC version 4.4 - the newer semantics are provided here}} + __sync_fetch_and_nand(ptr, val); +} + // rdar://7236819 void test10(void) __attribute__((noreturn));