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)