Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -1353,6 +1353,24 @@ If a function that has an ``sspstrong`` attribute is inlined into a function that doesn't have an ``sspstrong`` attribute, then the resulting function will have an ``sspstrong`` attribute. +``stackprobesize()`` + This attribute indicates that, when emitting the prologue, the backend + should emit a call to a prologue helper routine (the so called stack probe + function) when allocating more than ``n`` bytes on the stack. Specify the + desired size in parentheses. + + When the function allocates more than a certain amount of stack space, + some targets require such a stack probe call so that the function can + access its stack memory safely. + + A value of 0 is legal for ``n`` and indicates that stack probe function + calls are emitted regardless of the amount of stack space the function + uses. + + This attribute has only an effect on specific targets (MingW, Cygwin, + MSVC) and other targets will ignore this attribute. When this attribute is + omitted on such targets, the backend uses a safe default value for the + respective target. ``uwtable`` This attribute indicates that the ABI being targeted requires that an unwind table entry be produce for this function even if we can 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/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. @@ -127,6 +129,8 @@ /// \brief Return a uniquified Attribute object. static Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val = 0); + static Attribute getZeroValue(LLVMContext &Context, + Attribute::AttrKind Kind, uint64_t Val = 0); static Attribute get(LLVMContext &Context, StringRef Kind, StringRef Val = StringRef()); @@ -134,6 +138,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 +186,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 +332,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 +417,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 +483,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 +498,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: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -558,6 +558,7 @@ KEYWORD(asm); KEYWORD(sideeffect); KEYWORD(alignstack); + KEYWORD(stackprobesize); KEYWORD(inteldialect); KEYWORD(gc); KEYWORD(prefix); 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; @@ -1273,6 +1287,7 @@ case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break; case lltok::kw_alignstack: + case lltok::kw_stackprobesize: case lltok::kw_alwaysinline: case lltok::kw_builtin: case lltok::kw_inlinehint: @@ -1674,6 +1689,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 SizeLoc = 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/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 @@ -55,6 +55,25 @@ return Attribute(PA); } +Attribute Attribute::getZeroValue(LLVMContext &Context, + Attribute::AttrKind Kind, uint64_t Val) { + LLVMContextImpl *pImpl = Context.pImpl; + FoldingSetNodeID ID; + ID.AddInteger(Kind); + ID.AddInteger(Val); + + void *InsertPoint; + AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint); + + if (!PA) { + PA = new IntAttributeImpl(Kind, Val); + pImpl->AttrsSet.InsertNode(PA, InsertPoint); + } + + // Return the Attribute that we found or created. + return Attribute(PA); +} + Attribute Attribute::get(LLVMContext &Context, StringRef Kind, StringRef Val) { LLVMContextImpl *pImpl = Context.pImpl; FoldingSetNodeID ID; @@ -88,6 +107,11 @@ return get(Context, StackAlignment, Align); } +Attribute Attribute::getWithStackProbeSize(LLVMContext &Context, + uint64_t Size) { + return getZeroValue(Context, StackProbeSize, Size); +} + Attribute Attribute::getWithDereferenceableBytes(LLVMContext &Context, uint64_t Bytes) { assert(Bytes && "Bytes must be non-zero."); @@ -162,6 +186,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 +308,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 +473,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 +559,13 @@ return 0; } +unsigned AttributeSetNode::getStackProbeSize() const { + for (auto I : *this) + 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 +606,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 +715,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 +1063,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 +1081,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 +1106,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 +1126,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 +1154,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 { @@ -1134,6 +1200,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 +1222,9 @@ if (!StackAlignment) StackAlignment = B.StackAlignment; + if (!StackProbeSize) + StackProbeSize = B.StackProbeSize; + if (!DerefBytes) DerefBytes = B.DerefBytes; @@ -1209,7 +1284,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 +1293,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,8 @@ 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() ? @@ -528,6 +529,11 @@ bool UseStackProbe = (STI.isOSWindows() && !STI.isTargetMachO()); + if (Fn->hasFnAttribute(Attribute::StackProbeSize)) { + Attribute A = Fn->getFnAttribute(Attribute::StackProbeSize); + StackProbeSize = A.getStackProbeSize(); + } + // If this is x86-64 and the Red Zone is not disabled, if we are a leaf // function, and use up to 128 bytes of stack space, don't have a frame // pointer, calls, or dynamic alloca then we do not need to adjust the @@ -705,8 +711,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 +719,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,11 @@ /// entry to the function and which must be maintained by every function. unsigned stackAlignment; + /// DefaultStackProbeSize - When exceeding the stack probe size, stack probing + /// functions are inserted if the target requires them. This default value is + /// used if the function has no stackprobesize attribute. + unsigned DefaultStackProbeSize; + /// Max. memset / memcpy size that is turned into rep/movs, rep/stos ops. /// unsigned MaxInlineSizeThreshold; @@ -292,6 +297,10 @@ /// function for this subtarget. unsigned getStackAlignment() const { return stackAlignment; } + /// getDefaultStackProbeSize - Returns the maximum size of stack memory that + /// can be safely accessed without calling stack probing functions. + unsigned getDefaultStackProbeSize() const { return DefaultStackProbeSize; } + /// 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 @@ -278,6 +278,11 @@ UseSqrtEst = false; UseReciprocalEst = false; stackAlignment = 4; + + // By default, we assume that the page size for a page of stack space is at + // least 4096 bytes. + DefaultStackProbeSize = 4096; + // FIXME: this is a known good value for Yonah. How about others? MaxInlineSizeThreshold = 128; } @@ -343,7 +348,9 @@ TargetTriple.getEnvironment() == Triple::CODE16), TSInfo(DL), InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM), FrameLowering(TargetFrameLowering::StackGrowsDown, - getStackAlignment(), is64Bit() ? -8 : -4) { + getStackAlignment(), + getDefaultStackProbeSize(), + 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/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,78 @@ +; 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 | FileCheck %s + +target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32" +target triple = "i686-pc-windows-msvc" + +define i32 @test1() stackprobesize(0) { + %buffer = alloca [4095 x i8] + + ret i32 0 + +; CHECK-LABEL: _test1: +; CHECK-NOT: subl $4095, %esp +; CHECK: movl $4095, %eax +; CHECK: calll __chkstk +} + +define i32 @test2() { + %buffer = alloca [4095 x i8] + + ret i32 0 + +; CHECK-LABEL: _test2: +; CHECK-NOT: movl $4095, %eax +; CHECK: subl $4095, %esp +; CHECK-NOT: calll __chkstk +} + +define i32 @test3() stackprobesize(8192) { + %buffer = alloca [4095 x i8] + + ret i32 0 + +; CHECK-LABEL: _test3: +; CHECK-NOT: movl $4095, %eax +; CHECK: subl $4095, %esp +; CHECK-NOT: calll __chkstk +} + +define i32 @test4() stackprobesize(0) { + %buffer = alloca [4096 x i8] + + ret i32 0 + +; CHECK-LABEL: _test4: +; CHECK-NOT: subl $4096, %esp +; CHECK: movl $4096, %eax +; CHECK: calll __chkstk +} + +define i32 @test5() { + %buffer = alloca [4096 x i8] + + ret i32 0 + +; CHECK-LABEL: _test5: +; CHECK-NOT: subl $4096, %esp +; CHECK: movl $4096, %eax +; CHECK: calll __chkstk +} + +define i32 @test6() stackprobesize(8192) { + %buffer = alloca [4096 x i8] + + ret i32 0 + +; CGECK-LABEL: _test6: +; CGECK-NOT: movl $4096, %eax +; CGECK: subl $4096, %esp +; CGECK-NOT: calll __chkstk +}