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
+}