Index: llvm/lib/Target/ARM/ARMFrameLowering.cpp =================================================================== --- llvm/lib/Target/ARM/ARMFrameLowering.cpp +++ llvm/lib/Target/ARM/ARMFrameLowering.cpp @@ -579,18 +579,6 @@ return count; } -static bool WindowsRequiresStackProbe(const MachineFunction &MF, - size_t StackSizeInBytes) { - const MachineFrameInfo &MFI = MF.getFrameInfo(); - const Function &F = MF.getFunction(); - unsigned StackProbeSize = (MFI.getStackProtectorIndex() > 0) ? 4080 : 4096; - - StackProbeSize = - F.getFnAttributeAsParsedInteger("stack-probe-size", StackProbeSize); - return (StackSizeInBytes >= StackProbeSize) && - !F.hasFnAttribute("no-stack-arg-probe"); -} - namespace { struct StackAdjustingInsts { @@ -749,6 +737,10 @@ int FPCXTSaveSize = 0; bool NeedsWinCFI = needsWinCFI(MF); + const bool EmitStackProbeCall = + STI.getTargetLowering()->hasStackProbeSymbol(MF); + unsigned StackProbeSize = STI.getTargetLowering()->getStackProbeSize(MF); + // Debug location must be unknown since the first debug location is used // to determine the end of the prologue. DebugLoc dl; @@ -770,7 +762,7 @@ bool HasFP = hasFP(MF); if (!AFI->hasStackFrame() && - (!STI.isTargetWindows() || !WindowsRequiresStackProbe(MF, NumBytes))) { + !(EmitStackProbeCall && NumBytes >= StackProbeSize)) { if (NumBytes != 0) { emitSPUpdate(isARM, MBB, MBBI, dl, TII, -NumBytes, MachineInstr::FrameSetup); @@ -972,7 +964,7 @@ if (STI.splitFramePointerPush(MF) && HasFP) NeedsWinCFIStackAlloc = false; - if (STI.isTargetWindows() && WindowsRequiresStackProbe(MF, NumBytes)) { + if (NumBytes >= StackProbeSize && EmitStackProbeCall) { uint32_t NumWords = NumBytes >> 2; if (NumWords < 65536) { @@ -995,6 +987,8 @@ .add(predOps(ARMCC::AL)); } + StringRef Symbol = STI.getTargetLowering()->getStackProbeSymbolName(MF); + switch (TM.getCodeModel()) { case CodeModel::Tiny: llvm_unreachable("Tiny code model not available on ARM."); @@ -1003,14 +997,14 @@ case CodeModel::Kernel: BuildMI(MBB, MBBI, dl, TII.get(ARM::tBL)) .add(predOps(ARMCC::AL)) - .addExternalSymbol("__chkstk") + .addExternalSymbol(MF.createExternalSymbolName(Symbol)) .addReg(ARM::R4, RegState::Implicit) .setMIFlags(MachineInstr::FrameSetup); break; case CodeModel::Large: BuildMI(MBB, MBBI, dl, TII.get(ARM::t2MOVi32imm), ARM::R12) - .addExternalSymbol("__chkstk") - .setMIFlags(MachineInstr::FrameSetup); + .addExternalSymbol(MF.createExternalSymbolName(Symbol)) + .setMIFlags(MachineInstr::FrameSetup); BuildMI(MBB, MBBI, dl, TII.get(ARM::tBLXr)) .add(predOps(ARMCC::AL)) @@ -2286,6 +2280,10 @@ (void)TRI; // Silence unused warning in non-assert builds. Register FramePtr = RegInfo->getFrameRegister(MF); + const bool EmitStackProbeCall = + STI.getTargetLowering()->hasStackProbeSymbol(MF); + unsigned StackProbeSize = STI.getTargetLowering()->getStackProbeSize(MF); + // Spill R4 if Thumb2 function requires stack realignment - it will be used as // scratch register. Also spill R4 if Thumb2 function has varsized objects, // since it's not always possible to restore sp from fp in a single @@ -2300,8 +2298,7 @@ // This estimate should be a safe, conservative estimate. The actual // stack probe is enabled based on the size of the local objects; // this estimate also includes the varargs store size. - if (STI.isTargetWindows() && - WindowsRequiresStackProbe(MF, MFI.estimateStackSize(MF))) { + if (MFI.estimateStackSize(MF) >= StackProbeSize && EmitStackProbeCall) { SavedRegs.set(ARM::R4); SavedRegs.set(ARM::LR); } Index: llvm/lib/Target/ARM/ARMISelLowering.h =================================================================== --- llvm/lib/Target/ARM/ARMISelLowering.h +++ llvm/lib/Target/ARM/ARMISelLowering.h @@ -696,6 +696,10 @@ return true; } + bool hasStackProbeSymbol(const MachineFunction &MF) const override; + StringRef getStackProbeSymbolName(const MachineFunction &MF) const override; + unsigned getStackProbeSize(const MachineFunction &MF) const; + bool hasStandaloneRem(EVT VT) const override { return HasStandaloneRem; } Index: llvm/lib/Target/ARM/ARMISelLowering.cpp =================================================================== --- llvm/lib/Target/ARM/ARMISelLowering.cpp +++ llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -22129,3 +22129,43 @@ return nullptr; } + +/// Returns true if stack probing through a function call is requested. +bool ARMTargetLowering::hasStackProbeSymbol(const MachineFunction &MF) const { + return !getStackProbeSymbolName(MF).empty(); +} + +/// Returns the name of the symbol used to emit stack probes or the empty +/// string if not applicable. +StringRef +ARMTargetLowering::getStackProbeSymbolName(const MachineFunction &MF) const { + // If the function specifically requests stack probes, emit them. + if (MF.getFunction().hasFnAttribute("probe-stack")) + return MF.getFunction().getFnAttribute("probe-stack").getValueAsString(); + + if (Subtarget->isTargetWindows() && + !MF.getFunction().hasFnAttribute("no-stack-arg-probe")) + return "__chkstk"; + + // Generally, if we aren't on Windows, the platform ABI does not include + // support for stack probes, so don't emit them. + return ""; +} + +unsigned ARMTargetLowering::getStackProbeSize(const MachineFunction &MF) const { + // The default stack probe size is 4096 if the function has no stackprobesize + // attribute. + const MachineFrameInfo &MFI = MF.getFrameInfo(); + + unsigned StackProbeSize = 4096; + + if (Subtarget->isTargetWindows()) + StackProbeSize = (MFI.getStackProtectorIndex() > 0) ? 4080 : 4096; + + const Function &Fn = MF.getFunction(); + if (Fn.hasFnAttribute("stack-probe-size")) + Fn.getFnAttribute("stack-probe-size") + .getValueAsString() + .getAsInteger(0, StackProbeSize); + return StackProbeSize; +} Index: llvm/test/CodeGen/ARM/stack-probe-size.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/ARM/stack-probe-size.ll @@ -0,0 +1,42 @@ +; This tests that the probe-stack attribute properly calls the probe-stack +; function. +; +; RUN: llc < %s -mtriple=arm-none | FileCheck %s + +define void @_test1() "probe-stack"="__probestack" "stack-probe-size"="0" { + %array = alloca [1024 x i8], align 16 + ret void + +; CHECK-LABEL: test1: +; CHECK: movw r4, #256 +; CHECK-NEXT: bl __probestack +; CHECK-NEXT: sub.w sp, sp, r4 +} + +define void @_test2() "probe-stack"="__probestack" "stack-probe-size"="1024" { + %array = alloca [1024 x i8], align 16 + ret void + +; CHECK-LABEL: test2: +; CHECK: movw r4, #256 +; CHECK-NEXT: bl __probestack +; CHECK-NEXT: sub.w sp, sp, r4 +} + +define void @_test3() "probe-stack"="__probestack" "stack-probe-size"="8192" { + %array = alloca [8192 x i8], align 16 + ret void + +; CHECK-LABEL: test3: +; CHECK: movw r4, #2048 +; CHECK-NEXT: bl __probestack +; CHECK-NEXT: sub.w sp, sp, r4 +} + +define void @_test4() "probe-stack"="__probestack" "stack-probe-size"="8192" { + %array = alloca [4096 x i8], align 16 + ret void + +; CHECK-LABEL: test4: +; CHECK-NOT: bl __probestack +} Index: llvm/test/CodeGen/ARM/stack-probe.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/ARM/stack-probe.ll @@ -0,0 +1,14 @@ +; This tests that the probe-stack attribute properly calls the probe-stack +; function. +; +; RUN: llc < %s -mtriple=arm-none | FileCheck %s + +define void @_test1() "probe-stack"="__probestack" { + %array = alloca [4096 x i8], align 16 + ret void + +; CHECK-LABEL: test1: +; CHECK: movw r4, #1024 +; CHECK-NEXT: bl __probestack +; CHECK-NEXT: sub.w sp, sp, r4 +}