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 @@ -72,6 +72,7 @@ BUILTIN(__builtin_ppc_fetch_and_orlp, "ULiULiD*ULi", "") BUILTIN(__builtin_ppc_fetch_and_swap, "UiUiD*Ui", "") BUILTIN(__builtin_ppc_fetch_and_swaplp, "ULiULiD*ULi", "") +BUILTIN(__builtin_ppc_kill_canary, "v", "") BUILTIN(__builtin_ppc_ldarx, "LiLiD*", "") BUILTIN(__builtin_ppc_lwarx, "iiD*", "") BUILTIN(__builtin_ppc_lharx, "ssD*", "") 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 @@ -122,6 +122,7 @@ Builder.defineMacro("__fetch_and_orlp", "__builtin_ppc_fetch_and_orlp"); Builder.defineMacro("__fetch_and_swap", "__builtin_ppc_fetch_and_swap"); Builder.defineMacro("__fetch_and_swaplp", "__builtin_ppc_fetch_and_swaplp"); + Builder.defineMacro("__kill_canary", "__builtin_ppc_kill_canary"); Builder.defineMacro("__ldarx", "__builtin_ppc_ldarx"); Builder.defineMacro("__lwarx", "__builtin_ppc_lwarx"); Builder.defineMacro("__lharx", "__builtin_ppc_lharx"); diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-stackprotect.c b/clang/test/CodeGen/PowerPC/builtins-ppc-stackprotect.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/PowerPC/builtins-ppc-stackprotect.c @@ -0,0 +1,23 @@ +// REQUIRES: powerpc-registered-target +// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu \ +// RUN: -emit-llvm %s -o - -target-cpu pwr7 | \ +// RUN: FileCheck %s +// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu \ +// RUN: -emit-llvm %s -o - -target-cpu pwr8 | \ +// RUN: FileCheck %s +// RUN: %clang_cc1 -triple powerpc-unknown-aix \ +// RUN: -emit-llvm %s -o - -target-cpu pwr7 | \ +// RUN: FileCheck %s +// RUN: %clang_cc1 -triple powerpc64-unknown-aix \ +// RUN: -emit-llvm %s -o - -target-cpu pwr7 | \ +// RUN: FileCheck %s + +void test_builtin_ppc_kill_canary() { + // CHECK: call void @llvm.ppc.kill.canary() + __builtin_ppc_kill_canary(); +} + +void test_kill_canary() { + // CHECK: call void @llvm.ppc.kill.canary() + __kill_canary(); +} 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 @@ -194,6 +194,11 @@ : Intrinsic<[llvm_float_ty], [llvm_float_ty, llvm_float_ty, llvm_float_ty, llvm_vararg_ty], [IntrNoMem]>; + def int_ppc_kill_canary + : ClangBuiltin<"__builtin_ppc_kill_canary">, + Intrinsic<[], + [], + [IntrWriteMem, IntrHasSideEffects]>; } let TargetPrefix = "ppc" in { // All PPC intrinsics start with "llvm.ppc.". diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -10695,6 +10695,58 @@ Op.getOperand(0)), 0); } + case Intrinsic::ppc_kill_canary: { + MachineFunction &MF = DAG.getMachineFunction(); + const Module *M = MF.getMMI().getModule(); + + // The kill_canary intrinsic only makes sense when the Stack Protector + // feature is on in the function. It can also not be used in conjunction + // with safe stack because the latter splits the stack and the canary + // value isn't used (i.e. safe stack supersedes stack protector). + // In situations where the kill_canary intrinsic is not supported, + // we simply replace uses of its chain with its input chain, causing + // the SDAG CSE to remove the node. + if (MF.getFunction().hasFnAttribute(Attribute::SafeStack) || + !MF.getFunction().hasStackProtectorFnAttr()) { + DAG.ReplaceAllUsesOfValueWith( + SDValue(Op.getNode(), 0), + Op->getOperand(0)); + break; + } + + EVT VT = DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout()); + SDValue Load; + SDValue Store; + MachineFrameInfo &MFI = MF.getFrameInfo(); + int SPI = MFI.getStackProtectorIndex(); + PPCFunctionInfo *FuncInfo = MF.getInfo(); + SDValue FIN = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), VT); + + // Linux uses LOAD_STACK_GUARD node instead of a canary global value. + if (useLoadStackGuardNode()) { + MachineSDNode *LSG = + DAG.getMachineNode(PPC::LOAD_STACK_GUARD, DL, VT, Op->getOperand(0)); + Load = SDValue(LSG, 0); + } else if (Value *GV = getSDagStackGuard(*M)) { + // AIX load from global value. + VT = DAG.getTargetLoweringInfo().getValueType(DAG.getDataLayout(), + GV->getType(), true); + SDValue CanaryLoc = + DAG.getGlobalAddress(dyn_cast(GV), DL, VT); + + Load = DAG.getLoad(VT, DL, Op->getOperand(0), CanaryLoc, + MachinePointerInfo()); + } else { + llvm_unreachable("Unhandled stack guard case"); + } + + Store = DAG.getStore( + Op->getOperand(0), DL, + DAG.getNode(ISD::XOR, DL, VT, Load, DAG.getAllOnesConstant(DL, VT)), + DAG.getNode(ISD::ADD, DL, VT, FIN, DAG.getConstant(SPI, DL, VT)), + MachinePointerInfo()); + return Store; + } default: break; } diff --git a/llvm/test/CodeGen/PowerPC/kill-canary-intrinsic.ll b/llvm/test/CodeGen/PowerPC/kill-canary-intrinsic.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/kill-canary-intrinsic.ll @@ -0,0 +1,206 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -mtriple=powerpc-unknown-aix -ppc-vsr-nums-as-vr \ +; RUN: -mcpu=pwr7 --ppc-asm-full-reg-names < %s | FileCheck %s -check-prefix=CHECK-AIX +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu -ppc-vsr-nums-as-vr \ +; RUN: -mcpu=pwr7 --ppc-asm-full-reg-names < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-aix -ppc-vsr-nums-as-vr \ +; RUN: -mcpu=pwr7 --ppc-asm-full-reg-names < %s | FileCheck %s -check-prefix=CHECK-AIX64 +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -ppc-vsr-nums-as-vr \ +; RUN: -mcpu=pwr7 --ppc-asm-full-reg-names < %s | FileCheck %s -check-prefix=CHECK-LINUX-LE + +; RUN: llc -verify-machineinstrs -mtriple=powerpc-unknown-aix -ppc-vsr-nums-as-vr \ +; RUN: -mcpu=pwr8 --ppc-asm-full-reg-names < %s | FileCheck %s -check-prefix=CHECK-AIX +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu -ppc-vsr-nums-as-vr \ +; RUN: -mcpu=pwr8 --ppc-asm-full-reg-names < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-aix -ppc-vsr-nums-as-vr \ +; RUN: -mcpu=pwr8 --ppc-asm-full-reg-names < %s | FileCheck %s -check-prefix=CHECK-AIX64 +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -ppc-vsr-nums-as-vr \ +; RUN: -mcpu=pwr8 --ppc-asm-full-reg-names < %s | FileCheck %s -check-prefix=CHECK-LINUX-LE + +; RUN: llc -verify-machineinstrs -O0 -mtriple=powerpc-unknown-aix -ppc-vsr-nums-as-vr \ +; RUN: -mcpu=pwr7 --ppc-asm-full-reg-names < %s | FileCheck %s -check-prefix=CHECK-AIX-FAST +; RUN: llc -verify-machineinstrs -O0 -mtriple=powerpc64-unknown-linux-gnu -ppc-vsr-nums-as-vr \ +; RUN: -mcpu=pwr7 --ppc-asm-full-reg-names < %s | FileCheck %s -check-prefix=CHECK-FAST + +attributes #1 = { nounwind } +declare void @llvm.ppc.kill.canary() +define dso_local void @test_kill_canary() #1 { +; CHECK-AIX-LABEL: test_kill_canary: +; CHECK-AIX: # %bb.0: # %entry +; CHECK-AIX-NEXT: blr +; +; CHECK-LABEL: test_kill_canary: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: blr +; +; CHECK-AIX64-LABEL: test_kill_canary: +; CHECK-AIX64: # %bb.0: # %entry +; CHECK-AIX64-NEXT: blr +; +; CHECK-LINUX-LE-LABEL: test_kill_canary: +; CHECK-LINUX-LE: # %bb.0: # %entry +; CHECK-LINUX-LE-NEXT: blr +; +; CHECK-AIX-FAST-LABEL: test_kill_canary: +; CHECK-AIX-FAST: # %bb.0: # %entry +; CHECK-AIX-FAST-NEXT: blr +; +; CHECK-FAST-LABEL: test_kill_canary: +; CHECK-FAST: # %bb.0: # %entry +; CHECK-FAST-NEXT: blr +entry: + call void @llvm.ppc.kill.canary() + ret void +} + +attributes #0 = { sspreq } +; Function Attrs: sspreq +define dso_local void @test_kill_canary_ssp() #0 #1 { +; CHECK-AIX-LABEL: test_kill_canary_ssp: +; CHECK-AIX: # %bb.0: # %entry +; CHECK-AIX-NEXT: mflr r0 +; CHECK-AIX-NEXT: stw r0, 8(r1) +; CHECK-AIX-NEXT: stwu r1, -64(r1) +; CHECK-AIX-NEXT: lwz r3, L..C0(r2) # @__ssp_canary_word +; CHECK-AIX-NEXT: lwz r4, 0(r3) +; CHECK-AIX-NEXT: stw r4, 60(r1) +; CHECK-AIX-NEXT: lwz r4, 0(r3) +; CHECK-AIX-NEXT: not r4, r4 +; CHECK-AIX-NEXT: stw r4, 60(r1) +; CHECK-AIX-NEXT: lwz r3, 0(r3) +; CHECK-AIX-NEXT: lwz r4, 60(r1) +; CHECK-AIX-NEXT: cmplw r3, r4 +; CHECK-AIX-NEXT: bne cr0, L..BB1_2 +; CHECK-AIX-NEXT: # %bb.1: # %entry +; CHECK-AIX-NEXT: addi r1, r1, 64 +; CHECK-AIX-NEXT: lwz r0, 8(r1) +; CHECK-AIX-NEXT: mtlr r0 +; CHECK-AIX-NEXT: blr +; CHECK-AIX-NEXT: L..BB1_2: # %entry +; CHECK-AIX-NEXT: bl .__stack_chk_fail[PR] +; CHECK-AIX-NEXT: nop +; +; CHECK-LABEL: test_kill_canary_ssp: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mflr r0 +; CHECK-NEXT: std r0, 16(r1) +; CHECK-NEXT: stdu r1, -128(r1) +; CHECK-NEXT: ld r3, -28688(r13) +; CHECK-NEXT: std r3, 120(r1) +; CHECK-NEXT: ld r3, -28688(r13) +; CHECK-NEXT: not r3, r3 +; CHECK-NEXT: std r3, 120(r1) +; CHECK-NEXT: ld r3, 120(r1) +; CHECK-NEXT: ld r4, -28688(r13) +; CHECK-NEXT: cmpld r4, r3 +; CHECK-NEXT: bne cr0, .LBB1_2 +; CHECK-NEXT: # %bb.1: # %entry +; CHECK-NEXT: addi r1, r1, 128 +; CHECK-NEXT: ld r0, 16(r1) +; CHECK-NEXT: mtlr r0 +; CHECK-NEXT: blr +; CHECK-NEXT: .LBB1_2: # %entry +; CHECK-NEXT: bl __stack_chk_fail +; CHECK-NEXT: nop +; +; CHECK-AIX64-LABEL: test_kill_canary_ssp: +; CHECK-AIX64: # %bb.0: # %entry +; CHECK-AIX64-NEXT: mflr r0 +; CHECK-AIX64-NEXT: std r0, 16(r1) +; CHECK-AIX64-NEXT: stdu r1, -128(r1) +; CHECK-AIX64-NEXT: ld r3, L..C0(r2) # @__ssp_canary_word +; CHECK-AIX64-NEXT: ld r4, 0(r3) +; CHECK-AIX64-NEXT: std r4, 120(r1) +; CHECK-AIX64-NEXT: ld r4, 0(r3) +; CHECK-AIX64-NEXT: not r4, r4 +; CHECK-AIX64-NEXT: std r4, 120(r1) +; CHECK-AIX64-NEXT: ld r3, 0(r3) +; CHECK-AIX64-NEXT: ld r4, 120(r1) +; CHECK-AIX64-NEXT: cmpld r3, r4 +; CHECK-AIX64-NEXT: bne cr0, L..BB1_2 +; CHECK-AIX64-NEXT: # %bb.1: # %entry +; CHECK-AIX64-NEXT: addi r1, r1, 128 +; CHECK-AIX64-NEXT: ld r0, 16(r1) +; CHECK-AIX64-NEXT: mtlr r0 +; CHECK-AIX64-NEXT: blr +; CHECK-AIX64-NEXT: L..BB1_2: # %entry +; CHECK-AIX64-NEXT: bl .__stack_chk_fail[PR] +; CHECK-AIX64-NEXT: nop +; +; CHECK-LINUX-LE-LABEL: test_kill_canary_ssp: +; CHECK-LINUX-LE: # %bb.0: # %entry +; CHECK-LINUX-LE-NEXT: mflr r0 +; CHECK-LINUX-LE-NEXT: std r0, 16(r1) +; CHECK-LINUX-LE-NEXT: stdu r1, -48(r1) +; CHECK-LINUX-LE-NEXT: ld r3, -28688(r13) +; CHECK-LINUX-LE-NEXT: std r3, 40(r1) +; CHECK-LINUX-LE-NEXT: ld r3, -28688(r13) +; CHECK-LINUX-LE-NEXT: not r3, r3 +; CHECK-LINUX-LE-NEXT: std r3, 40(r1) +; CHECK-LINUX-LE-NEXT: ld r3, 40(r1) +; CHECK-LINUX-LE-NEXT: ld r4, -28688(r13) +; CHECK-LINUX-LE-NEXT: cmpld r4, r3 +; CHECK-LINUX-LE-NEXT: bne cr0, .LBB1_2 +; CHECK-LINUX-LE-NEXT: # %bb.1: # %entry +; CHECK-LINUX-LE-NEXT: addi r1, r1, 48 +; CHECK-LINUX-LE-NEXT: ld r0, 16(r1) +; CHECK-LINUX-LE-NEXT: mtlr r0 +; CHECK-LINUX-LE-NEXT: blr +; CHECK-LINUX-LE-NEXT: .LBB1_2: # %entry +; CHECK-LINUX-LE-NEXT: bl __stack_chk_fail +; CHECK-LINUX-LE-NEXT: nop +; +; CHECK-AIX-FAST-LABEL: test_kill_canary_ssp: +; CHECK-AIX-FAST: # %bb.0: # %entry +; CHECK-AIX-FAST-NEXT: mflr r0 +; CHECK-AIX-FAST-NEXT: stw r0, 8(r1) +; CHECK-AIX-FAST-NEXT: stwu r1, -64(r1) +; CHECK-AIX-FAST-NEXT: lwz r3, L..C0(r2) # @__ssp_canary_word +; CHECK-AIX-FAST-NEXT: lwz r4, 0(r3) +; CHECK-AIX-FAST-NEXT: stw r4, 60(r1) +; CHECK-AIX-FAST-NEXT: lwz r4, 0(r3) +; CHECK-AIX-FAST-NEXT: not r4, r4 +; CHECK-AIX-FAST-NEXT: stw r4, 60(r1) +; CHECK-AIX-FAST-NEXT: lwz r3, 0(r3) +; CHECK-AIX-FAST-NEXT: lwz r4, 60(r1) +; CHECK-AIX-FAST-NEXT: cmplw r3, r4 +; CHECK-AIX-FAST-NEXT: bne cr0, L..BB1_2 +; CHECK-AIX-FAST-NEXT: b L..BB1_1 +; CHECK-AIX-FAST-NEXT: L..BB1_1: # %SP_return +; CHECK-AIX-FAST-NEXT: addi r1, r1, 64 +; CHECK-AIX-FAST-NEXT: lwz r0, 8(r1) +; CHECK-AIX-FAST-NEXT: mtlr r0 +; CHECK-AIX-FAST-NEXT: blr +; CHECK-AIX-FAST-NEXT: L..BB1_2: # %CallStackCheckFailBlk +; CHECK-AIX-FAST-NEXT: bl .__stack_chk_fail[PR] +; CHECK-AIX-FAST-NEXT: nop +; +; CHECK-FAST-LABEL: test_kill_canary_ssp: +; CHECK-FAST: # %bb.0: # %entry +; CHECK-FAST-NEXT: mflr r0 +; CHECK-FAST-NEXT: std r0, 16(r1) +; CHECK-FAST-NEXT: stdu r1, -128(r1) +; CHECK-FAST-NEXT: ld r3, -28688(r13) +; CHECK-FAST-NEXT: ld r3, -28688(r13) +; CHECK-FAST-NEXT: std r3, 120(r1) +; CHECK-FAST-NEXT: ld r3, -28688(r13) +; CHECK-FAST-NEXT: not r3, r3 +; CHECK-FAST-NEXT: li r5, -1 +; CHECK-FAST-NEXT: addi r4, r1, 120 +; CHECK-FAST-NEXT: stdx r3, r4, r5 +; CHECK-FAST-NEXT: ld r3, -28688(r13) +; CHECK-FAST-NEXT: ld r4, 120(r1) +; CHECK-FAST-NEXT: cmpd r3, r4 +; CHECK-FAST-NEXT: bne cr0, .LBB1_2 +; CHECK-FAST-NEXT: # %bb.1: # %SP_return +; CHECK-FAST-NEXT: addi r1, r1, 128 +; CHECK-FAST-NEXT: ld r0, 16(r1) +; CHECK-FAST-NEXT: mtlr r0 +; CHECK-FAST-NEXT: blr +; CHECK-FAST-NEXT: .LBB1_2: # %CallStackCheckFailBlk +; CHECK-FAST-NEXT: bl __stack_chk_fail +; CHECK-FAST-NEXT: nop +entry: + call void @llvm.ppc.kill.canary() + ret void +}