Index: include/llvm-c/Core.h =================================================================== --- include/llvm-c/Core.h +++ include/llvm-c/Core.h @@ -169,6 +169,7 @@ LLVMNonNullAttribute = 1ULL << 37, LLVMJumpTableAttribute = 1ULL << 38, LLVMDereferenceableAttribute = 1ULL << 39, + LLVMStackProbeSizeAttribute = 1ULL << 40, */ } LLVMAttribute; Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -376,7 +376,8 @@ ATTR_KIND_IN_ALLOCA = 38, ATTR_KIND_NON_NULL = 39, ATTR_KIND_JUMP_TABLE = 40, - ATTR_KIND_DEREFERENCEABLE = 41 + ATTR_KIND_DEREFERENCEABLE = 41, + ATTR_KIND_STACK_PROBE_SIZE = 42 }; enum ComdatSelectionKindCodes { 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/CodeGen/MachineFrameInfo.h =================================================================== --- include/llvm/CodeGen/MachineFrameInfo.h +++ include/llvm/CodeGen/MachineFrameInfo.h @@ -124,6 +124,9 @@ /// StackAlignment - The alignment of the stack. unsigned StackAlignment; + /// StackProbeSize - The stack probe size. + unsigned StackProbeSize; + /// StackRealignable - Can the stack be realigned. bool StackRealignable; @@ -247,10 +250,10 @@ bool HasMustTailInVarArgFunc; public: - explicit MachineFrameInfo(unsigned StackAlign, bool isStackRealign, - bool RealignOpt) - : StackAlignment(StackAlign), StackRealignable(isStackRealign), - RealignOption(RealignOpt) { + explicit MachineFrameInfo(unsigned StackAlign, unsigned StackProbeSize, + bool isStackRealign, bool RealignOpt) + : StackAlignment(StackAlign), StackProbeSize(StackProbeSize), + StackRealignable(isStackRealign), RealignOption(RealignOpt) { StackSize = NumFixedObjects = OffsetAdjustment = MaxAlignment = 0; HasVarSizedObjects = false; FrameAddressTaken = false; Index: include/llvm/IR/Attributes.h =================================================================== --- include/llvm/IR/Attributes.h +++ include/llvm/IR/Attributes.h @@ -103,6 +103,8 @@ ///< stored as log2 of alignment with +1 bias 0 ///< means unaligned (different from ///< alignstack=(1)) + StackProbeSize, ///< Size the local variables may occupy before a + ///< stack probe call is generated. StackProtect, ///< Stack protection. StackProtectReq, ///< Stack protection required. StackProtectStrong, ///< Strong Stack protection. @@ -134,6 +136,7 @@ /// alignment set. static Attribute getWithAlignment(LLVMContext &Context, uint64_t Align); static Attribute getWithStackAlignment(LLVMContext &Context, uint64_t Align); + static Attribute getWithStackProbeSize(LLVMContext &Context, uint64_t Size); static Attribute getWithDereferenceableBytes(LLVMContext &Context, uint64_t Bytes); @@ -181,6 +184,10 @@ /// alignment value. unsigned getStackAlignment() const; + /// \brief Returns the stack probe size field of an attribute as a byte + /// value. + unsigned getStackProbeSize() const; + /// \brief Returns the number of dereferenceable bytes from the /// dereferenceable attribute (or zero if unknown). uint64_t getDereferenceableBytes() const; @@ -323,6 +330,9 @@ /// \brief Get the stack alignment. unsigned getStackAlignment(unsigned Index) const; + /// \brief Get the stack alignment. + unsigned getStackProbeSize(unsigned Index) const; + /// \brief Get the number of dereferenceable bytes (or zero if unknown). uint64_t getDereferenceableBytes(unsigned Index) const; @@ -405,15 +415,19 @@ std::map TargetDepAttrs; uint64_t Alignment; uint64_t StackAlignment; + uint64_t StackProbeSize; uint64_t DerefBytes; public: - AttrBuilder() : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0) {} + AttrBuilder() : Attrs(0), Alignment(0), StackAlignment(0), StackProbeSize(0), + DerefBytes(0) {} explicit AttrBuilder(uint64_t Val) - : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0) { + : Attrs(0), Alignment(0), StackAlignment(0), StackProbeSize(0), + DerefBytes(0) { addRawValue(Val); } AttrBuilder(const Attribute &A) - : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0) { + : Attrs(0), Alignment(0), StackAlignment(0), StackProbeSize(0), + DerefBytes(0) { addAttribute(A); } AttrBuilder(AttributeSet AS, unsigned Idx); @@ -467,6 +481,9 @@ /// \brief Retrieve the stack alignment attribute, if it exists. uint64_t getStackAlignment() const { return StackAlignment; } + /// \brief Retrieve the stack probe size attribute, if it exists. + uint64_t getStackProbeSize() const { return StackProbeSize; } + /// \brief Retrieve the number of dereferenceable bytes, if the dereferenceable /// attribute exists (zero is returned otherwise). uint64_t getDereferenceableBytes() const { return DerefBytes; } @@ -479,6 +496,10 @@ /// the form used internally in Attribute. AttrBuilder &addStackAlignmentAttr(unsigned Align); + /// \brief This turns an int stack probe size into the form used internally + /// in Attribute. + AttrBuilder &addStackProbeSizeAttr(unsigned Size); + /// \brief This turns the number of dereferenceable bytes into the form used /// internally in Attribute. AttrBuilder &addDereferenceableAttr(uint64_t Bytes); Index: include/llvm/Target/TargetFrameLowering.h =================================================================== --- include/llvm/Target/TargetFrameLowering.h +++ include/llvm/Target/TargetFrameLowering.h @@ -45,14 +45,17 @@ private: StackDirection StackDir; unsigned StackAlignment; + unsigned StackProbeSize; unsigned TransientStackAlignment; int LocalAreaOffset; bool StackRealignable; public: - TargetFrameLowering(StackDirection D, unsigned StackAl, int LAO, + TargetFrameLowering(StackDirection D, unsigned StackAl, + unsigned StackProbeS, int LAO, unsigned TransAl = 1, bool StackReal = true) - : StackDir(D), StackAlignment(StackAl), TransientStackAlignment(TransAl), - LocalAreaOffset(LAO), StackRealignable(StackReal) {} + : StackDir(D), StackAlignment(StackAl), StackProbeSize(StackProbeS), + TransientStackAlignment(TransAl), LocalAreaOffset(LAO), + StackRealignable(StackReal) {} virtual ~TargetFrameLowering(); @@ -69,6 +72,11 @@ /// unsigned getStackAlignment() const { return StackAlignment; } + /// getStackProbeSize - This method returns the number of bytes which local + /// may occupy before a stack probe call is being generated. + /// + unsigned getStackProbeSize() const { return StackProbeSize; } + /// getTransientStackAlignment - This method returns the number of bytes to /// which the stack pointer must be aligned at all times, even between /// calls. 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 + /// 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/AsmParser/LLParser.h =================================================================== --- lib/AsmParser/LLParser.h +++ lib/AsmParser/LLParser.h @@ -229,6 +229,7 @@ AtomicOrdering &Ordering); bool ParseOrdering(AtomicOrdering &Ordering); bool ParseOptionalStackAlignment(unsigned &Alignment); + bool ParseOptionalStackProbeSize(unsigned &Size); bool ParseOptionalCommaAlign(unsigned &Alignment, bool &AteExtraComma); bool ParseOptionalCommaInAlloca(bool &IsInAlloca); bool ParseIndexList(SmallVectorImpl &Indices,bool &AteExtraComma); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -972,6 +972,20 @@ B.addStackAlignmentAttr(Alignment); continue; } + case lltok::kw_stackprobesize: { + unsigned Size; + if (inAttrGrp) { + Lex.Lex(); + if (ParseToken(lltok::equal, "expected '=' here") || + ParseUInt32(Size)) + return true; + } else { + if (ParseOptionalStackProbeSize(Size)) + return true; + } + B.addStackProbeSizeAttr(Size); + continue; + } case lltok::kw_alwaysinline: B.addAttribute(Attribute::AlwaysInline); break; case lltok::kw_builtin: B.addAttribute(Attribute::Builtin); break; case lltok::kw_cold: B.addAttribute(Attribute::Cold); break; @@ -1674,6 +1688,24 @@ return false; } +/// ParseOptionalStackProbeSize +/// ::= /* empty */ +/// ::= 'stackprobesize' '(' 4096 ')' +bool LLParser::ParseOptionalStackProbeSize(unsigned &Size) { + Size = 0; + if (!EatIfPresent(lltok::kw_stackprobesize)) + return false; + LocTy ParenLoc = Lex.getLoc(); + if (!EatIfPresent(lltok::lparen)) + return Error(ParenLoc, "expected '('"); + LocTy AlignLoc = Lex.getLoc(); + if (ParseUInt32(Size)) return true; + ParenLoc = Lex.getLoc(); + if (!EatIfPresent(lltok::rparen)) + return Error(ParenLoc, "expected ')'"); + return false; +} + /// ParseIndexList - This parses the index list for an insert/extractvalue /// instruction. This sets AteExtraComma in the case where we eat an extra /// comma at the end of the line and find that it is followed by metadata. Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -80,6 +80,7 @@ kw_asm, kw_sideeffect, kw_alignstack, + kw_stackprobesize, kw_inteldialect, kw_gc, kw_prefix, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -670,6 +670,8 @@ return Attribute::SExt; case bitc::ATTR_KIND_STACK_ALIGNMENT: return Attribute::StackAlignment; + case bitc::ATTR_KIND_STACK_PROBE_SIZE: + return Attribute::StackProbeSize; case bitc::ATTR_KIND_STACK_PROTECT: return Attribute::StackProtect; case bitc::ATTR_KIND_STACK_PROTECT_REQ: @@ -751,6 +753,8 @@ B.addAlignmentAttr(Record[++i]); else if (Kind == Attribute::StackAlignment) B.addStackAlignmentAttr(Record[++i]); + else if (Kind == Attribute::StackProbeSize) + B.addStackProbeSizeAttr(Record[++i]); else if (Kind == Attribute::Dereferenceable) B.addDereferenceableAttr(Record[++i]); } else { // String attribute Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -220,6 +220,8 @@ return bitc::ATTR_KIND_S_EXT; case Attribute::StackAlignment: return bitc::ATTR_KIND_STACK_ALIGNMENT; + case Attribute::StackProbeSize: + return bitc::ATTR_KIND_STACK_PROBE_SIZE; case Attribute::StackProtect: return bitc::ATTR_KIND_STACK_PROTECT; case Attribute::StackProtectReq: Index: lib/CodeGen/MachineFunction.cpp =================================================================== --- lib/CodeGen/MachineFunction.cpp +++ lib/CodeGen/MachineFunction.cpp @@ -64,6 +64,7 @@ MFInfo = nullptr; FrameInfo = new (Allocator) MachineFrameInfo(STI->getFrameLowering()->getStackAlignment(), + STI->getFrameLowering()->getStackProbeSize(), STI->getFrameLowering()->isStackRealignable(), !F->hasFnAttribute("no-realign-stack")); Index: lib/IR/AttributeImpl.h =================================================================== --- lib/IR/AttributeImpl.h +++ lib/IR/AttributeImpl.h @@ -117,6 +117,7 @@ : EnumAttributeImpl(IntAttrEntry, Kind), Val(Val) { assert( (Kind == Attribute::Alignment || Kind == Attribute::StackAlignment || + Kind == Attribute::StackProbeSize || Kind == Attribute::Dereferenceable) && "Wrong kind for int attribute!"); } @@ -165,6 +166,7 @@ unsigned getAlignment() const; unsigned getStackAlignment() const; + unsigned getStackProbeSize() const; uint64_t getDereferenceableBytes() const; std::string getAsString(bool InAttrGrp) const; Index: lib/IR/Attributes.cpp =================================================================== --- lib/IR/Attributes.cpp +++ lib/IR/Attributes.cpp @@ -88,6 +88,11 @@ return get(Context, StackAlignment, Align); } +Attribute Attribute::getWithStackProbeSize(LLVMContext &Context, + uint64_t Size) { + return get(Context, StackProbeSize, Size); +} + Attribute Attribute::getWithDereferenceableBytes(LLVMContext &Context, uint64_t Bytes) { assert(Bytes && "Bytes must be non-zero."); @@ -162,6 +167,13 @@ return pImpl->getValueAsInt(); } +/// This returns the stack probe size field of an attribute as a byte value. +unsigned Attribute::getStackProbeSize() const { + assert(hasAttribute(Attribute::StackProbeSize) && + "Trying to get stack probe size from non-size attribute!"); + return pImpl->getValueAsInt(); +} + /// This returns the number of dereferenceable bytes. uint64_t Attribute::getDereferenceableBytes() const { assert(hasAttribute(Attribute::Dereferenceable) && @@ -277,6 +289,20 @@ return Result; } + if (hasAttribute(Attribute::StackProbeSize)) { + std::string Result; + Result += "stackprobesize"; + if (InAttrGrp) { + Result += "="; + Result += utostr(getValueAsInt()); + } else { + Result += "("; + Result += utostr(getValueAsInt()); + Result += ")"; + } + return Result; + } + if (hasAttribute(Attribute::Dereferenceable)) { std::string Result; Result += "dereferenceable"; @@ -428,6 +454,8 @@ case Attribute::JumpTable: return 1ULL << 45; case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); + case Attribute::StackProbeSize: + llvm_unreachable("stack probe size attribute not supported in raw format"); } llvm_unreachable("Unsupported attribute type"); } @@ -512,6 +540,13 @@ return 0; } +unsigned AttributeSetNode::getStackProbeSize() const { + for (iterator I = begin(), E = end(); I != E; ++I) + if (I->hasAttribute(Attribute::StackProbeSize)) + return I->getStackProbeSize(); + return 0; +} + uint64_t AttributeSetNode::getDereferenceableBytes() const { for (iterator I = begin(), E = end(); I != E; ++I) if (I->hasAttribute(Attribute::Dereferenceable)) @@ -552,6 +587,8 @@ Mask |= (Log2_32(ASN->getAlignment()) + 1) << 16; else if (Kind == Attribute::StackAlignment) Mask |= (Log2_32(ASN->getStackAlignment()) + 1) << 26; + else if (Kind == Attribute::StackProbeSize) + llvm_unreachable("stack probe size not supported in bit mask"); else if (Kind == Attribute::Dereferenceable) llvm_unreachable("dereferenceable not supported in bit mask"); else @@ -659,6 +696,9 @@ else if (Kind == Attribute::StackAlignment) Attrs.push_back(std::make_pair(Index, Attribute:: getWithStackAlignment(C, B.getStackAlignment()))); + else if (Kind == Attribute::StackProbeSize) + Attrs.push_back(std::make_pair(Index, Attribute:: + getWithStackProbeSize(C, B.getStackProbeSize()))); else if (Kind == Attribute::Dereferenceable) Attrs.push_back(std::make_pair(Index, Attribute::getWithDereferenceableBytes(C, @@ -1004,7 +1044,8 @@ //===----------------------------------------------------------------------===// AttrBuilder::AttrBuilder(AttributeSet AS, unsigned Index) - : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0) { + : Attrs(0), Alignment(0), StackAlignment(0), StackProbeSize(0), + DerefBytes(0) { AttributeSetImpl *pImpl = AS.pImpl; if (!pImpl) return; @@ -1021,13 +1062,13 @@ void AttrBuilder::clear() { Attrs.reset(); - Alignment = StackAlignment = DerefBytes = 0; + Alignment = StackAlignment = StackProbeSize = DerefBytes = 0; } AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Val) { assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!"); assert(Val != Attribute::Alignment && Val != Attribute::StackAlignment && - Val != Attribute::Dereferenceable && + Val != Attribute::StackProbeSize && Val != Attribute::Dereferenceable && "Adding integer attribute without adding a value!"); Attrs[Val] = true; return *this; @@ -1046,6 +1087,8 @@ Alignment = Attr.getAlignment(); else if (Kind == Attribute::StackAlignment) StackAlignment = Attr.getStackAlignment(); + else if (Kind == Attribute::StackProbeSize) + StackProbeSize = Attr.getStackProbeSize(); else if (Kind == Attribute::Dereferenceable) DerefBytes = Attr.getDereferenceableBytes(); return *this; @@ -1064,6 +1107,8 @@ Alignment = 0; else if (Val == Attribute::StackAlignment) StackAlignment = 0; + else if (Val == Attribute::StackProbeSize) + StackProbeSize = 0; else if (Val == Attribute::Dereferenceable) DerefBytes = 0; @@ -1090,6 +1135,8 @@ Alignment = 0; else if (Kind == Attribute::StackAlignment) StackAlignment = 0; + else if (Kind == Attribute::StackProbeSize) + StackProbeSize = 0; else if (Kind == Attribute::Dereferenceable) DerefBytes = 0; } else { @@ -1121,7 +1168,6 @@ Alignment = Align; return *this; } - AttrBuilder &AttrBuilder::addStackAlignmentAttr(unsigned Align) { // Default alignment, allow the target to define how to align it. if (Align == 0) return *this; @@ -1134,6 +1180,12 @@ return *this; } +AttrBuilder &AttrBuilder::addStackProbeSizeAttr(unsigned Size) { + Attrs[Attribute::StackProbeSize] = true; + StackProbeSize = Size; + return *this; +} + AttrBuilder &AttrBuilder::addDereferenceableAttr(uint64_t Bytes) { if (Bytes == 0) return *this; @@ -1150,6 +1202,9 @@ if (!StackAlignment) StackAlignment = B.StackAlignment; + if (!StackProbeSize) + StackProbeSize = B.StackProbeSize; + if (!DerefBytes) DerefBytes = B.DerefBytes; @@ -1209,7 +1264,7 @@ return false; return Alignment == B.Alignment && StackAlignment == B.StackAlignment && - DerefBytes == B.DerefBytes; + StackProbeSize == B.StackProbeSize && DerefBytes == B.DerefBytes; } AttrBuilder &AttrBuilder::addRawValue(uint64_t Val) { @@ -1218,6 +1273,8 @@ for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; I = Attribute::AttrKind(I + 1)) { + if (I == Attribute::StackProbeSize) + continue; if (I == Attribute::Dereferenceable) continue; if (uint64_t A = (Val & AttributeImpl::getAttrMask(I))) { Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -820,6 +820,7 @@ I->getKindAsEnum() == Attribute::Naked || I->getKindAsEnum() == Attribute::InlineHint || I->getKindAsEnum() == Attribute::StackAlignment || + I->getKindAsEnum() == Attribute::StackProbeSize || I->getKindAsEnum() == Attribute::UWTable || I->getKindAsEnum() == Attribute::NonLazyBind || I->getKindAsEnum() == Attribute::ReturnsTwice || Index: lib/Target/CppBackend/CPPBackend.cpp =================================================================== --- lib/Target/CppBackend/CPPBackend.cpp +++ lib/Target/CppBackend/CPPBackend.cpp @@ -527,6 +527,12 @@ attrs.removeAttribute(Attribute::StackAlignment); } + if (attrs.contains(Attribute::StackProbeSize)) { + Out << "B.addStackProbeSizeAttr(" << attrs.getStackProbeSize()<<')'; + nl(Out); + attrs.removeAttribute(Attribute::StackProbeSize); + } + Out << "PAS = AttributeSet::get(mod->getContext(), "; if (index == ~0U) Out << "~0U,"; Index: lib/Target/Hexagon/HexagonFrameLowering.h =================================================================== --- lib/Target/Hexagon/HexagonFrameLowering.h +++ lib/Target/Hexagon/HexagonFrameLowering.h @@ -20,7 +20,7 @@ void determineFrameLayout(MachineFunction &MF) const; public: - explicit HexagonFrameLowering() : TargetFrameLowering(StackGrowsDown, 8, 0) {} + explicit HexagonFrameLowering() : TargetFrameLowering(StackGrowsDown, 8, 0, 0) {} /// emitProlog/emitEpilog - These methods insert prolog and epilog code into /// the function. Index: lib/Target/NVPTX/NVPTXFrameLowering.cpp =================================================================== --- lib/Target/NVPTX/NVPTXFrameLowering.cpp +++ lib/Target/NVPTX/NVPTXFrameLowering.cpp @@ -27,7 +27,7 @@ using namespace llvm; NVPTXFrameLowering::NVPTXFrameLowering(NVPTXSubtarget &STI) - : TargetFrameLowering(TargetFrameLowering::StackGrowsUp, 8, 0), + : TargetFrameLowering(TargetFrameLowering::StackGrowsUp, 8, 0, 0), is64bit(STI.is64Bit()) {} bool NVPTXFrameLowering::hasFP(const MachineFunction &MF) const { return true; } Index: lib/Target/PowerPC/PPCFrameLowering.cpp =================================================================== --- lib/Target/PowerPC/PPCFrameLowering.cpp +++ lib/Target/PowerPC/PPCFrameLowering.cpp @@ -38,7 +38,7 @@ PPCFrameLowering::PPCFrameLowering(const PPCSubtarget &STI) : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, - (STI.hasQPX() || STI.isBGQ()) ? 32 : 16, 0), + (STI.hasQPX() || STI.isBGQ()) ? 32 : 16, 0, 0), Subtarget(STI) {} // With the SVR4 ABI, callee-saved registers have fixed offsets on the stack. Index: lib/Target/X86/X86FrameLowering.h =================================================================== --- lib/Target/X86/X86FrameLowering.h +++ lib/Target/X86/X86FrameLowering.h @@ -24,8 +24,10 @@ class X86FrameLowering : public TargetFrameLowering { public: - explicit X86FrameLowering(StackDirection D, unsigned StackAl, int LAO) - : TargetFrameLowering(StackGrowsDown, StackAl, LAO) {} + explicit X86FrameLowering(StackDirection D, unsigned StackAl, + unsigned StackProbeS, int LAO) + : TargetFrameLowering(StackGrowsDown, StackAl, StackProbeS, LAO) + {} static void getStackProbeFunction(const X86Subtarget &STI, unsigned &CallOp, 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 = 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), @@ -343,7 +357,9 @@ TargetTriple.getEnvironment() == Triple::CODE16), TSInfo(DL), InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM), FrameLowering(TargetFrameLowering::StackGrowsDown, - getStackAlignment(), is64Bit() ? -8 : -4) { + getStackAlignment(), + getStackProbeSize(), + is64Bit() ? -8 : -4) { // Determine the PICStyle based on the target selected. if (TM.getRelocationModel() == Reloc::Static) { // Unless we're in PIC or DynamicNoPIC mode, set the PIC style to None. 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: lib/Target/XCore/XCoreFrameLowering.cpp =================================================================== --- lib/Target/XCore/XCoreFrameLowering.cpp +++ lib/Target/XCore/XCoreFrameLowering.cpp @@ -211,7 +211,7 @@ //===----------------------------------------------------------------------===// XCoreFrameLowering::XCoreFrameLowering(const XCoreSubtarget &sti) - : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 4, 0) { + : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 4, 0, 0) { // Do nothing } 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 +}