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

Reply via email to