Index: docs/Extensions.rst =================================================================== --- docs/Extensions.rst +++ docs/Extensions.rst @@ -159,3 +159,34 @@ .globl Symbol2 Symbol2: .long 1 + +Target Specific Behaviour +========================= + +Windows on ARM +-------------- + +Stack Probe Emission +^^^^^^^^^^^^^^^^^^^^ + +The reference implementation (Microsoft Visual Studio 2012) emits stack probes +in the following fashion: + +.. code-block:: gas + + movw r4, #constant + bl __chkstk + sub.w sp, sp, r4 + +However, this has the limitation of 32 MiB (±16MiB). In order to accomodate +larger binaries, LLVM supports the use of ``-mcode-model=large`` to allow a 4GiB +range via a slight deviation. It will generate an indirect jump as follows: + +.. code-block:: gas + + movw r4, #constant + movw r12, :lower16:__chkstk + movt r12, :upper16:__chkstk + blx r12 + sub.w sp, sp, r4 + Index: lib/Target/ARM/ARMFrameLowering.cpp =================================================================== --- lib/Target/ARM/ARMFrameLowering.cpp +++ lib/Target/ARM/ARMFrameLowering.cpp @@ -24,6 +24,7 @@ #include "llvm/CodeGen/RegisterScavenging.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Function.h" +#include "llvm/IR/Module.h" #include "llvm/MC/MCContext.h" #include "llvm/Support/CommandLine.h" #include "llvm/Target/TargetOptions.h" @@ -148,15 +149,16 @@ ARMFunctionInfo *AFI = MF.getInfo(); MachineModuleInfo &MMI = MF.getMMI(); MCContext &Context = MMI.getContext(); + const TargetMachine &TM = MF.getTarget(); const MCRegisterInfo *MRI = Context.getRegisterInfo(); const ARMBaseRegisterInfo *RegInfo = - static_cast(MF.getTarget().getRegisterInfo()); + static_cast(TM.getRegisterInfo()); const ARMBaseInstrInfo &TII = - *static_cast(MF.getTarget().getInstrInfo()); + *static_cast(TM.getInstrInfo()); assert(!AFI->isThumb1OnlyFunction() && "This emitPrologue does not support Thumb1!"); bool isARM = !AFI->isThumbFunction(); - unsigned Align = MF.getTarget().getFrameLowering()->getStackAlignment(); + unsigned Align = TM.getFrameLowering()->getStackAlignment(); unsigned ArgRegsSaveSize = AFI->getArgRegsSaveSize(Align); unsigned NumBytes = MFI->getStackSize(); const std::vector &CSI = MFI->getCalleeSavedInfo(); @@ -186,7 +188,8 @@ .addCFIIndex(CFIIndex); } - if (!AFI->hasStackFrame()) { + if (!AFI->hasStackFrame() && + !(NumBytes >= 4080 /* 4096 */ && STI.isTargetWindows())) { if (NumBytes - ArgRegsSaveSize != 0) { emitSPUpdate(isARM, MBB, MBBI, dl, TII, -(NumBytes - ArgRegsSaveSize), MachineInstr::FrameSetup); @@ -283,6 +286,52 @@ } else NumBytes = DPRCSOffset; + if (STI.isTargetWindows()) { + if (NumBytes >= 4080 /* 4096 */) { + uint32_t NumWords = NumBytes >> 2; + + if (NumWords < 65536) + AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::t2MOVi16), ARM::R4) + .addImm(NumWords)); + else + BuildMI(MBB, MBBI, dl, TII.get(ARM::t2MOVi32imm), ARM::R4) + .addImm(NumWords); + + switch (TM.getCodeModel()) { + case CodeModel::Small: + case CodeModel::Medium: + case CodeModel::Default: + case CodeModel::Kernel: + BuildMI(MBB, MBBI, dl, TII.get(ARM::tBL)) + .addImm((unsigned)ARMCC::AL).addReg(0) + .addExternalSymbol("__chkstk") + .addReg(ARM::R4, RegState::Implicit); + break; + case CodeModel::Large: + case CodeModel::JITDefault: { + LLVMContext &Ctx = MF.getMMI().getModule()->getContext(); + const GlobalValue *F = + Function::Create(FunctionType::get(Type::getVoidTy(Ctx), false), + GlobalValue::AvailableExternallyLinkage, "__chkstk"); + + BuildMI(MBB, MBBI, dl, TII.get(ARM::t2MOVi32imm), ARM::R12) + .addGlobalAddress(F); + BuildMI(MBB, MBBI, dl, TII.get(ARM::BLX)) + .addReg(ARM::R12, RegState::Kill) + .addReg(ARM::R4, RegState::Implicit); + break; + } + } + + AddDefaultCC(AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::t2SUBrr), + ARM::SP) + .addReg(ARM::SP, RegState::Define) + .addReg(ARM::R4, RegState::Kill) + .setMIFlags(MachineInstr::FrameSetup))); + NumBytes = 0; + } + } + unsigned adjustedGPRCS1Size = GPRCS1Size; if (NumBytes) { // Adjust SP after all the callee-save spills. Index: test/CodeGen/ARM/Windows/chkstk.ll =================================================================== --- /dev/null +++ test/CodeGen/ARM/Windows/chkstk.ll @@ -0,0 +1,26 @@ +; RUN: llc -mtriple=thumbv7-windows -mcpu=cortex-a9 %s -o - \ +; RUN: | FileCheck -check-prefix CHECK-DEFAULT-CODE-MODEL %s + +; RUN: llc -mtriple=thumbv7-windows -mcpu=cortex-a9 -code-model=large %s -o - \ +; RUN: | FileCheck -check-prefix CHECK-LARGE-CODE-MODEL %s + +define arm_aapcs_vfpcc void @check_watermark() #0 { +entry: + %buffer = alloca [4080 x i8], align 1 + ret void +} + +; CHECK-DEFAULT-CODE-MODEL: check_watermark: +; CHECK-DEFAULT-CODE-MODEL: movw r4, #1020 +; CHECK-DEFAULT-CODE-MODEL: bl __chkstk +; CHECK-DEFAULT-CODE-MODEL: sub.w sp, sp, r4 + +; CHECK-LARGE-CODE-MODEL: check_watermark: +; CHECK-LARGE-CODE-MODEL: movw r12, :lower16:__chkstk +; CHECK-LARGE-CODE-MODEL: movt r12, :upper16:__chkstk +; CHECK-LARGE-CODE-MODEL: movw r4, #1020 +; CHECK-LARGE-CODE-MODEL: blx r12 +; CHECK-LARGE-CODE-MODEL: sub.w sp, sp, r4 + +attributes #0 = { nounwind } +