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 @@ -165,6 +165,8 @@ BUILTIN(__builtin_ppc_get_timebase, "ULLi", "n") +BUILTIN(__builtin_ppc_kill_canary, "v", "") + // This is just a placeholder, the types and attributes are wrong. BUILTIN(__builtin_altivec_vaddcuw, "V4UiV4UiV4Ui", "") 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 -O2 -triple powerpc64-unknown-linux-gnu \ +// RUN: -emit-llvm %s -o - -target-cpu pwr7 | \ +// RUN: FileCheck %s +// RUN: %clang_cc1 -O2 -triple powerpc64le-unknown-linux-gnu \ +// RUN: -emit-llvm %s -o - -target-cpu pwr8 | \ +// RUN: FileCheck %s +// RUN: %clang_cc1 -O2 -triple powerpc-unknown-aix \ +// RUN: -emit-llvm %s -o - -target-cpu pwr7 | \ +// RUN: FileCheck %s +// RUN: %clang_cc1 -O2 -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 @@ -217,6 +217,11 @@ : Intrinsic<[llvm_float_ty], [llvm_float_ty, llvm_float_ty, llvm_float_ty, llvm_vararg_ty], [IntrNoMem]>; + def int_ppc_kill_canary + : GCCBuiltin<"__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/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp --- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -5010,6 +5010,7 @@ case ISD::INTRINSIC_VOID: { auto IntrinsicID = N->getConstantOperandVal(1); + if (IntrinsicID == Intrinsic::ppc_tdw || IntrinsicID == Intrinsic::ppc_tw) { unsigned Opcode = IntrinsicID == Intrinsic::ppc_tdw ? PPC::TDI : PPC::TWI; SDValue Ops[] = {N->getOperand(4), N->getOperand(2), N->getOperand(3)}; 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 @@ -58,6 +58,7 @@ #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/ValueTypes.h" +#include "llvm/CodeGen/GlobalISel/IRTranslator.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" @@ -11127,6 +11128,51 @@ } break; } + case Intrinsic::ppc_kill_canary: { + MachineFunction &MF = DAG.getMachineFunction(); + if (MF.getFunction().hasFnAttribute(Attribute::SafeStack) || + !MF.getFunction().hasStackProtectorFnAttr()) { + DAG.ReplaceAllUsesOfValueWith(SDValue(Op.getNode(), 0), Op->getOperand(0)); + break; + } + + const Module *M = MF.getMMI().getModule(); + GlobalValue *GV = (Subtarget.isAIXABI()) ? + M->getGlobalVariable(AIXSSPCanaryWordName) : M->getNamedValue("__stack_chk_guard"); + + if(GV == nullptr) { + DAG.ReplaceAllUsesOfValueWith(SDValue(Op.getNode(), 0), Op->getOperand(0)); + break; + } + EVT VT = DAG.getTargetLoweringInfo().getValueType(DAG.getDataLayout(), GV->getType(), true); + SDValue canaryLoc = DAG.getGlobalAddress(GV, DL, VT); + + const uint64_t XORWord = 0xFFFFFFFF; // XORing with 0b111...111 will never result in the + // original word + + SDValue Load = DAG.getLoad( + VT, + DL, + Op->getOperand(0), + canaryLoc, + MachinePointerInfo() + ); + + SDValue Store = DAG.getStore( + Op->getOperand(0), + DL, + DAG.getNode( + ISD::XOR, + DL, + VT, + Load, + DAG.getConstant(XORWord, DL, VT) + ), + canaryLoc, + MachinePointerInfo() + ); + return Store; + } default: break; } diff --git a/llvm/test/CodeGen/PowerPC/kill-canary-intrinsic-aix.ll b/llvm/test/CodeGen/PowerPC/kill-canary-intrinsic-aix.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/kill-canary-intrinsic-aix.ll @@ -0,0 +1,46 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-aix \ +; RUN: --ppc-asm-full-reg-names < %s | FileCheck %s + +declare void @llvm.ppc.kill.canary() +define dso_local void @test_kill_canary() { +; CHECK-LABEL: test_kill_canary: +; CHECK: # %bb.0: # %entry +; CHECK-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 { +; 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, L..C0(r2) # @__ssp_canary_word +; CHECK-NEXT: ld r4, 0(r3) +; CHECK-NEXT: std r4, 120(r1) +; CHECK-NEXT: ld r4, 0(r3) +; CHECK-NEXT: xori r4, r4, 65535 +; CHECK-NEXT: xoris r4, r4, 65535 +; CHECK-NEXT: std r4, 0(r3) +; CHECK-NEXT: ld r3, 0(r3) +; CHECK-NEXT: ld r4, 120(r1) +; CHECK-NEXT: cmpld r3, r4 +; CHECK-NEXT: bne cr0, L..BB1_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: L..BB1_2: # %entry +; CHECK-NEXT: bl .__stack_chk_fail[PR] +; CHECK-NEXT: nop +entry: + call void @llvm.ppc.kill.canary() + ret void +} + diff --git a/llvm/test/CodeGen/PowerPC/kill-canary-intrinsic-linux.ll b/llvm/test/CodeGen/PowerPC/kill-canary-intrinsic-linux.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/kill-canary-intrinsic-linux.ll @@ -0,0 +1,43 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux \ +; RUN: --ppc-asm-full-reg-names < %s | FileCheck %s + +declare void @llvm.ppc.kill.canary() +define dso_local void @test_kill_canary() { +; CHECK-LABEL: test_kill_canary: +; CHECK: # %bb.0: # %entry +; CHECK-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 { +; 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: .cfi_def_cfa_offset 128 +; CHECK-NEXT: .cfi_offset lr, 16 +; CHECK-NEXT: ld r3, -28688(r13) +; 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 +entry: + call void @llvm.ppc.kill.canary() + ret void +} +