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 @@ -113,6 +113,7 @@ BUILTIN(__builtin_ppc_fnmsubs, "ffff", "") BUILTIN(__builtin_ppc_fre, "dd", "") BUILTIN(__builtin_ppc_fres, "ff", "") +BUILTIN(__builtin_ppc_stbcx, "icD*i", "") 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 @@ -118,6 +118,7 @@ Builder.defineMacro("__fetch_and_swaplp", "__builtin_ppc_fetch_and_swaplp"); Builder.defineMacro("__ldarx", "__builtin_ppc_ldarx"); Builder.defineMacro("__lwarx", "__builtin_ppc_lwarx"); + Builder.defineMacro("__stbcx", "__builtin_ppc_stbcx"); Builder.defineMacro("__stdcx", "__builtin_ppc_stdcx"); Builder.defineMacro("__stwcx", "__builtin_ppc_stwcx"); Builder.defineMacro("__tdw", "__builtin_ppc_tdw"); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3429,6 +3429,9 @@ case PPC::BI__builtin_ppc_mtfsfi: return SemaBuiltinConstantArgRange(TheCall, 0, 0, 7) || SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + case PPC::BI__builtin_ppc_stbcx: + return SemaFeatureCheck(*this, TheCall, "isa-v207-instructions", + diag::err_ppc_builtin_only_on_arch, "8"); #define CUSTOM_BUILTIN(Name, Intr, Types, Acc) \ case PPC::BI__builtin_##Name: \ return SemaBuiltinPPCMMACall(TheCall, Types); diff --git a/clang/test/CodeGen/builtins-ppc-xlcompat-pwr8.c b/clang/test/CodeGen/builtins-ppc-xlcompat-pwr8.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/builtins-ppc-xlcompat-pwr8.c @@ -0,0 +1,31 @@ +// REQUIRES: powerpc-registered-target +// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -emit-llvm %s \ +// RUN: -target-cpu pwr8 -o - | FileCheck %s --check-prefix=CHECK-PWR8 +// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -emit-llvm %s \ +// RUN: -target-cpu pwr8 -o - | FileCheck %s --check-prefix=CHECK-PWR8 +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -emit-llvm %s \ +// RUN: -target-cpu pwr8 -o - | FileCheck %s --check-prefix=CHECK-PWR8 +// RUN: %clang_cc1 -triple powerpc-unknown-aix %s -emit-llvm %s \ +// RUN: -target-cpu pwr8 -o - | FileCheck %s --check-prefix=CHECK-PWR8 +// RUN: not %clang_cc1 -triple powerpc64-unknown-unknown -emit-llvm %s \ +// RUN: -target-cpu pwr7 -o - 2>&1 | FileCheck %s -check-prefix=CHECK-NOPWR8 +// RUN: not %clang_cc1 -triple powerpc64-unknown-aix -emit-llvm %s \ +// RUN: -target-cpu pwr7 -o - 2>&1 | FileCheck %s -check-prefix=CHECK-NOPWR8 +// RUN: not %clang_cc1 -triple powerpc-unknown-aix %s -emit-llvm %s \ +// RUN: -target-cpu pwr7 -o - 2>&1 | FileCheck %s -check-prefix=CHECK-NOPWR8 + +extern volatile char *c_addr; +extern char c; + +// CHECK-PWR8-LABEL: @test_builtin_ppc_stbcx( +// CHECK-PWR8: [[TMP0:%.*]] = load i8*, i8** @c_addr, align {{[0-9]+}} +// CHECK-PWR8-NEXT: [[TMP1:%.*]] = load i8, i8* @c, align 1 +// CHECK-PWR8-NEXT: [[TMP2:%.*]] = sext i8 [[TMP1]] to i32 +// CHECK-PWR8-NEXT: [[TMP3:%.*]] = call i32 @llvm.ppc.stbcx(i8* [[TMP0]], i32 [[TMP2]]) +// CHECK-PWR8-NEXT: ret i32 [[TMP3]] + +// CHECK-NOPWR8: error: this builtin is only valid on POWER8 or later CPUs + +int test_builtin_ppc_stbcx() { + return __builtin_ppc_stbcx(c_addr, c); +} diff --git a/llvm/include/llvm/IR/IntrinsicsPowerPC.td b/llvm/include/llvm/IR/IntrinsicsPowerPC.td --- a/llvm/include/llvm/IR/IntrinsicsPowerPC.td +++ b/llvm/include/llvm/IR/IntrinsicsPowerPC.td @@ -1559,6 +1559,9 @@ Intrinsic<[],[],[]>; def int_ppc_iospace_eieio : GCCBuiltin<"__builtin_ppc_iospace_eieio">, Intrinsic<[],[],[]>; + def int_ppc_stbcx : GCCBuiltin<"__builtin_ppc_stbcx">, + Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty], + [IntrWriteMem]>; def int_ppc_stdcx : GCCBuiltin<"__builtin_ppc_stdcx">, Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i64_ty], [IntrWriteMem]>; diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td @@ -5459,6 +5459,8 @@ def : Pat<(int_ppc_stwcx ForceXForm:$dst, gprc:$A), (STWCX gprc:$A, ForceXForm:$dst)>; +def : Pat<(int_ppc_stbcx ForceXForm:$dst, gprc:$A), + (STBCX gprc:$A, ForceXForm:$dst)>; def : Pat<(int_ppc_tw gprc:$A, gprc:$B, i32:$IMM), (TW $IMM, $A, $B)>; def : Pat<(int_ppc_trap gprc:$A), diff --git a/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-LoadReserve-StoreCond.ll b/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-LoadReserve-StoreCond.ll --- a/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-LoadReserve-StoreCond.ll +++ b/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-LoadReserve-StoreCond.ll @@ -50,3 +50,25 @@ %1 = tail call i32 @llvm.ppc.stwcx(i8* %0, i32 %b) ret i32 %1 } + +declare i32 @llvm.ppc.stbcx(i8*, i32) +define signext i32 @test_stbcx(i8* %addr, i8 signext %val) { +; CHECK-64-LABEL: test_stbcx: +; CHECK-64: # %bb.0: # %entry +; CHECK-64-NEXT: stbcx. 4, 0, 3 +; CHECK-64-NEXT: mfocrf 3, 128 +; CHECK-64-NEXT: srwi 3, 3, 28 +; CHECK-64-NEXT: extsw 3, 3 +; CHECK-64-NEXT: blr +; +; CHECK-32-LABEL: test_stbcx: +; CHECK-32: # %bb.0: # %entry +; CHECK-32-NEXT: stbcx. 4, 0, 3 +; CHECK-32-NEXT: mfocrf 3, 128 +; CHECK-32-NEXT: srwi 3, 3, 28 +; CHECK-32-NEXT: blr +entry: + %conv = sext i8 %val to i32 + %0 = tail call i32 @llvm.ppc.stbcx(i8* %addr, i32 %conv) + ret i32 %0 +}