diff --git a/clang/include/clang/Basic/BuiltinsPPC.def b/clang/include/clang/Basic/BuiltinsPPC.def --- a/clang/include/clang/Basic/BuiltinsPPC.def +++ b/clang/include/clang/Basic/BuiltinsPPC.def @@ -45,6 +45,8 @@ BUILTIN(__builtin_ppc_dcbtst, "vv*", "") BUILTIN(__builtin_ppc_dcbz, "vv*", "") BUILTIN(__builtin_ppc_icbt, "vv*", "") +BUILTIN(__builtin_ppc_compare_and_swap, "iiD*i*i", "") +BUILTIN(__builtin_ppc_compare_and_swaplp, "iLiD*Li*Li", "") BUILTIN(__builtin_ppc_get_timebase, "ULLi", "n") diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -97,6 +97,9 @@ Builder.defineMacro("__dcbtst", "__builtin_ppc_dcbtst"); Builder.defineMacro("__dcbz", "__builtin_ppc_dcbz"); Builder.defineMacro("__icbt", "__builtin_ppc_icbt"); + Builder.defineMacro("__compare_and_swap", "__builtin_ppc_compare_and_swap"); + Builder.defineMacro("__compare_and_swaplp", + "__builtin_ppc_compare_and_swaplp"); } /// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -15427,6 +15427,19 @@ Value *Call = Builder.CreateCall(F, CallOps); return Builder.CreateAlignedStore(Call, Ops[0], MaybeAlign(64)); } + + case PPC::BI__builtin_ppc_compare_and_swap: + case PPC::BI__builtin_ppc_compare_and_swaplp: { + Address Addr = EmitPointerWithAlignment(E->getArg(0)); + Address OldValAddr = EmitPointerWithAlignment(E->getArg(1)); + Value *OldVal = Builder.CreateLoad(OldValAddr); + QualType AtomicTy = E->getArg(0)->getType()->getPointeeType(); + LValue LV = MakeAddrLValue(Addr, AtomicTy); + auto Pair = EmitAtomicCompareExchange( + LV, RValue::get(OldVal), RValue::get(Ops[2]), E->getExprLoc(), + llvm::AtomicOrdering::Monotonic, llvm::AtomicOrdering::Monotonic, true); + return Pair.second; + } } } diff --git a/clang/test/CodeGen/builtins-ppc-xlcompat-cas-error.c b/clang/test/CodeGen/builtins-ppc-xlcompat-cas-error.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/builtins-ppc-xlcompat-cas-error.c @@ -0,0 +1,19 @@ +// REQUIRES: powerpc-registered-target +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -target-cpu pwr8 \ +// RUN: -verify %s + +void test_builtin_ppc_compare_and_swap() { + volatile int a = 0; + long b = 0, c = 0; + + __compare_and_swap(&a, &b, c); // expected-warning {{incompatible pointer types passing 'long *' to parameter of type 'int *'}} + +} + +void test_builtin_ppc_compare_and_swaplp() { + volatile long a = 0; + int b = 0, c = 0; + + __compare_and_swaplp(&a, &b, c);// expected-warning {{incompatible pointer types passing 'int *' to parameter of type 'long *'}} + +} diff --git a/clang/test/CodeGen/builtins-ppc-xlcompat-cas.c b/clang/test/CodeGen/builtins-ppc-xlcompat-cas.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/builtins-ppc-xlcompat-cas.c @@ -0,0 +1,47 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// REQUIRES: powerpc-registered-target +// RUN: %clang_cc1 -triple powerpc64-unknown-unknown \ +// RUN: -emit-llvm %s -o - -target-cpu pwr8 | FileCheck %s +// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown \ +// RUN: -emit-llvm %s -o - -target-cpu pwr8 | FileCheck %s + + +// CHECK-LABEL: @test_builtin_ppc_compare_and_swap( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], i32* [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], i32* [[B_ADDR]], align 4 +// CHECK-NEXT: store i32 [[C:%.*]], i32* [[C_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[C_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = cmpxchg weak volatile i32* [[A_ADDR]], i32 [[TMP1]], i32 [[TMP0]] monotonic monotonic, align 4 +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK-NEXT: ret void +// +void test_builtin_ppc_compare_and_swap(int a, int b, int c) { + __compare_and_swap(&a, &b, c); +} + + +// CHECK-LABEL: @test_builtin_ppc_compare_and_swaplp( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[C_ADDR:%.*]] = alloca i64, align 8 +// CHECK-NEXT: store i64 [[A:%.*]], i64* [[A_ADDR]], align 8 +// CHECK-NEXT: store i64 [[B:%.*]], i64* [[B_ADDR]], align 8 +// CHECK-NEXT: store i64 [[C:%.*]], i64* [[C_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load i64, i64* [[C_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load i64, i64* [[B_ADDR]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = cmpxchg weak volatile i64* [[A_ADDR]], i64 [[TMP1]], i64 [[TMP0]] monotonic monotonic, align 8 +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK-NEXT: ret void +// +void test_builtin_ppc_compare_and_swaplp(long a, long b, long c) { + __compare_and_swaplp(&a, &b, c); +} +