From 0002d23aaf10f307273dab5facda01c137283d22 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Tue, 7 Apr 2009 00:55:51 +0000 Subject: [PATCH] Implement __sync_{add,sub,and,or,xor}_and_fetch and __sync_bool_compare_and_swap. - [sema/irgen] support __sync_bool_compare_and_swap and __sync_add_and_fetch git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68482 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Builtins.def | 14 ++++++- lib/CodeGen/CGBuiltin.cpp | 68 +++++++++++++++++++++++++++++----- test/CodeGen/atomic.c | 20 +++++++--- 3 files changed, 86 insertions(+), 16 deletions(-) diff --git a/include/clang/AST/Builtins.def b/include/clang/AST/Builtins.def index ce11658667..104c5a8621 100644 --- a/include/clang/AST/Builtins.def +++ b/include/clang/AST/Builtins.def @@ -176,7 +176,9 @@ BUILTIN(__builtin_shufflevector, "v." , "nc") BUILTIN(__builtin_alloca, "v*z" , "n") -// Atomic operators builtin. +// Atomic operators builtin. + +// FIXME: These should be overloaded for i8, i16, i32, and i64. BUILTIN(__sync_fetch_and_add,"ii*i", "n") BUILTIN(__sync_fetch_and_sub,"ii*i", "n") BUILTIN(__sync_fetch_and_min,"ii*i", "n") @@ -186,7 +188,17 @@ BUILTIN(__sync_fetch_and_umax,"UiUi*Ui", "n") BUILTIN(__sync_fetch_and_and,"ii*i", "n") BUILTIN(__sync_fetch_and_or,"ii*i", "n") BUILTIN(__sync_fetch_and_xor,"ii*i", "n") +BUILTIN(__sync_add_and_fetch,"ii*i", "n") +BUILTIN(__sync_sub_and_fetch,"ii*i", "n") +BUILTIN(__sync_min_and_fetch,"ii*i", "n") +BUILTIN(__sync_max_and_fetch,"ii*i", "n") +BUILTIN(__sync_umin_and_fetch,"UiUi*Ui", "n") +BUILTIN(__sync_umax_and_fetch,"UiUi*Ui", "n") +BUILTIN(__sync_and_and_fetch,"ii*i", "n") +BUILTIN(__sync_or_and_fetch,"ii*i", "n") +BUILTIN(__sync_xor_and_fetch,"ii*i", "n") BUILTIN(__sync_lock_test_and_set,"ii*i", "n") +BUILTIN(__sync_bool_compare_and_swap,"ii*ii", "n") BUILTIN(__sync_val_compare_and_swap,"ii*ii", "n") // LLVM instruction builtin diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 6e59226a6e..0b40ec76e8 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -23,17 +23,33 @@ using namespace clang; using namespace CodeGen; using namespace llvm; -/// Utility to insert an atomic instruction based Instrinsic::ID and -// the expression node -static RValue EmitBinaryAtomic(CodeGenFunction& CFG, +/// Utility to insert an atomic instruction based on Instrinsic::ID +/// and the expression node. +static RValue EmitBinaryAtomic(CodeGenFunction& CGF, Intrinsic::ID Id, const CallExpr *E) { const llvm::Type *ResType[2]; - ResType[0] = CFG.ConvertType(E->getType()); - ResType[1] = CFG.ConvertType(E->getArg(0)->getType()); - Value *AtomF = CFG.CGM.getIntrinsic(Id, ResType, 2); - return RValue::get(CFG.Builder.CreateCall2(AtomF, - CFG.EmitScalarExpr(E->getArg(0)), - CFG.EmitScalarExpr(E->getArg(1)))); + ResType[0] = CGF.ConvertType(E->getType()); + ResType[1] = CGF.ConvertType(E->getArg(0)->getType()); + Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2); + return RValue::get(CGF.Builder.CreateCall2(AtomF, + CGF.EmitScalarExpr(E->getArg(0)), + CGF.EmitScalarExpr(E->getArg(1)))); +} + +/// Utility to insert an atomic instruction based Instrinsic::ID and +// the expression node, where the return value is the result of the +// operation. +static RValue EmitBinaryAtomicPost(CodeGenFunction& CGF, + Intrinsic::ID Id, const CallExpr *E, + Instruction::BinaryOps Op) { + const llvm::Type *ResType[2]; + ResType[0] = CGF.ConvertType(E->getType()); + ResType[1] = CGF.ConvertType(E->getArg(0)->getType()); + Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2); + Value *Ptr = CGF.EmitScalarExpr(E->getArg(0)); + Value *Operand = CGF.EmitScalarExpr(E->getArg(1)); + Value *Result = CGF.Builder.CreateCall2(AtomF, Ptr, Operand); + return RValue::get(CGF.Builder.CreateBinOp(Op, Result, Operand)); } RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, @@ -295,6 +311,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *F = CGM.getIntrinsic(Intrinsic::frameaddress, 0, 0); return RValue::get(Builder.CreateCall(F, EmitScalarExpr(E->getArg(0)))); } + case Builtin::BI__sync_fetch_and_add: return EmitBinaryAtomic(*this, Intrinsic::atomic_load_add, E); case Builtin::BI__sync_fetch_and_sub: @@ -313,6 +330,23 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return EmitBinaryAtomic(*this, Intrinsic::atomic_load_or, E); case Builtin::BI__sync_fetch_and_xor: return EmitBinaryAtomic(*this, Intrinsic::atomic_load_xor, E); + + case Builtin::BI__sync_add_and_fetch: + return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_add, E, + llvm::Instruction::Add); + case Builtin::BI__sync_sub_and_fetch: + return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_sub, E, + llvm::Instruction::Sub); + case Builtin::BI__sync_and_and_fetch: + return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_and, E, + llvm::Instruction::And); + case Builtin::BI__sync_or_and_fetch: + return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_or, E, + llvm::Instruction::Or); + case Builtin::BI__sync_xor_and_fetch: + return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_xor, E, + llvm::Instruction::Xor); + case Builtin::BI__sync_val_compare_and_swap: { const llvm::Type *ResType[2]; ResType[0]= ConvertType(E->getType()); @@ -323,6 +357,22 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, EmitScalarExpr(E->getArg(1)), EmitScalarExpr(E->getArg(2)))); } + + case Builtin::BI__sync_bool_compare_and_swap: { + const llvm::Type *ResType[2]; + ResType[0]= ConvertType(E->getType()); + ResType[1] = ConvertType(E->getArg(0)->getType()); + Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2); + Value *OldVal = EmitScalarExpr(E->getArg(1)); + Value *PrevVal = Builder.CreateCall3(AtomF, + EmitScalarExpr(E->getArg(0)), + OldVal, + EmitScalarExpr(E->getArg(2))); + Value *Result = Builder.CreateICmpEQ(PrevVal, OldVal); + // zext bool to int. + return RValue::get(Builder.CreateZExt(Result, ConvertType(E->getType()))); + } + case Builtin::BI__sync_lock_test_and_set: return EmitBinaryAtomic(*this, Intrinsic::atomic_swap, E); diff --git a/test/CodeGen/atomic.c b/test/CodeGen/atomic.c index 0e2d850dbb..d1b3cbb0d4 100644 --- a/test/CodeGen/atomic.c +++ b/test/CodeGen/atomic.c @@ -1,15 +1,15 @@ // RUN: clang-cc %s -emit-llvm -o - > %t1 && -// RUN: grep @llvm.atomic.load.add.i32 %t1 && -// RUN: grep @llvm.atomic.load.sub.i32 %t1 && +// RUN: grep @llvm.atomic.load.add.i32 %t1 | count 3 && +// RUN: grep @llvm.atomic.load.sub.i32 %t1 | count 3 && // RUN: grep @llvm.atomic.load.min.i32 %t1 && // RUN: grep @llvm.atomic.load.max.i32 %t1 && // RUN: grep @llvm.atomic.load.umin.i32 %t1 && // RUN: grep @llvm.atomic.load.umax.i32 %t1 && // RUN: grep @llvm.atomic.swap.i32 %t1 && -// RUN: grep @llvm.atomic.cmp.swap.i32 %t1 && -// RUN: grep @llvm.atomic.load.and.i32 %t1 && -// RUN: grep @llvm.atomic.load.or.i32 %t1 && -// RUN: grep @llvm.atomic.load.xor.i32 %t1 +// RUN: grep @llvm.atomic.cmp.swap.i32 %t1 | count 3 && +// RUN: grep @llvm.atomic.load.and.i32 %t1 | count 3 && +// RUN: grep @llvm.atomic.load.or.i32 %t1 | count 3 && +// RUN: grep @llvm.atomic.load.xor.i32 %t1 | count 3 int atomic(void) @@ -28,8 +28,16 @@ int atomic(void) old = __sync_fetch_and_umax(&uval, 6u); old = __sync_lock_test_and_set(&val, 7); old = __sync_val_compare_and_swap(&val, 4, 1976); + old = __sync_bool_compare_and_swap(&val, 4, 1976); old = __sync_fetch_and_and(&val, 0x9); old = __sync_fetch_and_or(&val, 0xa); old = __sync_fetch_and_xor(&val, 0xb); + + old = __sync_add_and_fetch(&val, 1); + old = __sync_sub_and_fetch(&val, 2); + old = __sync_and_and_fetch(&val, 3); + old = __sync_or_and_fetch(&val, 4); + old = __sync_xor_and_fetch(&val, 5); + return old; } -- 2.50.1