XCore target: Lower FRAME_TO_ARGS_OFFSET
authorRobert Lytton <robert@xmos.com>
Mon, 6 Jan 2014 14:21:00 +0000 (14:21 +0000)
committerRobert Lytton <robert@xmos.com>
Mon, 6 Jan 2014 14:21:00 +0000 (14:21 +0000)
This requires a knowledge of the stack size which is not known until
the frame is complete, hence the need for the XCoreFTAOElim pass
which lowers the XCoreISD::FRAME_TO_ARGS_OFFSET instrution into its
final form.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@198614 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/XCore/CMakeLists.txt
lib/Target/XCore/XCore.h
lib/Target/XCore/XCoreFrameToArgsOffsetElim.cpp [new file with mode: 0644]
lib/Target/XCore/XCoreISelLowering.cpp
lib/Target/XCore/XCoreISelLowering.h
lib/Target/XCore/XCoreInstrInfo.td
lib/Target/XCore/XCoreTargetMachine.cpp
test/CodeGen/XCore/llvm-intrinsics.ll

index 72d06ebaff579445739927593ca6dc38c58867ed..5ad07544ef8c4804241ea2eee21743f8a70877a1 100644 (file)
@@ -24,6 +24,7 @@ add_llvm_target(XCoreCodeGen
   XCoreTargetObjectFile.cpp
   XCoreTargetTransformInfo.cpp
   XCoreSelectionDAGInfo.cpp
+  XCoreFrameToArgsOffsetElim.cpp
   )
 
 add_subdirectory(Disassembler)
index 73c310be034427959f48dc40e64e496618198e95..d707edc8735f1ced86c5414376a5b198427aee2c 100644 (file)
@@ -27,6 +27,7 @@ namespace llvm {
 
   void initializeXCoreLowerThreadLocalPass(PassRegistry &p);
 
+  FunctionPass *createXCoreFrameToArgsOffsetEliminationPass();
   FunctionPass *createXCoreISelDag(XCoreTargetMachine &TM,
                                    CodeGenOpt::Level OptLevel);
   ModulePass *createXCoreLowerThreadLocalPass();
diff --git a/lib/Target/XCore/XCoreFrameToArgsOffsetElim.cpp b/lib/Target/XCore/XCoreFrameToArgsOffsetElim.cpp
new file mode 100644 (file)
index 0000000..29e2dd0
--- /dev/null
@@ -0,0 +1,70 @@
+//===-- XCoreFrameToArgsOffsetElim.cpp ----------------------------*- C++ -*-=//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Replace Pseudo FRAME_TO_ARGS_OFFSET with the appropriate real offset.
+//
+//===----------------------------------------------------------------------===//
+
+#include "XCore.h"
+#include "XCoreInstrInfo.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetMachine.h"
+using namespace llvm;
+
+namespace {
+  struct XCoreFTAOElim : public MachineFunctionPass {
+    static char ID;
+    XCoreFTAOElim() : MachineFunctionPass(ID) {}
+
+    virtual bool runOnMachineFunction(MachineFunction &Fn);
+
+    virtual const char *getPassName() const {
+      return "XCore FRAME_TO_ARGS_OFFSET Elimination";
+    }
+  };
+  char XCoreFTAOElim::ID = 0;
+}
+
+/// createXCoreFrameToArgsOffsetEliminationPass - returns an instance of the
+/// Frame to args offset elimination pass
+FunctionPass *llvm::createXCoreFrameToArgsOffsetEliminationPass() {
+  return new XCoreFTAOElim();
+}
+
+static inline bool isImmU6(unsigned val) {
+  return val < (1 << 6);
+}
+
+static inline bool isImmU16(unsigned val) {
+  return val < (1 << 16);
+}
+
+bool XCoreFTAOElim::runOnMachineFunction(MachineFunction &MF) {
+  const XCoreInstrInfo &TII =
+          *static_cast<const XCoreInstrInfo*>(MF.getTarget().getInstrInfo());
+  unsigned StackSize = MF.getFrameInfo()->getStackSize();
+  for (MachineFunction::iterator MFI = MF.begin(), E = MF.end(); MFI != E;
+       ++MFI) {
+    MachineBasicBlock &MBB = *MFI;
+    for (MachineBasicBlock::iterator MBBI = MBB.begin(), EE = MBB.end();
+         MBBI != EE; ++MBBI) {
+      if (MBBI->getOpcode() == XCore::FRAME_TO_ARGS_OFFSET) {
+        MachineInstr *OldInst = MBBI;
+        unsigned Reg = OldInst->getOperand(0).getReg();
+        MBBI = TII.loadImmediate(MBB, MBBI, Reg, StackSize);
+        OldInst->eraseFromParent();
+      }
+    }
+  }
+  return true;
+}
index 65568c9654333d29060c73d19bb162ef93f2a990..c0edee55e43b263adbcd190bc90cc8e31d2d3af4 100644 (file)
@@ -60,6 +60,7 @@ getTargetNodeName(unsigned Opcode) const
     case XCoreISD::CRC8              : return "XCoreISD::CRC8";
     case XCoreISD::BR_JT             : return "XCoreISD::BR_JT";
     case XCoreISD::BR_JT32           : return "XCoreISD::BR_JT32";
+    case XCoreISD::FRAME_TO_ARGS_OFFSET : return "XCoreISD::FRAME_TO_ARGS_OFFSET";
     case XCoreISD::MEMBARRIER        : return "XCoreISD::MEMBARRIER";
     default                          : return NULL;
   }
@@ -153,6 +154,7 @@ XCoreTargetLowering::XCoreTargetLowering(XCoreTargetMachine &XTM)
   // Exception handling
   setExceptionPointerRegister(XCore::R0);
   setExceptionSelectorRegister(XCore::R1);
+  setOperationAction(ISD::FRAME_TO_ARGS_OFFSET, MVT::i32, Custom);
 
   // Atomic operations
   setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom);
@@ -213,6 +215,7 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const {
   case ISD::SUB:                return ExpandADDSUB(Op.getNode(), DAG);
   case ISD::FRAMEADDR:          return LowerFRAMEADDR(Op, DAG);
   case ISD::RETURNADDR:         return LowerRETURNADDR(Op, DAG);
+  case ISD::FRAME_TO_ARGS_OFFSET: return LowerFRAME_TO_ARGS_OFFSET(Op, DAG);
   case ISD::INIT_TRAMPOLINE:    return LowerINIT_TRAMPOLINE(Op, DAG);
   case ISD::ADJUST_TRAMPOLINE:  return LowerADJUST_TRAMPOLINE(Op, DAG);
   case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG);
@@ -826,6 +829,15 @@ LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const {
                      false, 0);
 }
 
+SDValue XCoreTargetLowering::
+LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const {
+  // This node represents offset from frame pointer to first on-stack argument.
+  // This is needed for correct stack adjustment during unwind.
+  // However, we don't know the offset until after the frame has be finalised.
+  // This is done during the XCoreFTAOElim pass.
+  return DAG.getNode(XCoreISD::FRAME_TO_ARGS_OFFSET, SDLoc(Op), MVT::i32);
+}
+
 SDValue XCoreTargetLowering::
 LowerADJUST_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const {
   return Op.getOperand(0);
index a6dd2260246b0cead420c24480882371e536696e..c4de86e22dc29f3c0d05b96123e61be83709836f 100644 (file)
@@ -72,6 +72,9 @@ namespace llvm {
       // Jumptable branch using long branches for each entry.
       BR_JT32,
 
+      // Offset from frame pointer to the first (possible) on-stack argument
+      FRAME_TO_ARGS_OFFSET,
+
       // Memory barrier.
       MEMBARRIER
     };
@@ -158,6 +161,7 @@ namespace llvm {
     SDValue LowerUMUL_LOHI(SDValue Op, SelectionDAG &DAG) const;
     SDValue LowerSMUL_LOHI(SDValue Op, SelectionDAG &DAG) const;
     SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
+    SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const;
     SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
     SDValue LowerINIT_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const;
     SDValue LowerADJUST_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const;
index 5974842383ce9a3c9434f87f3965d8e455014589..144d4fec24665da3efb9a714b0f3bd7ec873c1da 100644 (file)
@@ -56,6 +56,9 @@ def dprelwrapper : SDNode<"XCoreISD::DPRelativeWrapper", SDT_XCoreAddress,
 def cprelwrapper : SDNode<"XCoreISD::CPRelativeWrapper", SDT_XCoreAddress,
                            []>;
 
+def frametoargsoffset : SDNode<"XCoreISD::FRAME_TO_ARGS_OFFSET", SDTIntLeaf,
+                               []>;
+
 def SDT_XCoreStwsp    : SDTypeProfile<0, 2, [SDTCisInt<1>]>;
 def XCoreStwsp        : SDNode<"XCoreISD::STWSP", SDT_XCoreStwsp,
                                [SDNPHasChain, SDNPMayStore]>;
@@ -326,6 +329,11 @@ def ADJCALLSTACKUP : PseudoInstXCore<(outs), (ins i32imm:$amt1, i32imm:$amt2),
                             [(callseq_end timm:$amt1, timm:$amt2)]>;
 }
 
+let isReMaterializable = 1 in
+def FRAME_TO_ARGS_OFFSET : PseudoInstXCore<(outs GRRegs:$dst), (ins),
+                               "# FRAME_TO_ARGS_OFFSET $dst",
+                               [(set GRRegs:$dst, (frametoargsoffset))]>;
+
 def LDWFI : PseudoInstXCore<(outs GRRegs:$dst), (ins MEMii:$addr),
                              "# LDWFI $dst, $addr",
                              [(set GRRegs:$dst, (load ADDRspii:$addr))]>;
index 21027270911dec1691d59d6e8e43c8c5bdfc1987..781a87b1e910995d6f00e63cf48ff16d71384e07 100644 (file)
@@ -48,6 +48,7 @@ public:
 
   virtual bool addPreISel();
   virtual bool addInstSelector();
+  virtual bool addPreEmitPass();
 };
 } // namespace
 
@@ -65,6 +66,11 @@ bool XCorePassConfig::addInstSelector() {
   return false;
 }
 
+bool XCorePassConfig::addPreEmitPass() {
+  addPass(createXCoreFrameToArgsOffsetEliminationPass());
+  return false;
+}
+
 // Force static initialization.
 extern "C" void LLVMInitializeXCoreTarget() {
   RegisterTargetMachine<XCoreTargetMachine> X(TheXCoreTarget);
index 14b299d46e8d4c4f997a189acb3f051754df3b8c..55b77ac9e6b33c5f7bf519e61b26824a2dcf41ca 100644 (file)
@@ -44,3 +44,29 @@ entry:
   %1 = call i8* @llvm.returnaddress(i32 0)
   ret i8* %1
 }
+
+; test FRAME_TO_ARGS_OFFSET lowering
+declare i8* @llvm.eh.dwarf.cfa(i32) nounwind
+define i8* @FTAO0() nounwind {
+entry:
+; CHECK-LABEL: FTAO0
+; CHECK: ldc r0, 0
+; CHECK-NEXT: ldaw r1, sp[0]
+; CHECK-NEXT: add r0, r1, r0
+; CHECK-NEXT: retsp 0
+  %0 = call i8* @llvm.eh.dwarf.cfa(i32 0)
+  ret i8* %0
+}
+
+define i8* @FTAO1() nounwind {
+entry:
+; CHECK-LABEL: FTAO1
+; CHECK: entsp 100
+; CHECK-NEXT: ldc r0, 400
+; CHECK-NEXT: ldaw r1, sp[0]
+; CHECK-NEXT: add r0, r1, r0
+; CHECK-NEXT: retsp 100
+  %0 = alloca [100 x i32]
+  %1 = call i8* @llvm.eh.dwarf.cfa(i32 0)
+  ret i8* %1
+}