diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h --- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h +++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h @@ -994,6 +994,16 @@ return false; } + /// Allow targets to specify that a particular instruction is part of a + /// terminator sequence so that block splitting for the stack smashing + /// protector feature does not separate the instruction from the terminator. + /// This is for instructions such as the PowerPC MTCTR instruction that + /// is clearly not a COPY but sets up the CTR register that a subsequent + /// branch uses. + virtual bool isPartOfTerminatorSequence(const MachineInstr &MI) const { + return false; + } + protected: /// Target-dependent implementation for IsCopyInstr. /// If the specific machine instruction is a instruction that moves/copies diff --git a/llvm/lib/CodeGen/CodeGenCommonISel.cpp b/llvm/lib/CodeGen/CodeGenCommonISel.cpp --- a/llvm/lib/CodeGen/CodeGenCommonISel.cpp +++ b/llvm/lib/CodeGen/CodeGenCommonISel.cpp @@ -160,7 +160,7 @@ return Previous; } - while (MIIsInTerminatorSequence(*Previous)) { + while (MIIsInTerminatorSequence(*Previous) || TII.isPartOfTerminatorSequence(*Previous)) { SplitPoint = Previous; if (Previous == Start) break; diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.h b/llvm/lib/Target/PowerPC/PPCInstrInfo.h --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.h +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.h @@ -793,6 +793,9 @@ /// conditions can be understood enough produce a PipelinerLoopInfo object. std::unique_ptr analyzeLoopForPipelining(MachineBasicBlock *LoopBB) const override; + bool isPartOfTerminatorSequence(const MachineInstr &MI) const override { + return MI.getOpcode() == PPC::MTCTR || MI.getOpcode() == PPC::MTCTR8; + } }; } diff --git a/llvm/test/CodeGen/PowerPC/safestack-indirect-tailcall.ll b/llvm/test/CodeGen/PowerPC/safestack-indirect-tailcall.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/safestack-indirect-tailcall.ll @@ -0,0 +1,82 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \ +; RUN: -mcpu=pwr10 -ppc-asm-full-reg-names \ +; RUN: -ppc-vsr-nums-as-vr < %s | FileCheck %s + +%0 = type { %1 } +%1 = type { { i64, i64 } } +%2 = type { %3, void (%0*, i32*)* } +%3 = type { %0, i1 (%0*, %0*, i32)* } + +$func2 = comdat any + +declare i32 @__gxx_personality_v0(...) + +define hidden void @main() local_unnamed_addr #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; CHECK-LABEL: main: +; CHECK: # %bb.0: # %bb +; CHECK-NEXT: mflr r0 +; CHECK-NEXT: std r0, 16(r1) +; CHECK-NEXT: stdu r1, -32(r1) +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: .cfi_offset lr, 16 +; CHECK-NEXT: paddi r3, 0, func2@PCREL, 1 +; CHECK-NEXT: std r3, 24(0) +; CHECK-NEXT: .Ltmp0: +; CHECK-NEXT: bl func1@notoc +; CHECK-NEXT: .Ltmp1: +; CHECK-NEXT: # %bb.1: # %bb1 +; CHECK-NEXT: .LBB0_2: # %bb2 +; CHECK-NEXT: .Ltmp2: +; CHECK-NEXT: bl _Unwind_Resume@notoc +bb: + %i = getelementptr inbounds %2, %2* null, i64 0, i32 1 + store void (%0*, i32*)* @func2, void (%0*, i32*)** %i, align 8 + invoke void @func1() + to label %bb1 unwind label %bb2 + +bb1: ; preds = %bb + unreachable + +bb2: ; preds = %bb + %i3 = landingpad { i8*, i32 } + cleanup + resume { i8*, i32 } undef +} + +declare hidden void @func1() local_unnamed_addr #0 + +; Function Attrs: sspreq +define hidden void @func2(%0* %arg, i32* %arg1) #1 comdat align 2 { +; CHECK-LABEL: func2: +; CHECK: # %bb.0: # %bb +; CHECK-NEXT: mflr r0 +; CHECK-NEXT: std r0, 16(r1) +; CHECK-NEXT: stdu r1, -48(r1) +; CHECK-NEXT: .cfi_def_cfa_offset 48 +; CHECK-NEXT: .cfi_offset lr, 16 +; CHECK-NEXT: ld r4, -28688(r13) +; CHECK-NEXT: std r4, 40(r1) +; CHECK-NEXT: ld r12, 0(r3) +; CHECK-NEXT: ld r3, 40(r1) +; CHECK-NEXT: ld r4, -28688(r13) +; CHECK-NEXT: cmpld r4, r3 +; CHECK-NEXT: bne cr0, .LBB1_2 +; CHECK-NEXT: # %bb.1: # %bb +; CHECK-NEXT: mtctr r12 +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: addi r1, r1, 48 +; CHECK-NEXT: ld r0, 16(r1) +; CHECK-NEXT: mtlr r0 +; CHECK-NEXT: bctr +; CHECK-NEXT: #TC_RETURNr8 ctr 0 +; CHECK-NEXT: .LBB1_2: # %bb +; CHECK-NEXT: bl __stack_chk_fail@notoc +bb: + %i = bitcast %0* %arg to void (i32)** + %i2 = load void (i32)*, void (i32)** %i, align 8 + tail call void %i2(i32 noundef signext undef) + ret void +} + +attributes #1 = { sspreq }