Index: include/llvm/CodeGen/CommandFlags.h =================================================================== --- include/llvm/CodeGen/CommandFlags.h +++ include/llvm/CodeGen/CommandFlags.h @@ -174,6 +174,11 @@ cl::desc("Override default stack alignment"), cl::init(0)); +cl::opt +OverrideStackProbeSize("stack-probe-size", + cl::desc("Override default stack probe size"), + cl::init(0)); + cl::opt TrapFuncName("trap-func", cl::Hidden, cl::desc("Emit a call to trap function rather than a trap instruction"), @@ -284,6 +289,8 @@ Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; Options.DisableTailCalls = DisableTailCalls; Options.StackAlignmentOverride = OverrideStackAlignment; + Options.IsStackProbeSizeOverridden = (OverrideStackProbeSize.getNumOccurrences() > 0); + Options.StackProbeSizeOverride = OverrideStackProbeSize; Options.TrapFuncName = TrapFuncName; Options.ABIName = ABIName; Options.PositionIndependentExecutable = EnablePIE; Index: include/llvm/Target/TargetOptions.h =================================================================== --- include/llvm/Target/TargetOptions.h +++ include/llvm/Target/TargetOptions.h @@ -75,6 +75,7 @@ NoZerosInBSS(false), JITEmitDebugInfo(false), JITEmitDebugInfoToDisk(false), GuaranteedTailCallOpt(false), DisableTailCalls(false), StackAlignmentOverride(0), + IsStackProbeSizeOverridden(false), StackProbeSizeOverride(0), EnableFastISel(false), PositionIndependentExecutable(false), UseInitArray(false), DisableIntegratedAS(false), CompressDebugSections(false), FunctionSections(false), @@ -171,6 +172,15 @@ /// StackAlignmentOverride - Override default stack alignment for target. unsigned StackAlignmentOverride; + /// IsStackProbeSizeOverridden - Specifies whether the default stack probe + /// probe size should be used or the value which is specified by + /// StackProbeSizeOverride. This is needed as 0 is a valid value for + /// StackProbeSizeOverride. + bool IsStackProbeSizeOverridden; + + /// StackProbeSizeOverride - Override default stack probe size for target. + unsigned StackProbeSizeOverride; + /// EnableFastISel - This flag enables fast-path instruction selection /// which trades away generated code quality in favor of reducing /// compile time. @@ -287,6 +297,8 @@ ARE_EQUAL(GuaranteedTailCallOpt) && ARE_EQUAL(DisableTailCalls) && ARE_EQUAL(StackAlignmentOverride) && + ARE_EQUAL(IsStackProbeSizeOverridden) && + ARE_EQUAL(StackProbeSizeOverride) && ARE_EQUAL(EnableFastISel) && ARE_EQUAL(PositionIndependentExecutable) && ARE_EQUAL(UseInitArray) && Index: lib/Target/X86/X86FrameLowering.cpp =================================================================== --- lib/Target/X86/X86FrameLowering.cpp +++ lib/Target/X86/X86FrameLowering.cpp @@ -501,6 +501,7 @@ !IsWinEH && (MMI.hasDebugInfo() || Fn->needsUnwindTableEntry()); bool UseLEA = STI.useLeaForSP(); unsigned StackAlign = getStackAlignment(); + unsigned StackProbeSize = STI.getStackProbeSize(); unsigned SlotSize = RegInfo->getSlotSize(); unsigned FramePtr = RegInfo->getFrameRegister(MF); const unsigned MachineFramePtr = STI.isTarget64BitILP32() ? @@ -705,8 +706,6 @@ // Adjust stack pointer: ESP -= numbytes. - static const size_t PageSize = 4096; - // Windows and cygwin/mingw require a prologue helper routine when allocating // more than 4K bytes on the stack. Windows uses __chkstk and cygwin/mingw // uses __alloca. __alloca and the 32-bit version of __chkstk will probe the @@ -715,7 +714,7 @@ // responsible for adjusting the stack pointer. Touching the stack at 4K // increments is necessary to ensure that the guard pages used by the OS // virtual memory manager are allocated in correct sequence. - if (NumBytes >= PageSize && UseStackProbe) { + if (NumBytes >= StackProbeSize && UseStackProbe) { const char *StackProbeSymbol; unsigned CallOp; Index: lib/Target/X86/X86Subtarget.h =================================================================== --- lib/Target/X86/X86Subtarget.h +++ lib/Target/X86/X86Subtarget.h @@ -231,6 +231,10 @@ /// entry to the function and which must be maintained by every function. unsigned stackAlignment; + /// stackProbeSize - When exceeding the stack probe size, stack probing + /// functions are inserted if the target requires them. + unsigned stackProbeSize; + /// Max. memset / memcpy size that is turned into rep/movs, rep/stos ops. /// unsigned MaxInlineSizeThreshold; @@ -248,6 +252,12 @@ /// StackAlignOverride - Override the stack alignment. unsigned StackAlignOverride; + /// IsStackProbeSizeOverridden - Is the stack probe size overridden. + bool IsStackProbeSizeOverridden; + + /// StackProbeSizeOverride - The value of the overridden stack probe size. + unsigned StackProbeSizeOverride; + /// In64BitMode - True if compiling for 64-bit, false for 16-bit or 32-bit. bool In64BitMode; @@ -270,7 +280,9 @@ /// X86Subtarget(const std::string &TT, const std::string &CPU, const std::string &FS, const X86TargetMachine &TM, - unsigned StackAlignOverride); + unsigned StackAlignOverride, + bool IsStackProbeSizeOverridden, + unsigned StackProbeSizeOverride); const X86TargetLowering *getTargetLowering() const override { return &TLInfo; @@ -292,6 +304,10 @@ /// function for this subtarget. unsigned getStackAlignment() const { return stackAlignment; } + /// getStackProbeSize - Returns the maximum size of stack memory that can be + /// safely accessed without calling stack probing functions. + unsigned getStackProbeSize() const { return stackProbeSize; } + /// getMaxInlineSizeThreshold - Returns the maximum memset / memcpy size /// that still makes it profitable to inline the call. unsigned getMaxInlineSizeThreshold() const { return MaxInlineSizeThreshold; } Index: lib/Target/X86/X86Subtarget.cpp =================================================================== --- lib/Target/X86/X86Subtarget.cpp +++ lib/Target/X86/X86Subtarget.cpp @@ -225,9 +225,15 @@ else if (isTargetDarwin() || isTargetLinux() || isTargetSolaris() || In64BitMode) stackAlignment = 16; + + if (IsStackProbeSizeOverridden) + stackProbeSize = StackProbeSizeOverride; } void X86Subtarget::initializeEnvironment() { + // The page size is 4096 bytes for all targets. + static const size_t PageSize = 4096; + X86SSELevel = NoMMXSSE; X863DNowLevel = NoThreeDNow; HasCMov = false; @@ -278,6 +284,10 @@ UseSqrtEst = false; UseReciprocalEst = false; stackAlignment = 4; + + // By default, the stack probe size is equal to the page size. + stackProbeSize = PageSize; + // FIXME: this is a known good value for Yonah. How about others? MaxInlineSizeThreshold = 128; } @@ -331,11 +341,15 @@ X86Subtarget::X86Subtarget(const std::string &TT, const std::string &CPU, const std::string &FS, const X86TargetMachine &TM, - unsigned StackAlignOverride) + unsigned StackAlignOverride, + bool IsStackProbeSizeOverridden, + unsigned StackProbeSizeOverride) : X86GenSubtargetInfo(TT, CPU, FS), X86ProcFamily(Others), PICStyle(PICStyles::None), TargetTriple(TT), DL(computeDataLayout(TargetTriple)), StackAlignOverride(StackAlignOverride), + IsStackProbeSizeOverridden(IsStackProbeSizeOverridden), + StackProbeSizeOverride(StackProbeSizeOverride), In64BitMode(TargetTriple.getArch() == Triple::x86_64), In32BitMode(TargetTriple.getArch() == Triple::x86 && TargetTriple.getEnvironment() != Triple::CODE16), Index: lib/Target/X86/X86TargetMachine.cpp =================================================================== --- lib/Target/X86/X86TargetMachine.cpp +++ lib/Target/X86/X86TargetMachine.cpp @@ -55,7 +55,10 @@ CodeGenOpt::Level OL) : LLVMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL), TLOF(createTLOF(Triple(getTargetTriple()))), - Subtarget(TT, CPU, FS, *this, Options.StackAlignmentOverride) { + Subtarget(TT, CPU, FS, *this, + Options.StackAlignmentOverride, + Options.IsStackProbeSizeOverridden, + Options.StackProbeSizeOverride) { // default to hard float ABI if (Options.FloatABIType == FloatABI::Default) this->Options.FloatABIType = FloatABI::Hard; @@ -106,7 +109,9 @@ // function that reside in TargetOptions. resetTargetOptions(F); I = llvm::make_unique(TargetTriple, CPU, FS, *this, - Options.StackAlignmentOverride); + Options.StackAlignmentOverride, + Options.IsStackProbeSizeOverridden, + Options.StackProbeSizeOverride); } return I.get(); } Index: test/CodeGen/X86/stack-probe-size.ll =================================================================== --- test/CodeGen/X86/stack-probe-size.ll +++ test/CodeGen/X86/stack-probe-size.ll @@ -0,0 +1,58 @@ +; This test is attempting to detect that the compiler correctly generates stack +; probe calls when the size of the local variables exceeds the specified stack +; probe size. +; +; Testing the default value of 4096 bytes makes sense, because the default +; stack probe size equals the page size (4096 bytes for all x86 targets), and +; this is unlikely to change in the future. +; +; RUN: llc < %s -stack-probe-size=0 | FileCheck %s -check-prefix=SMALL_STACK_PROBE_SIZE +; RUN: llc < %s | FileCheck %s -check-prefix=DEFAULT_STACK_PROBE_SIZE +; RUN: llc < %s -stack-probe-size=8192 | FileCheck %s -check-prefix=LARGE_STACK_PROBE_SIZE + +target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32" +target triple = "i686-pc-windows-msvc" + +; Function Attrs: nounwind +define i32 @test1() #0 { + %buffer = alloca [4095 x i8] + + ret i32 0 + +; SMALL_STACK_PROBE_SIZE-LABEL: _test1: +; SMALL_STACK_PROBE_SIZE-NOT: subl $4095, %esp +; SMALL_STACK_PROBE_SIZE: movl $4095, %eax +; SMALL_STACK_PROBE_SIZE: calll __chkstk + +; DEFAULT_STACK_PROBE_SIZE-LABEL: _test1: +; DEFAULT_STACK_PROBE_SIZE-NOT: movl $4095, %eax +; DEFAULT_STACK_PROBE_SIZE: subl $4095, %esp +; DEFAULT_STACK_PROBE_SIZE-NOT: calll __chkstk + +; LARGE_STACK_PROBE_SIZE-LABEL: _test1: +; LARGE_STACK_PROBE_SIZE-NOT: movl $4095, %eax +; LARGE_STACK_PROBE_SIZE: subl $4095, %esp +; LARGE_STACK_PROBE_SIZE-NOT: calll __chkstk +} + +; Function Attrs: nounwind +define i32 @test2() #0 { + %buffer = alloca [4096 x i8] + + ret i32 0 + +; SMALL_STACK_PROBE_SIZE-LABEL: _test2: +; SMALL_STACK_PROBE_SIZE-NOT: subl $4096, %esp +; SMALL_STACK_PROBE_SIZE: movl $4096, %eax +; SMALL_STACK_PROBE_SIZE: calll __chkstk + +; DEFAULT_STACK_PROBE_SIZE-LABEL: _test2: +; DEFAULT_STACK_PROBE_SIZE-NOT: subl $4096, %esp +; DEFAULT_STACK_PROBE_SIZE: movl $4096, %eax +; DEFAULT_STACK_PROBE_SIZE: calll __chkstk + +; LARGE_STACK_PROBE_SIZE-LABEL: _test2: +; LARGE_STACK_PROBE_SIZE-NOT: movl $4096, %eax +; LARGE_STACK_PROBE_SIZE: subl $4096, %esp +; LARGE_STACK_PROBE_SIZE-NOT: calll __chkstk +}