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 @@ -76,6 +76,7 @@ BUILTIN(__builtin_ppc_lwarx, "iiD*", "") BUILTIN(__builtin_ppc_lharx, "isD*", "") BUILTIN(__builtin_ppc_lbarx, "UiUcD*", "") +BUILTIN(__builtin_ppc_stbcx, "icD*i", "") BUILTIN(__builtin_ppc_stdcx, "iLiD*Li", "") BUILTIN(__builtin_ppc_stwcx, "iiD*i", "") BUILTIN(__builtin_ppc_sthcx, "isD*s", "") 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 @@ -121,6 +121,7 @@ Builder.defineMacro("__lharx", "__builtin_ppc_lharx"); Builder.defineMacro("__lbarx", "__builtin_ppc_lbarx"); Builder.defineMacro("__stfiw", "__builtin_ppc_stfiw"); + Builder.defineMacro("__stbcx", "__builtin_ppc_stbcx"); Builder.defineMacro("__stdcx", "__builtin_ppc_stdcx"); Builder.defineMacro("__stwcx", "__builtin_ppc_stwcx"); Builder.defineMacro("__sthcx", "__builtin_ppc_sthcx"); 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 @@ -3434,6 +3434,7 @@ case PPC::BI__builtin_ppc_rdlam: return SemaValueIsRunOfOnes(TheCall, 2); case PPC::BI__builtin_ppc_icbt: + case PPC::BI__builtin_ppc_stbcx: return SemaFeatureCheck(*this, TheCall, "isa-v207-instructions", diag::err_ppc_builtin_only_on_arch, "8"); case PPC::BI__builtin_ppc_sthcx: diff --git a/clang/test/CodeGen/builtins-ppc-xlcompat-pwr8.c b/clang/test/CodeGen/builtins-ppc-xlcompat-pwr8.c --- a/clang/test/CodeGen/builtins-ppc-xlcompat-pwr8.c +++ b/clang/test/CodeGen/builtins-ppc-xlcompat-pwr8.c @@ -15,6 +15,8 @@ // RUN: -target-cpu pwr7 -o - 2>&1 | FileCheck %s -check-prefix=CHECK-NOPWR8 extern void *a; +extern volatile char *c_addr; +extern char c; void test_icbt() { // CHECK-LABEL: @test_icbt( @@ -31,3 +33,14 @@ // CHECK-PWR8: call void @llvm.ppc.icbt(i8* %0) // CHECK-NOPWR8: error: this builtin is only valid on POWER8 or later CPUs } + +int test_builtin_ppc_stbcx() { +// 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 + 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 @@ -1558,6 +1558,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 @@ -5463,6 +5463,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 @@ -29,6 +29,28 @@ ret i32 %0 } +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 +} + declare i32 @llvm.ppc.stwcx(i8*, i32) define dso_local signext i32 @test_stwcx(i32* %a, i32 signext %b) { ; CHECK-64-LABEL: test_stwcx: