Index: llvm/trunk/docs/LangRef.rst =================================================================== --- llvm/trunk/docs/LangRef.rst +++ llvm/trunk/docs/LangRef.rst @@ -1511,6 +1511,21 @@ On an argument, this attribute indicates that the function does not write through this pointer argument, even though it may write to the memory that the pointer points to. +``"stack-probe-size"`` + This attribute controls the behavior of stack probes: either + the ``"probe-stack"`` attribute, or ABI-required stack probes, if any. + It defines the size of the guard region. It ensures that if the function + may use more stack space than the size of the guard region, stack probing + sequence will be emitted. It takes one required integer value, which + is 4096 by default. + + If a function that has a ``"stack-probe-size"`` attribute is inlined into + a function with another ``"stack-probe-size"`` attribute, the resulting + function has the ``"stack-probe-size"`` attribute that has the lower + numeric value. If a function that has a ``"stack-probe-size"`` attribute is + inlined into a function that has no ``"stack-probe-size"`` attribute + at all, the resulting function has the ``"stack-probe-size"`` attribute + of the callee. ``writeonly`` On a function, this attribute indicates that the function may write to but does not read from memory. Index: llvm/trunk/include/llvm/IR/Attributes.td =================================================================== --- llvm/trunk/include/llvm/IR/Attributes.td +++ llvm/trunk/include/llvm/IR/Attributes.td @@ -215,3 +215,4 @@ def : MergeRule<"setOR">; def : MergeRule<"adjustCallerSSPLevel">; def : MergeRule<"adjustCallerStackProbes">; +def : MergeRule<"adjustCallerStackProbeSize">; Index: llvm/trunk/lib/IR/Attributes.cpp =================================================================== --- llvm/trunk/lib/IR/Attributes.cpp +++ llvm/trunk/lib/IR/Attributes.cpp @@ -1641,8 +1641,34 @@ /// \brief If the inlined function required stack probes, then ensure that /// the calling function has those too. static void adjustCallerStackProbes(Function &Caller, const Function &Callee) { - if (!Caller.hasFnAttribute("probe-stack") && Callee.hasFnAttribute("probe-stack")) - Caller.addFnAttr("probe-stack", Callee.getFnAttribute("probe-stack").getValueAsString()); + if (!Caller.hasFnAttribute("probe-stack") && + Callee.hasFnAttribute("probe-stack")) { + Caller.addFnAttr(Callee.getFnAttribute("probe-stack")); + } +} + +/// \brief If the inlined function defines the size of guard region +/// on the stack, then ensure that the calling function defines a guard region +/// that is no larger. +static void +adjustCallerStackProbeSize(Function &Caller, const Function &Callee) { + if (Callee.hasFnAttribute("stack-probe-size")) { + uint64_t CalleeStackProbeSize; + Callee.getFnAttribute("stack-probe-size") + .getValueAsString() + .getAsInteger(0, CalleeStackProbeSize); + if (Caller.hasFnAttribute("stack-probe-size")) { + uint64_t CallerStackProbeSize; + Caller.getFnAttribute("stack-probe-size") + .getValueAsString() + .getAsInteger(0, CallerStackProbeSize); + if (CallerStackProbeSize > CalleeStackProbeSize) { + Caller.addFnAttr(Callee.getFnAttribute("stack-probe-size")); + } + } else { + Caller.addFnAttr(Callee.getFnAttribute("stack-probe-size")); + } + } } #define GET_ATTR_COMPAT_FUNC Index: llvm/trunk/test/Transforms/Inline/inline-stack-probe-size.ll =================================================================== --- llvm/trunk/test/Transforms/Inline/inline-stack-probe-size.ll +++ llvm/trunk/test/Transforms/Inline/inline-stack-probe-size.ll @@ -0,0 +1,29 @@ +; RUN: opt %s -inline -S | FileCheck %s + +define internal void @innerSmall() "stack-probe-size"="4096" { + ret void +} + +define internal void @innerLarge() "stack-probe-size"="8192" { + ret void +} + +define void @outerNoAttribute() { + call void @innerSmall() + ret void +} + +define void @outerConflictingAttributeSmall() "stack-probe-size"="4096" { + call void @innerLarge() + ret void +} + +define void @outerConflictingAttributeLarge() "stack-probe-size"="8192" { + call void @innerSmall() + ret void +} + +; CHECK: define void @outerNoAttribute() #0 +; CHECK: define void @outerConflictingAttributeSmall() #0 +; CHECK: define void @outerConflictingAttributeLarge() #0 +; CHECK: attributes #0 = { "stack-probe-size"="4096" }