For LLVM patches, we prefer if you have first attempted to upstream the patch with LLVM before we push it to our local fork. This normally entails emailing the llvm-commits mailing list. Once this upstream attempt has been made, you can open a PR against the rust-lang/llvm repo on github.
This looks pretty awesome though, nice work! On Sat, Feb 15, 2014 at 8:36 AM, Svetoslav Neykov <svetos...@neykov.name> wrote: > Hi, > > I am working on getting Rust to directly compile code for bare metal ARM > devices working in Thumb mode. I created a patch for LLVM to emit > the appropriate function prologue. Since I couldn't find instructions on how > to submit the change for review and inclusion in the Rust's copy of LLVM I > am sending it here on the dev mailing list. > > Besides the mechanincal differences between the ARM and Thumb functions, > because of the different instruction sets, there is difference in how the > stack limit is located. The ARM version uses hardware which isn't available > on the lower-end Thumb processors (namely system co-processor and MMU) > therefore I am looking for the stack limit at a predefined location in > memory - STACK_LIMIT. It is the responsibility of the wrapping runtime > to manage this location with the correct value. It can vary from a simple > constant defined by the linker to actively managed variable by a RTOS > implementation. > (thanks to whitequark for discussing the possible approaches) > > There is an old pull request for Rust which was the precursor to this change > located at https://github.com/mozilla/rust/pull/10942. Once the patch is > accepted I will try to update it to the latest changes in the repository. > > Here is the patch itself: > =============================================================================== > > Add stack overflow check for ARM Thumb instruction set. > > The code assumes that the stack limit will be located at the > address labeled STACK_LIMIT. > --- > lib/Target/ARM/ARMFrameLowering.cpp | 184 > +++++++++++++++++++++++++++++++++++- > lib/Target/ARM/ARMFrameLowering.h | 2 + > 2 files changed, 185 insertions(+), 1 deletion(-) > > diff --git a/lib/Target/ARM/ARMFrameLowering.cpp > b/lib/Target/ARM/ARMFrameLowering.cpp > index bdf0480..c286228 100644 > --- a/lib/Target/ARM/ARMFrameLowering.cpp > +++ b/lib/Target/ARM/ARMFrameLowering.cpp > @@ -14,6 +14,7 @@ > #include "ARMFrameLowering.h" > #include "ARMBaseInstrInfo.h" > #include "ARMBaseRegisterInfo.h" > +#include "ARMConstantPoolValue.h" > #include "ARMInstrInfo.h" > #include "ARMMachineFunctionInfo.h" > #include "ARMTargetMachine.h" > @@ -1481,10 +1482,20 @@ static uint32_t AlignToARMConstant(uint32_t Value) { > // stack limit. > static const uint64_t kSplitStackAvailable = 256; > > +void > +ARMFrameLowering::adjustForSegmentedStacks(MachineFunction &MF) const { > + const ARMSubtarget *ST = &MF.getTarget().getSubtarget<ARMSubtarget>(); > + if(ST->isThumb()) { > + adjustForSegmentedStacksThumb(MF); > + } else { > + adjustForSegmentedStacksARM(MF); > + } > +} > + > // Adjust function prologue to enable split stack. > // Only support android and linux. > void > -ARMFrameLowering::adjustForSegmentedStacks(MachineFunction &MF) const { > +ARMFrameLowering::adjustForSegmentedStacksARM(MachineFunction &MF) const { > const ARMSubtarget *ST = &MF.getTarget().getSubtarget<ARMSubtarget>(); > > // Doesn't support vararg function. > @@ -1697,3 +1708,174 @@ > ARMFrameLowering::adjustForSegmentedStacks(MachineFunction &MF) const { > MF.verify(); > #endif > } > + > +void > +ARMFrameLowering::adjustForSegmentedStacksThumb(MachineFunction &MF) const { > +// const ARMSubtarget *ST = &MF.getTarget().getSubtarget<ARMSubtarget>(); > + > + // Doesn't support vararg function. > + if (MF.getFunction()->isVarArg()) > + report_fatal_error("Segmented stacks do not support vararg functions."); > + > + MachineBasicBlock &prologueMBB = MF.front(); > + MachineFrameInfo* MFI = MF.getFrameInfo(); > + const ARMBaseInstrInfo &TII = *TM.getInstrInfo(); > + ARMFunctionInfo* ARMFI = MF.getInfo<ARMFunctionInfo>(); > + DebugLoc DL; > + > + // Use R4 and R5 as scratch register. > + // We should save R4 and R5 before use it and restore before > + // leave the function. > + unsigned ScratchReg0 = ARM::R4; > + unsigned ScratchReg1 = ARM::R5; > + uint64_t AlignedStackSize; > + > + MachineBasicBlock* prevStackMBB = MF.CreateMachineBasicBlock(); > + MachineBasicBlock* postStackMBB = MF.CreateMachineBasicBlock(); > + MachineBasicBlock* allocMBB = MF.CreateMachineBasicBlock(); > + MachineBasicBlock* getMBB = MF.CreateMachineBasicBlock(); > + MachineBasicBlock* mcrMBB = MF.CreateMachineBasicBlock(); > + MachineBasicBlock* magicMBB = MF.CreateMachineBasicBlock(); > + > + for (MachineBasicBlock::livein_iterator i = prologueMBB.livein_begin(), > + e = prologueMBB.livein_end(); i != e; ++i) { > + allocMBB->addLiveIn(*i); > + getMBB->addLiveIn(*i); > + magicMBB->addLiveIn(*i); > + mcrMBB->addLiveIn(*i); > + prevStackMBB->addLiveIn(*i); > + postStackMBB->addLiveIn(*i); > + } > + > + MF.push_front(postStackMBB); > + MF.push_front(allocMBB); > + MF.push_front(getMBB); > + MF.push_front(magicMBB); > + MF.push_front(mcrMBB); > + MF.push_front(prevStackMBB); > + > + // The required stack size that is aligend to ARM constant critarion. > + uint64_t StackSize = MFI->getStackSize(); > + > + AlignedStackSize = AlignToARMConstant(StackSize); > + > + // When the frame size is less than 256 we just compare the stack > + // boundary directly to the value of the stack pointer, per gcc. > + bool CompareStackPointer = AlignedStackSize < kSplitStackAvailable; > + > + // We will use two of callee save registers as scratch register so we > + // need to save those registers into stack frame before use it. > + // We will use SR0 to hold stack limit and SR1 to stack size requested. > + // and arguments for __morestack(). > + // SR0: Scratch Register #0 > + // SR1: Scratch Register #1 > + // push {SR0, SR1} > + AddDefaultPred(BuildMI(prevStackMBB, DL, TII.get(ARM::tPUSH))) > + .addReg(ScratchReg0) > + .addReg(ScratchReg1); > + > + if (CompareStackPointer) { > + // mov SR1, sp > + AddDefaultPred(BuildMI(mcrMBB, DL, TII.get(ARM::tMOVr), ScratchReg1) > + .addReg(ARM::SP)); > + } else { > + // sub SR1, sp, #StackSize > + AddDefaultPred(BuildMI(mcrMBB, DL, TII.get(ARM::tSUBi8), ScratchReg1) > + .addReg(ARM::SP).addImm(AlignedStackSize)); > + } > + > + unsigned PCLabelId = ARMFI->createPICLabelUId(); > + ARMConstantPoolValue *NewCPV = ARMConstantPoolSymbol:: > + Create(MF.getFunction()->getContext(), "STACK_LIMIT", PCLabelId, 0); > + MachineConstantPool *MCP = MF.getConstantPool(); > + unsigned CPI = MCP->getConstantPoolIndex(NewCPV, MF.getAlignment()); > + > + //ldr SR0, [pc, offset(STACK_LIMIT)] > + AddDefaultPred(BuildMI(magicMBB, DL, TII.get(ARM::tLDRpci), ScratchReg0) > + .addConstantPoolIndex(CPI)); > + > + //ldr SR0, [SR0] > + AddDefaultPred(BuildMI(magicMBB, DL, TII.get(ARM::tLDRi), ScratchReg0) > + .addReg(ScratchReg0) > + .addImm(0)); > + > + // Compare stack limit with stack size requested. > + // cmp SR0, SR1 > + AddDefaultPred(BuildMI(getMBB, DL, TII.get(ARM::tCMPr)) > + .addReg(ScratchReg0) > + .addReg(ScratchReg1)); > + > + // This jump is taken if StackLimit < SP - stack required. > + BuildMI(getMBB, DL, TII.get(ARM::tBcc)) > + .addMBB(postStackMBB) > + .addImm(ARMCC::LO) > + .addReg(ARM::CPSR); > + > + > + // Calling __morestack(StackSize, Size of stack arguments). > + // __morestack knows that the stack size requested is in SR0(r4) > + // and amount size of stack arguments is in SR1(r5). > + > + // Pass first argument for the __morestack by Scratch Register #0. > + // The amount size of stack required > + AddDefaultPred(AddDefaultCC(BuildMI(allocMBB, DL, TII.get(ARM::tMOVi8), > ScratchReg0)) > + .addImm(AlignedStackSize)); > + // Pass second argument for the __morestack by Scratch Register #1. > + // The amount size of stack consumed to save function arguments. > + AddDefaultPred(AddDefaultCC(BuildMI(allocMBB, DL, TII.get(ARM::tMOVi8), > ScratchReg1)) > + .addImm(AlignToARMConstant(ARMFI->getArgumentStackSize()))); > + > + // push {lr} - Save return address of this function. > + AddDefaultPred(BuildMI(allocMBB, DL, TII.get(ARM::tPUSH))) > + .addReg(ARM::LR); > + > + // Call __morestack(). > + AddDefaultPred(BuildMI(allocMBB, DL, TII.get(ARM::tBL))) > + .addExternalSymbol("__morestack"); > + > + // Restore return address of this original function. > + // pop {SR0} > + AddDefaultPred(BuildMI(allocMBB, DL, TII.get(ARM::tPOP))) > + .addReg(ScratchReg0); > + > + // mov lr, SR0 > + AddDefaultPred(BuildMI(allocMBB, DL, TII.get(ARM::tMOVr), ARM::LR) > + .addReg(ScratchReg0)); > + > + // Restore SR0 and SR1 in case of __morestack() was called. > + // __morestack() will skip postStackMBB block so we need to restore > + // scratch registers from here. > + // pop {SR0, SR1} > + AddDefaultPred(BuildMI(allocMBB, DL, TII.get(ARM::tPOP))) > + .addReg(ScratchReg0) > + .addReg(ScratchReg1); > + > + // Return from this function. > + AddDefaultPred(BuildMI(allocMBB, DL, TII.get(ARM::tMOVr), ARM::PC) > + .addReg(ARM::LR)); > + > + // Restore SR0 and SR1 in case of __morestack() was not called. > + // pop {SR0, SR1} > + AddDefaultPred(BuildMI(postStackMBB, DL, TII.get(ARM::tPOP))) > + .addReg(ScratchReg0) > + .addReg(ScratchReg1); > + > + // Organizing MBB lists > + postStackMBB->addSuccessor(&prologueMBB); > + > + allocMBB->addSuccessor(postStackMBB); > + > + getMBB->addSuccessor(postStackMBB); > + getMBB->addSuccessor(allocMBB); > + > + magicMBB->addSuccessor(getMBB); > + > + mcrMBB->addSuccessor(getMBB); > + mcrMBB->addSuccessor(magicMBB); > + > + prevStackMBB->addSuccessor(mcrMBB); > + > +#ifdef XDEBUG > + MF.verify(); > +#endif > +} > diff --git a/lib/Target/ARM/ARMFrameLowering.h > b/lib/Target/ARM/ARMFrameLowering.h > index 16b477a..0cb8e5a 100644 > --- a/lib/Target/ARM/ARMFrameLowering.h > +++ b/lib/Target/ARM/ARMFrameLowering.h > @@ -62,6 +62,8 @@ public: > RegScavenger *RS) const; > > void adjustForSegmentedStacks(MachineFunction &MF) const; > + void adjustForSegmentedStacksThumb(MachineFunction &MF) const; > + void adjustForSegmentedStacksARM(MachineFunction &MF) const; > > private: > void emitPushInst(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, > -- > 1.8.3.2 > > _______________________________________________ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev _______________________________________________ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev