Skip to content

Commit cebe824

Browse files
committedJun 22, 2017
[X86] Add support for "probe-stack" attribute
This commit adds prologue code emission for stack probe function calls. Reviewed By: majnemer Differential Revision: https://reviews.llvm.org/D34387 llvm-svn: 306010
1 parent 5991b5b commit cebe824

File tree

6 files changed

+93
-19
lines changed

6 files changed

+93
-19
lines changed
 

‎llvm/include/llvm/Target/TargetLowering.h

+6
Original file line numberDiff line numberDiff line change
@@ -1374,6 +1374,12 @@ class TargetLoweringBase {
13741374
/// Returns the target-specific address of the unsafe stack pointer.
13751375
virtual Value *getSafeStackPointerLocation(IRBuilder<> &IRB) const;
13761376

1377+
/// Returns the name of the symbol used to emit stack probes or the empty
1378+
/// string if not applicable.
1379+
virtual StringRef getStackProbeSymbolName(MachineFunction &MF) const {
1380+
return "";
1381+
}
1382+
13771383
/// Returns true if a cast between SrcAS and DestAS is a noop.
13781384
virtual bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const {
13791385
return false;

‎llvm/lib/Target/X86/X86FrameLowering.cpp

+14-18
Original file line numberDiff line numberDiff line change
@@ -748,17 +748,7 @@ void X86FrameLowering::emitStackProbeCall(MachineFunction &MF,
748748
else
749749
CallOp = X86::CALLpcrel32;
750750

751-
const char *Symbol;
752-
if (Is64Bit) {
753-
if (STI.isTargetCygMing()) {
754-
Symbol = "___chkstk_ms";
755-
} else {
756-
Symbol = "__chkstk";
757-
}
758-
} else if (STI.isTargetCygMing())
759-
Symbol = "_alloca";
760-
else
761-
Symbol = "_chkstk";
751+
StringRef Symbol = STI.getTargetLowering()->getStackProbeSymbolName(MF);
762752

763753
MachineInstrBuilder CI;
764754
MachineBasicBlock::iterator ExpansionMBBI = std::prev(MBBI);
@@ -769,10 +759,11 @@ void X86FrameLowering::emitStackProbeCall(MachineFunction &MF,
769759
// For the large code model, we have to call through a register. Use R11,
770760
// as it is scratch in all supported calling conventions.
771761
BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64ri), X86::R11)
772-
.addExternalSymbol(Symbol);
762+
.addExternalSymbol(MF.createExternalSymbolName(Symbol));
773763
CI = BuildMI(MBB, MBBI, DL, TII.get(CallOp)).addReg(X86::R11);
774764
} else {
775-
CI = BuildMI(MBB, MBBI, DL, TII.get(CallOp)).addExternalSymbol(Symbol);
765+
CI = BuildMI(MBB, MBBI, DL, TII.get(CallOp))
766+
.addExternalSymbol(MF.createExternalSymbolName(Symbol));
776767
}
777768

778769
unsigned AX = Is64Bit ? X86::RAX : X86::EAX;
@@ -783,13 +774,13 @@ void X86FrameLowering::emitStackProbeCall(MachineFunction &MF,
783774
.addReg(SP, RegState::Define | RegState::Implicit)
784775
.addReg(X86::EFLAGS, RegState::Define | RegState::Implicit);
785776

786-
if (Is64Bit) {
777+
if (!STI.isTargetWin32()) {
787778
// MSVC x64's __chkstk and cygwin/mingw's ___chkstk_ms do not adjust %rsp
788779
// themselves. It also does not clobber %rax so we can reuse it when
789780
// adjusting %rsp.
790-
BuildMI(MBB, MBBI, DL, TII.get(X86::SUB64rr), X86::RSP)
791-
.addReg(X86::RSP)
792-
.addReg(X86::RAX);
781+
BuildMI(MBB, MBBI, DL, TII.get(getSUBrrOpcode(Is64Bit)), SP)
782+
.addReg(SP)
783+
.addReg(AX);
793784
}
794785

795786
if (InProlog) {
@@ -978,7 +969,8 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
978969
X86FI->setCalleeSavedFrameSize(
979970
X86FI->getCalleeSavedFrameSize() - TailCallReturnAddrDelta);
980971

981-
bool UseStackProbe = (STI.isOSWindows() && !STI.isTargetMachO());
972+
bool UseRedZone = false;
973+
bool UseStackProbe = !STI.getTargetLowering()->getStackProbeSymbolName(MF).empty();
982974

983975
// The default stack probe size is 4096 if the function has no stackprobesize
984976
// attribute.
@@ -1007,6 +999,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
1007999
!TRI->needsStackRealignment(MF) &&
10081000
!MFI.hasVarSizedObjects() && // No dynamic alloca.
10091001
!MFI.adjustsStack() && // No calls.
1002+
!UseStackProbe && // No stack probes.
10101003
!IsWin64CC && // Win64 has no Red Zone
10111004
!MFI.hasCopyImplyingStackAdjustment() && // Don't push and pop.
10121005
!MF.shouldSplitStack()) { // Regular stack
@@ -1015,6 +1008,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
10151008
X86FI->setUsesRedZone(MinSize > 0 || StackSize > 0);
10161009
StackSize = std::max(MinSize, StackSize > 128 ? StackSize - 128 : 0);
10171010
MFI.setStackSize(StackSize);
1011+
UseRedZone = true;
10181012
}
10191013

10201014
// Insert stack pointer adjustment for later moving of return addr. Only
@@ -1192,6 +1186,8 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
11921186
if (IsWin64Prologue && !IsFunclet && TRI->needsStackRealignment(MF))
11931187
AlignedNumBytes = alignTo(AlignedNumBytes, MaxAlign);
11941188
if (AlignedNumBytes >= StackProbeSize && UseStackProbe) {
1189+
assert(!UseRedZone && "The Red Zone is not accounted for in stack probes");
1190+
11951191
// Check whether EAX is livein for this block.
11961192
bool isEAXAlive = isEAXLiveIn(MBB);
11971193

‎llvm/lib/Target/X86/X86ISelLowering.cpp

+21-1
Original file line numberDiff line numberDiff line change
@@ -18651,8 +18651,9 @@ X86TargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
1865118651
SelectionDAG &DAG) const {
1865218652
MachineFunction &MF = DAG.getMachineFunction();
1865318653
bool SplitStack = MF.shouldSplitStack();
18654+
bool EmitStackProbe = !getStackProbeSymbolName(MF).empty();
1865418655
bool Lower = (Subtarget.isOSWindows() && !Subtarget.isTargetMachO()) ||
18655-
SplitStack;
18656+
SplitStack || EmitStackProbe;
1865618657
SDLoc dl(Op);
1865718658

1865818659
// Get the inputs.
@@ -36390,3 +36391,22 @@ void X86TargetLowering::insertCopiesSplitCSR(
3639036391
bool X86TargetLowering::supportSwiftError() const {
3639136392
return Subtarget.is64Bit();
3639236393
}
36394+
36395+
/// Returns the name of the symbol used to emit stack probes or the empty
36396+
/// string if not applicable.
36397+
StringRef X86TargetLowering::getStackProbeSymbolName(MachineFunction &MF) const {
36398+
// If the function specifically requests stack probes, emit them.
36399+
if (MF.getFunction()->hasFnAttribute("probe-stack"))
36400+
return MF.getFunction()->getFnAttribute("probe-stack").getValueAsString();
36401+
36402+
// Generally, if we aren't on Windows, the platform ABI does not include
36403+
// support for stack probes, so don't emit them.
36404+
if (!Subtarget.isOSWindows() || Subtarget.isTargetMachO())
36405+
return "";
36406+
36407+
// We need a stack probe to conform to the Windows ABI. Choose the right
36408+
// symbol.
36409+
if (Subtarget.is64Bit())
36410+
return Subtarget.isTargetCygMing() ? "___chkstk_ms" : "__chkstk";
36411+
return Subtarget.isTargetCygMing() ? "_alloca" : "_chkstk";
36412+
}

‎llvm/lib/Target/X86/X86ISelLowering.h

+2
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,8 @@ namespace llvm {
10591059

10601060
bool supportSwiftError() const override;
10611061

1062+
StringRef getStackProbeSymbolName(MachineFunction &MF) const override;
1063+
10621064
unsigned getMaxSupportedInterleaveFactor() const override { return 4; }
10631065

10641066
/// \brief Lower interleaved load(s) into target specific
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
; RUN: llc -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s
2+
3+
; Ensure that red zone usage occurs.
4+
define void @testStackProbesOff() {
5+
%array = alloca [40096 x i8], align 16
6+
ret void
7+
8+
; CHECK-LABEL: testStackProbesOff:
9+
; CHECK: subq $39976, %rsp # imm = 0x9C28
10+
}
11+
12+
; Ensure stack probes do not result in red zone usage.
13+
define void @testStackProbesOn() "probe-stack"="__probestack" {
14+
%array = alloca [40096 x i8], align 16
15+
ret void
16+
17+
; CHECK-LABEL: testStackProbesOn:
18+
; CHECK: movl $40104, %eax # imm = 0x9CA8
19+
; CHECK-NEXT: callq __probestack
20+
; CHECK-NEXT: subq %rax, %rsp
21+
}

‎llvm/test/CodeGen/X86/stack-probes.ll

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
; RUN: llc -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck --check-prefix=X86-LINUX %s
2+
; RUN: llc -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck --check-prefix=X64-LINUX %s
3+
; RUN: llc -mtriple=x86_64-pc-linux-gnu -code-model=large < %s -o - | FileCheck --check-prefix=X64-LINUX-LARGE %s
4+
5+
declare void @use([40096 x i8]*)
6+
7+
; Ensure calls to __probestack occur for large stack frames
8+
define void @test() "probe-stack"="__probestack" {
9+
%array = alloca [40096 x i8], align 16
10+
call void @use([40096 x i8]* %array)
11+
ret void
12+
13+
; X86-LINUX-LABEL: test:
14+
; X86-LINUX: movl $40124, %eax # imm = 0x9CBC
15+
; X86-LINUX-NEXT: calll __probestack
16+
; X86-LINUX-NEXT: subl %eax, %esp
17+
18+
; X64-LINUX-LABEL: test:
19+
; X64-LINUX: movl $40104, %eax # imm = 0x9CA8
20+
; X64-LINUX-NEXT: callq __probestack
21+
; X64-LINUX-NEXT: subq %rax, %rsp
22+
23+
; X64-LINUX-LARGE-LABEL: test:
24+
; X64-LINUX-LARGE: movl $40104, %eax # imm = 0x9CA8
25+
; X64-LINUX-LARGE-NEXT: movabsq $__probestack, %r11
26+
; X64-LINUX-LARGE-NEXT: callq *%r11
27+
; X64-LINUX-LARGE-NEXT: subq %rax, %rsp
28+
29+
}

0 commit comments

Comments
 (0)
Please sign in to comment.