Lower BR_JT on the XCore to a jump into a series of jump instructions.
authorRichard Osborne <richard@xmos.com>
Tue, 23 Feb 2010 13:25:07 +0000 (13:25 +0000)
committerRichard Osborne <richard@xmos.com>
Tue, 23 Feb 2010 13:25:07 +0000 (13:25 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@96942 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/XCore/AsmPrinter/XCoreAsmPrinter.cpp
lib/Target/XCore/XCoreISelLowering.cpp
lib/Target/XCore/XCoreISelLowering.h
lib/Target/XCore/XCoreInstrInfo.cpp
lib/Target/XCore/XCoreInstrInfo.td
test/CodeGen/XCore/switch.ll [new file with mode: 0644]
test/CodeGen/XCore/switch_long.ll [new file with mode: 0644]

index d18f55de81ba5abcc2f0459fb4c4154b6c6891b5..82e23a13e802ebb9abd740b4783d3b6de23ad04d 100644 (file)
@@ -27,6 +27,7 @@
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/MachineConstantPool.h"
 #include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineJumpTableInfo.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSymbol.h"
 #include "llvm/Target/TargetData.h"
@@ -62,6 +63,11 @@ namespace {
     }
 
     void printMemOperand(const MachineInstr *MI, int opNum);
+    void printInlineJT(const MachineInstr *MI, int opNum,
+                       const std::string &directive = ".jmptable");
+    void printInlineJT32(const MachineInstr *MI, int opNum) {
+      printInlineJT(MI, opNum, ".jmptable32");
+    }
     void printOperand(const MachineInstr *MI, int opNum);
     bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
                         unsigned AsmVariant, const char *ExtraCode);
@@ -257,6 +263,23 @@ void XCoreAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum)
   printOperand(MI, opNum+1);
 }
 
+void XCoreAsmPrinter::
+printInlineJT(const MachineInstr *MI, int opNum, const std::string &directive)
+{
+  unsigned JTI = MI->getOperand(opNum).getIndex();
+  const MachineFunction *MF = MI->getParent()->getParent();
+  const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
+  const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
+  const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
+  O << "\t" << directive << " ";
+  for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) {
+    MachineBasicBlock *MBB = JTBBs[i];
+    if (i > 0)
+      O << ",";
+    O << *MBB->getSymbol(OutContext);
+  }
+}
+
 void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
   const MachineOperand &MO = MI->getOperand(opNum);
   switch (MO.getType()) {
index 57fd43b16bddf80f6c30c2cbc79366e1b96ddb08..667476cb257407ddf8bb1ba7edd5969ff10041aa 100644 (file)
@@ -29,6 +29,7 @@
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineJumpTableInfo.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/SelectionDAGISel.h"
 #include "llvm/CodeGen/ValueTypes.h"
@@ -53,6 +54,8 @@ getTargetNodeName(unsigned Opcode) const
     case XCoreISD::RETSP             : return "XCoreISD::RETSP";
     case XCoreISD::LADD              : return "XCoreISD::LADD";
     case XCoreISD::LSUB              : return "XCoreISD::LSUB";
+    case XCoreISD::BR_JT             : return "XCoreISD::BR_JT";
+    case XCoreISD::BR_JT32           : return "XCoreISD::BR_JT32";
     default                           : return NULL;
   }
 }
@@ -106,9 +109,8 @@ XCoreTargetLowering::XCoreTargetLowering(XCoreTargetMachine &XTM)
   
   setOperationAction(ISD::TRAP, MVT::Other, Legal);
   
-  // Expand jump tables for now
-  setOperationAction(ISD::BR_JT, MVT::Other, Expand);
-  setOperationAction(ISD::JumpTable, MVT::i32, Custom);
+  // Jump tables.
+  setOperationAction(ISD::BR_JT, MVT::Other, Custom);
 
   setOperationAction(ISD::GlobalAddress, MVT::i32,   Custom);
   setOperationAction(ISD::BlockAddress, MVT::i32 , Custom);
@@ -158,6 +160,7 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) {
   case ISD::BlockAddress:     return LowerBlockAddress(Op, DAG);
   case ISD::ConstantPool:     return LowerConstantPool(Op, DAG);
   case ISD::JumpTable:        return LowerJumpTable(Op, DAG);
+  case ISD::BR_JT:            return LowerBR_JT(Op, DAG);
   case ISD::LOAD:             return LowerLOAD(Op, DAG);
   case ISD::STORE:            return LowerSTORE(Op, DAG);
   case ISD::SELECT_CC:        return LowerSELECT_CC(Op, DAG);
@@ -325,6 +328,30 @@ LowerJumpTable(SDValue Op, SelectionDAG &DAG)
   return DAG.getNode(XCoreISD::DPRelativeWrapper, dl, MVT::i32, JTI);
 }
 
+SDValue XCoreTargetLowering::
+LowerBR_JT(SDValue Op, SelectionDAG &DAG)
+{
+  SDValue Chain = Op.getOperand(0);
+  SDValue Table = Op.getOperand(1);
+  SDValue Index = Op.getOperand(2);
+  DebugLoc dl = Op.getDebugLoc();
+  JumpTableSDNode *JT = cast<JumpTableSDNode>(Table);
+  unsigned JTI = JT->getIndex();
+  MachineFunction &MF = DAG.getMachineFunction();
+  const MachineJumpTableInfo *MJTI = MF.getJumpTableInfo();
+  SDValue TargetJT = DAG.getTargetJumpTable(JT->getIndex(), MVT::i32);
+
+  unsigned NumEntries = MJTI->getJumpTables()[JTI].MBBs.size();
+  if (NumEntries <= 32) {
+    return DAG.getNode(XCoreISD::BR_JT, dl, MVT::Other, Chain, TargetJT, Index);
+  }
+  assert((NumEntries >> 31) == 0);
+  SDValue ScaledIndex = DAG.getNode(ISD::SHL, dl, MVT::i32, Index,
+                                    DAG.getConstant(1, MVT::i32));
+  return DAG.getNode(XCoreISD::BR_JT32, dl, MVT::Other, Chain, TargetJT,
+                     ScaledIndex);
+}
+
 static bool
 IsWordAlignedBasePlusConstantOffset(SDValue Addr, SDValue &AlignedBase,
                                     int64_t &Offset)
index 5095f3638b59a6ef236ab2a66211b5ce9cc9be71..5675bdcc9275d0e0ee5df9f8b2eb2fef340ef5b6 100644 (file)
@@ -52,7 +52,13 @@ namespace llvm {
       LADD,
 
       // Corresponds to LSUB instruction
-      LSUB
+      LSUB,
+
+      // Jumptable branch.
+      BR_JT,
+
+      // Jumptable branch using long branches for each entry.
+      BR_JT32
     };
   }
 
@@ -123,6 +129,7 @@ namespace llvm {
     SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG);
     SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG);
     SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG);
+    SDValue LowerBR_JT(SDValue Op, SelectionDAG &DAG);
     SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG);
     SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG);
     SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG);
index 5a548449d841dc25e7219243096a7cb3e9670dd9..722e7470f066d1d1989e17c1bef1b6a751b385b1 100644 (file)
@@ -145,6 +145,11 @@ static inline bool IsCondBranch(unsigned BrOpc) {
   return IsBRF(BrOpc) || IsBRT(BrOpc);
 }
 
+static inline bool IsBR_JT(unsigned BrOpc) {
+  return BrOpc == XCore::BR_JT
+      || BrOpc == XCore::BR_JT32;
+}
+
 /// GetCondFromBranchOpc - Return the XCore CC that matches 
 /// the correspondent Branch instruction opcode.
 static XCore::CondCode GetCondFromBranchOpc(unsigned BrOpc) 
@@ -271,6 +276,14 @@ XCoreInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
     return false;
   }
 
+  // Likewise if it ends with a branch table followed by an unconditional branch.
+  if (IsBR_JT(SecondLastInst->getOpcode()) && IsBRU(LastInst->getOpcode())) {
+    I = LastInst;
+    if (AllowModify)
+      I->eraseFromParent();
+    return true;
+  }
+
   // Otherwise, can't handle this.
   return true;
 }
index 10dc18cfead08a0443c3d857f32f9fab88b98cb7..d702d183c3d30cd9da02dc3c72853167f459f9d2 100644 (file)
@@ -34,6 +34,15 @@ def XCoreBranchLink     : SDNode<"XCoreISD::BL",SDT_XCoreBranchLink,
 def XCoreRetsp       : SDNode<"XCoreISD::RETSP", SDTNone,
                          [SDNPHasChain, SDNPOptInFlag]>;
 
+def SDT_XCoreBR_JT    : SDTypeProfile<0, 2,
+                                      [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>;
+
+def XCoreBR_JT : SDNode<"XCoreISD::BR_JT", SDT_XCoreBR_JT,
+                        [SDNPHasChain]>;
+
+def XCoreBR_JT32 : SDNode<"XCoreISD::BR_JT32", SDT_XCoreBR_JT,
+                        [SDNPHasChain]>;
+
 def SDT_XCoreAddress    : SDTypeProfile<1, 1,
                             [SDTCisSameAs<0, 1>, SDTCisPtrTy<0>]>;
 
@@ -185,6 +194,15 @@ def MEMii : Operand<i32> {
   let MIOperandInfo = (ops i32imm, i32imm);
 }
 
+// Jump tables.
+def InlineJT : Operand<i32> {
+  let PrintMethod = "printInlineJT";
+}
+
+def InlineJT32 : Operand<i32> {
+  let PrintMethod = "printInlineJT32";
+}
+
 //===----------------------------------------------------------------------===//
 // Instruction Class Templates
 //===----------------------------------------------------------------------===//
@@ -756,13 +774,23 @@ def CLZ_l2r : _FL2R<(outs GRRegs:$dst), (ins GRRegs:$src),
 
 // One operand short
 // TODO edu, eeu, waitet, waitef, freer, tstart, msync, mjoin, syncr, clrtp
-// bru, setdp, setcp, setv, setev, kcall
+// setdp, setcp, setv, setev, kcall
 // dgetreg
 let isBranch=1, isIndirectBranch=1, isTerminator=1 in
 def BAU_1r : _F1R<(outs), (ins GRRegs:$addr),
                  "bau $addr",
                  [(brind GRRegs:$addr)]>;
 
+let isBranch=1, isIndirectBranch=1, isTerminator=1, isBarrier = 1 in
+def BR_JT : PseudoInstXCore<(outs), (ins InlineJT:$t, GRRegs:$i),
+                            "bru $i\n$t",
+                            [(XCoreBR_JT tjumptable:$t, GRRegs:$i)]>;
+
+let isBranch=1, isIndirectBranch=1, isTerminator=1, isBarrier = 1 in
+def BR_JT32 : PseudoInstXCore<(outs), (ins InlineJT32:$t, GRRegs:$i),
+                              "bru $i\n$t",
+                              [(XCoreBR_JT32 tjumptable:$t, GRRegs:$i)]>;
+
 let Defs=[SP], neverHasSideEffects=1 in
 def SETSP_1r : _F1R<(outs), (ins GRRegs:$src),
                  "set sp, $src",
diff --git a/test/CodeGen/XCore/switch.ll b/test/CodeGen/XCore/switch.ll
new file mode 100644 (file)
index 0000000..9cc27f2
--- /dev/null
@@ -0,0 +1,24 @@
+; RUN: llc -march=xcore < %s | FileCheck %s
+
+define i32 @switch(i32 %i) {
+entry:
+        switch i32 %i, label %default [
+                 i32 0, label %bb0
+                 i32 1, label %bb1
+                 i32 2, label %bb2
+                 i32 3, label %bb3
+        ]
+; CHECK-NOT: shl
+; CHECK: bru
+; CHECK: .jmptable
+bb0:
+        ret i32 0
+bb1:
+        ret i32 1
+bb2:
+        ret i32 2
+bb3:
+        ret i32 3
+default:
+        ret i32 4
+}
diff --git a/test/CodeGen/XCore/switch_long.ll b/test/CodeGen/XCore/switch_long.ll
new file mode 100644 (file)
index 0000000..30c9e3d
--- /dev/null
@@ -0,0 +1,132 @@
+; RUN: llc -march=xcore < %s | FileCheck %s
+
+define i32 @switch(i32 %i) {
+entry:
+        switch i32 %i, label %default [
+                 i32 0, label %bb0
+                 i32 1, label %bb1
+                 i32 2, label %bb2
+                 i32 3, label %bb3
+                 i32 4, label %bb4
+                 i32 5, label %bb5
+                 i32 6, label %bb6
+                 i32 7, label %bb7
+                 i32 8, label %bb8
+                 i32 9, label %bb9
+                 i32 10, label %bb10
+                 i32 11, label %bb11
+                 i32 12, label %bb12
+                 i32 13, label %bb13
+                 i32 14, label %bb14
+                 i32 15, label %bb15
+                 i32 16, label %bb16
+                 i32 17, label %bb17
+                 i32 18, label %bb18
+                 i32 19, label %bb19
+                 i32 20, label %bb20
+                 i32 21, label %bb21
+                 i32 22, label %bb22
+                 i32 23, label %bb23
+                 i32 24, label %bb24
+                 i32 25, label %bb25
+                 i32 26, label %bb26
+                 i32 27, label %bb27
+                 i32 28, label %bb28
+                 i32 29, label %bb29
+                 i32 30, label %bb30
+                 i32 31, label %bb31
+                 i32 32, label %bb32
+                 i32 33, label %bb33
+                 i32 34, label %bb34
+                 i32 35, label %bb35
+                 i32 36, label %bb36
+                 i32 37, label %bb37
+                 i32 38, label %bb38
+                 i32 39, label %bb39
+        ]
+; CHECK: shl
+; CHECK: bru
+; CHECK: .jmptable
+bb0:
+        ret i32 0
+bb1:
+        ret i32 1
+bb2:
+        ret i32 2
+bb3:
+        ret i32 3
+bb4:
+        ret i32 4
+bb5:
+        ret i32 5
+bb6:
+        ret i32 6
+bb7:
+        ret i32 7
+bb8:
+        ret i32 8
+bb9:
+        ret i32 9
+bb10:
+        ret i32 0
+bb11:
+        ret i32 1
+bb12:
+        ret i32 2
+bb13:
+        ret i32 3
+bb14:
+        ret i32 4
+bb15:
+        ret i32 5
+bb16:
+        ret i32 6
+bb17:
+        ret i32 7
+bb18:
+        ret i32 8
+bb19:
+        ret i32 9
+bb20:
+        ret i32 0
+bb21:
+        ret i32 1
+bb22:
+        ret i32 2
+bb23:
+        ret i32 3
+bb24:
+        ret i32 4
+bb25:
+        ret i32 5
+bb26:
+        ret i32 6
+bb27:
+        ret i32 7
+bb28:
+        ret i32 8
+bb29:
+        ret i32 9
+bb30:
+        ret i32 0
+bb31:
+        ret i32 1
+bb32:
+        ret i32 2
+bb33:
+        ret i32 3
+bb34:
+        ret i32 4
+bb35:
+        ret i32 5
+bb36:
+        ret i32 6
+bb37:
+        ret i32 7
+bb38:
+        ret i32 8
+bb39:
+        ret i32 9
+default:
+        ret i32 0
+}