aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMon P Wang <wangmp@apple.com>2008-05-09 22:40:52 +0000
committerMon P Wang <wangmp@apple.com>2008-05-09 22:40:52 +0000
commit1ffe281890f3cd7728316b45a1f3dd4d3120af7b (patch)
tree5f16a0ba2fac56665a84e0696c118dfe890ef086
parent580ca7859330f8c92a66b09c21399ed9efa3991e (diff)
Added support to generate some atomic operators (add, sub, and, or etc..)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50919 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/Builtins.def13
-rw-r--r--lib/CodeGen/CGBuiltin.cpp39
-rw-r--r--test/CodeGen/atomic.c35
3 files changed, 87 insertions, 0 deletions
diff --git a/include/clang/AST/Builtins.def b/include/clang/AST/Builtins.def
index d231498582..33380baadb 100644
--- a/include/clang/AST/Builtins.def
+++ b/include/clang/AST/Builtins.def
@@ -98,4 +98,17 @@ BUILTIN(__builtin_expect, "iii" , "nc")
BUILTIN(__builtin_alloca, "v*z" , "n")
+// Atomic operators builtin.
+BUILTIN(__sync_fetch_and_add,"ii*i", "n")
+BUILTIN(__sync_fetch_and_sub,"ii*i", "n")
+BUILTIN(__sync_fetch_and_min,"ii*i", "n")
+BUILTIN(__sync_fetch_and_max,"ii*i", "n")
+BUILTIN(__sync_fetch_and_umin,"UiUi*Ui", "n")
+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_lock_test_and_set,"ii*i", "n")
+BUILTIN(__sync_val_compare_and_swap,"ii*ii", "n")
+
#undef BUILTIN
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index f32031325d..1574ae1085 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -25,6 +25,17 @@ 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,
+ Intrinsic::ID Id, const CallExpr *E) {
+ const llvm::Type *ResType = CFG.ConvertType(E->getType());
+ Value *AtomF = CFG.CGM.getIntrinsic(Id, &ResType, 1);
+ return RValue::get(CFG.Builder.CreateCall2(AtomF,
+ CFG.EmitScalarExpr(E->getArg(0)),
+ CFG.EmitScalarExpr(E->getArg(1))));
+}
+
RValue CodeGenFunction::EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E) {
switch (BuiltinID) {
default: {
@@ -241,7 +252,35 @@ RValue CodeGenFunction::EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E) {
return RValue::get(Builder.CreateAlloca(llvm::Type::Int8Ty,
EmitScalarExpr(E->getArg(0)),
"tmp"));
+ case Builtin::BI__sync_fetch_and_add:
+ return EmitBinaryAtomic(*this, Intrinsic::atomic_las, E);
+ case Builtin::BI__sync_fetch_and_sub:
+ return EmitBinaryAtomic(*this, Intrinsic::atomic_lss, E);
+ case Builtin::BI__sync_fetch_and_min:
+ return EmitBinaryAtomic(*this, Intrinsic::atomic_load_min, E);
+ case Builtin::BI__sync_fetch_and_max:
+ return EmitBinaryAtomic(*this, Intrinsic::atomic_load_max, E);
+ case Builtin::BI__sync_fetch_and_umin:
+ return EmitBinaryAtomic(*this, Intrinsic::atomic_load_umin, E);
+ case Builtin::BI__sync_fetch_and_umax:
+ return EmitBinaryAtomic(*this, Intrinsic::atomic_load_umax, E);
+ case Builtin::BI__sync_fetch_and_and:
+ return EmitBinaryAtomic(*this, Intrinsic::atomic_load_and, E);
+ case Builtin::BI__sync_fetch_and_or:
+ 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_val_compare_and_swap: {
+ Value *Args[3];
+ Args[0]= EmitScalarExpr(E->getArg(0));
+ Args[1] = EmitScalarExpr(E->getArg(1));
+ Args[2] = EmitScalarExpr(E->getArg(2));
+ const llvm::Type *ResType = ConvertType(E->getType());
+ Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_lcs, &ResType, 1);
+ return RValue::get(Builder.CreateCall(AtomF, &Args[0], &Args[1]+2));
}
+ case Builtin::BI__sync_lock_test_and_set:
+ return EmitBinaryAtomic(*this, Intrinsic::atomic_swap, E); }
return RValue::get(0);
}
diff --git a/test/CodeGen/atomic.c b/test/CodeGen/atomic.c
new file mode 100644
index 0000000000..a80d4666cb
--- /dev/null
+++ b/test/CodeGen/atomic.c
@@ -0,0 +1,35 @@
+// RUN: clang %s -emit-llvm -o - > %t1
+// RUN: grep @llvm.atomic.las.i32 %t1
+// RUN: grep @llvm.atomic.lss.i32 %t1
+// 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.lcs.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
+
+
+int atomic(void)
+{
+ // nonsenical test for sync functions
+ int old;
+ int val = 1;
+ unsigned int uval = 1;
+ int cmp = 0;
+
+ old = __sync_fetch_and_add(&val, 1);
+ old = __sync_fetch_and_sub(&val, 2);
+ old = __sync_fetch_and_min(&val, 3);
+ old = __sync_fetch_and_max(&val, 4);
+ old = __sync_fetch_and_umin(&uval, 5u);
+ 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_fetch_and_and(&val, 0x9);
+ old = __sync_fetch_and_or(&val, 0xa);
+ old = __sync_fetch_and_xor(&val, 0xb);
+ return old;
+}