diff --git a/clang/docs/LanguageExtensions.html b/clang/docs/LanguageExtensions.html
index 1cd77a1791c9..b16c38c76824 100644
--- a/clang/docs/LanguageExtensions.html
+++ b/clang/docs/LanguageExtensions.html
@@ -56,6 +56,7 @@ td {
Target-Specific Extensions
@@ -711,6 +712,36 @@ no arguments and produces a void result.
Query for this feature with __has_builtin(__builtin_unreachable).
+
+__sync_swap
+
+
+__sync_swap is used to atomically swap integers or pointers in
+memory.
+
+
+Syntax:
+
+
+type __sync_swap(type *ptr, type value, ...)
+
+
+Example of Use:
+
+
+int old_value = __sync_swap(&value, new_value);
+
+
+Description:
+
+The __sync_swap() builtin extends the existing __sync_*() family of atomic
+intrinsics to allow code to atomically swap the current value with the new
+value. More importantly, it helps developers write more efficient and correct
+code by avoiding expensive loops around __sync_bool_compare_and_swap() or
+relying on the platform specific implementation details of
+__sync_lock_test_and_set(). The __sync_swap() builtin is a full barrier.
+
+
Target-Specific Extensions
diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def
index 3f97b787f690..9a4c768dc649 100644
--- a/clang/include/clang/Basic/Builtins.def
+++ b/clang/include/clang/Basic/Builtins.def
@@ -577,6 +577,13 @@ BUILTIN(__sync_lock_release_4, "viD*.", "n")
BUILTIN(__sync_lock_release_8, "vLLiD*.", "n")
BUILTIN(__sync_lock_release_16, "vLLLiD*.", "n")
+BUILTIN(__sync_swap, "v.", "")
+BUILTIN(__sync_swap_1, "ccD*c.", "n")
+BUILTIN(__sync_swap_2, "ssD*s.", "n")
+BUILTIN(__sync_swap_4, "iiD*i.", "n")
+BUILTIN(__sync_swap_8, "LLiLLiD*LLi.", "n")
+BUILTIN(__sync_swap_16, "LLLiLLLiD*LLLi.", "n")
+
// Non-overloaded atomic builtins.
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 35507b99215a..af8d37a22100 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -721,6 +721,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_bool_compare_and_swap:
case Builtin::BI__sync_lock_test_and_set:
case Builtin::BI__sync_lock_release:
+ case Builtin::BI__sync_swap:
assert(0 && "Shouldn't make it through sema");
case Builtin::BI__sync_fetch_and_add_1:
case Builtin::BI__sync_fetch_and_add_2:
@@ -860,6 +861,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Result);
}
+ case Builtin::BI__sync_swap_1:
+ case Builtin::BI__sync_swap_2:
+ case Builtin::BI__sync_swap_4:
+ case Builtin::BI__sync_swap_8:
+ case Builtin::BI__sync_swap_16:
+ return EmitBinaryAtomic(*this, Intrinsic::atomic_swap, E);
+
case Builtin::BI__sync_lock_test_and_set_1:
case Builtin::BI__sync_lock_test_and_set_2:
case Builtin::BI__sync_lock_test_and_set_4:
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 105fb52ddb55..e1adfd48396c 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -180,6 +180,7 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case Builtin::BI__sync_bool_compare_and_swap:
case Builtin::BI__sync_lock_test_and_set:
case Builtin::BI__sync_lock_release:
+ case Builtin::BI__sync_swap:
return SemaBuiltinAtomicOverloaded(move(TheCallResult));
}
@@ -415,7 +416,8 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
BUILTIN_ROW(__sync_val_compare_and_swap),
BUILTIN_ROW(__sync_bool_compare_and_swap),
BUILTIN_ROW(__sync_lock_test_and_set),
- BUILTIN_ROW(__sync_lock_release)
+ BUILTIN_ROW(__sync_lock_release),
+ BUILTIN_ROW(__sync_swap)
};
#undef BUILTIN_ROW
@@ -468,6 +470,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
NumFixed = 0;
ResultType = Context.VoidTy;
break;
+ case Builtin::BI__sync_swap: BuiltinIndex = 14; break;
}
// Now that we know how many fixed arguments we expect, first check that we
diff --git a/clang/test/CodeGen/atomic.c b/clang/test/CodeGen/atomic.c
index 4a7c13f03c41..8ce2d96043f2 100644
--- a/clang/test/CodeGen/atomic.c
+++ b/clang/test/CodeGen/atomic.c
@@ -44,6 +44,11 @@ int atomic(void) {
// CHECK: call i32 @llvm.atomic.swap.i32.p0i32(i32* %val, i32 7)
// CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ old = __sync_swap(&val, 8);
+ // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: call i32 @llvm.atomic.swap.i32.p0i32(i32* %val, i32 8)
+ // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+
old = __sync_val_compare_and_swap(&val, 4, 1976);
// CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
// CHECK: call i32 @llvm.atomic.cmp.swap.i32.p0i32(i32* %val, i32 4, i32 1976)