Index: include/clang/Basic/Builtins.def =================================================================== --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -541,6 +541,12 @@ 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_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") Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -6875,6 +6875,11 @@ "attribute %0 is already applied with different parameters">, InGroup; +def warn_gcc44_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< Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -113,7 +113,8 @@ 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 @@ 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); } @@ -871,11 +875,13 @@ 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: @@ -912,6 +918,12 @@ 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: @@ -958,6 +970,13 @@ 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: Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -273,6 +273,12 @@ 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 @@ 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: @@ -1516,12 +1528,14 @@ 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), @@ -1551,6 +1565,7 @@ // 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: @@ -1598,13 +1613,23 @@ 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: @@ -1613,7 +1638,7 @@ 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: @@ -1622,7 +1647,7 @@ 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: @@ -1631,7 +1656,7 @@ 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: @@ -1640,7 +1665,17 @@ 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: @@ -1649,7 +1684,7 @@ 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; @@ -1659,7 +1694,7 @@ 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; @@ -1670,7 +1705,7 @@ 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: @@ -1679,7 +1714,7 @@ 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; @@ -1690,7 +1725,7 @@ case Builtin::BI__sync_swap_4: case Builtin::BI__sync_swap_8: case Builtin::BI__sync_swap_16: - BuiltinIndex = 14; + BuiltinIndex = 16; break; } @@ -1703,6 +1738,11 @@ return ExprError(); } + if (WarnAboutSemanticsChange) { + Diag(TheCall->getLocEnd(), diag::warn_gcc44_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]; Index: test/CodeGen/Atomics.c =================================================================== --- test/CodeGen/Atomics.c +++ test/CodeGen/Atomics.c @@ -49,6 +49,15 @@ (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 @@ 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,23 @@ 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: xor + uc = __sync_nand_and_fetch (&uc, uc); // CHECK: atomicrmw nand + // CHECK: xor + ss = __sync_nand_and_fetch (&ss, uc); // CHECK: atomicrmw nand + // CHECK: xor + us = __sync_nand_and_fetch (&us, uc); // CHECK: atomicrmw nand + // CHECK: xor + si = __sync_nand_and_fetch (&si, uc); // CHECK: atomicrmw nand + // CHECK: xor + ui = __sync_nand_and_fetch (&ui, uc); // CHECK: atomicrmw nand + // CHECK: xor + sll = __sync_nand_and_fetch (&sll, uc); // CHECK: atomicrmw nand + // CHECK: xor + ull = __sync_nand_and_fetch (&ull, uc); // CHECK: atomicrmw nand + // 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 Index: test/CodeGen/atomic.c =================================================================== --- test/CodeGen/atomic.c +++ test/CodeGen/atomic.c @@ -50,7 +50,10 @@ 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 @@ 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 Index: test/Sema/builtins.c =================================================================== --- test/Sema/builtins.c +++ test/Sema/builtins.c @@ -66,6 +66,11 @@ __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));