]> granicus.if.org Git - llvm/commitdiff
[GlobalISel] Add support for indirectbr
authorKristof Beyls <kristof.beyls@arm.com>
Mon, 30 Jan 2017 09:13:18 +0000 (09:13 +0000)
committerKristof Beyls <kristof.beyls@arm.com>
Mon, 30 Jan 2017 09:13:18 +0000 (09:13 +0000)
Differential Revision: https://reviews.llvm.org/D28079

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

include/llvm/CodeGen/GlobalISel/IRTranslator.h
include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
include/llvm/Target/GenericOpcodes.td
include/llvm/Target/TargetOpcodes.def
lib/CodeGen/GlobalISel/IRTranslator.cpp
lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
lib/Target/AArch64/AArch64InstructionSelector.cpp
lib/Target/AArch64/AArch64LegalizerInfo.cpp
test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir
test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll

index 79a6da42160875285b298dced9c15669aab12259..07df370ee5970e249e0d6d70b0759f18a768eb9b 100644 (file)
@@ -190,6 +190,8 @@ private:
 
   bool translateSwitch(const User &U, MachineIRBuilder &MIRBuilder);
 
+  bool translateIndirectBr(const User &U, MachineIRBuilder &MIRBuilder);
+
   bool translateExtractValue(const User &U, MachineIRBuilder &MIRBuilder);
 
   bool translateInsertValue(const User &U, MachineIRBuilder &MIRBuilder);
@@ -304,9 +306,6 @@ private:
 
   // Stubs to keep the compiler happy while we implement the rest of the
   // translation.
-  bool translateIndirectBr(const User &U, MachineIRBuilder &MIRBuilder) {
-    return false;
-  }
   bool translateResume(const User &U, MachineIRBuilder &MIRBuilder) {
     return false;
   }
index 94d179f10d6ed273054b659d1688e43be5c787fe..353aab5e12b7a051b30842211b35c481c92d145c 100644 (file)
@@ -322,6 +322,16 @@ public:
   /// \return The newly created instruction.
   MachineInstrBuilder buildBrCond(unsigned Tst, MachineBasicBlock &BB);
 
+  /// Build and insert G_BRINDIRECT \p Tgt
+  ///
+  /// G_BRINDIRECT is an indirect branch to \p Tgt.
+  ///
+  /// \pre setBasicBlock or setMI must have been called.
+  /// \pre \p Tgt must be a generic virtual register with pointer type.
+  ///
+  /// \return a MachineInstrBuilder for the newly created instruction.
+  MachineInstrBuilder buildBrIndirect(unsigned Tgt);
+
   /// Build and insert \p Res = G_CONSTANT \p Val
   ///
   /// G_CONSTANT is an integer constant with the specified size and value. \p
index 8694eb5797d04423a8aa070c96d93a95c443e679..d3b2835d1bd403a4fad743400d5cee6c8d95f5d6 100644 (file)
@@ -445,4 +445,13 @@ def G_BRCOND : Instruction {
   let isTerminator = 1;
 }
 
+// Generic indirect branch.
+def G_BRINDIRECT : Instruction {
+  let OutOperandList = (outs);
+  let InOperandList = (ins type0:$src1);
+  let hasSideEffects = 0;
+  let isBranch = 1;
+  let isTerminator = 1;
+}
+
 // TODO: Add the other generic opcodes.
index 04e9a3ebbc6959b539e5433ca0958ce34dd364f6..cd62a19fdf16734e753b5a81fe2aa95f71f2b6aa 100644 (file)
@@ -251,6 +251,9 @@ HANDLE_TARGET_OPCODE(G_STORE)
 /// Generic conditional branch instruction.
 HANDLE_TARGET_OPCODE(G_BRCOND)
 
+/// Generic indirect branch instruction.
+HANDLE_TARGET_OPCODE(G_BRINDIRECT)
+
 /// Generic intrinsic use (without side effects).
 HANDLE_TARGET_OPCODE(G_INTRINSIC)
 
index 1a667d60166a503e8ebd09eda0b05b2608072b55..58bd65ef323bef8d28ebbf13866d0b75e7c80ce9 100644 (file)
@@ -252,6 +252,21 @@ bool IRTranslator::translateSwitch(const User &U,
   return true;
 }
 
+bool IRTranslator::translateIndirectBr(const User &U,
+                                       MachineIRBuilder &MIRBuilder) {
+  const IndirectBrInst &BrInst = cast<IndirectBrInst>(U);
+
+  const unsigned Tgt = getOrCreateVReg(*BrInst.getAddress());
+  MIRBuilder.buildBrIndirect(Tgt);
+
+  // Link successors.
+  MachineBasicBlock &CurBB = MIRBuilder.getMBB();
+  for (const BasicBlock *Succ : BrInst.successors())
+    CurBB.addSuccessor(&getOrCreateBB(*Succ));
+
+  return true;
+}
+
 bool IRTranslator::translateLoad(const User &U, MachineIRBuilder &MIRBuilder) {
   const LoadInst &LI = cast<LoadInst>(U);
 
index ae1550d0d3d3cfc9b655caf142266d2bc3e21578..01457260ca64755aeb20800644d41bff93d9b291 100644 (file)
@@ -217,6 +217,10 @@ MachineInstrBuilder MachineIRBuilder::buildBr(MachineBasicBlock &Dest) {
   return buildInstr(TargetOpcode::G_BR).addMBB(&Dest);
 }
 
+MachineInstrBuilder MachineIRBuilder::buildBrIndirect(unsigned Tgt) {
+  return buildInstr(TargetOpcode::G_BRINDIRECT).addUse(Tgt);
+}
+
 MachineInstrBuilder MachineIRBuilder::buildCopy(unsigned Res, unsigned Op) {
   return buildInstr(TargetOpcode::COPY).addDef(Res).addUse(Op);
 }
index 5c03ea930af823a87516bc5476029cead2e05ed3..21d80ca9f812f9a98be1c78e2c0e64096b59069a 100644 (file)
@@ -525,6 +525,11 @@ bool AArch64InstructionSelector::select(MachineInstr &I) const {
     return constrainSelectedInstRegOperands(*MIB.getInstr(), TII, TRI, RBI);
   }
 
+  case TargetOpcode::G_BRINDIRECT: {
+    I.setDesc(TII.get(AArch64::BR));
+    return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
+  }
+
   case TargetOpcode::G_FCONSTANT:
   case TargetOpcode::G_CONSTANT: {
     const bool isFP = Opcode == TargetOpcode::G_FCONSTANT;
index 9d774f6b282426720772ae9a1afaafed64addb20..86037c97731c4c457e6e0fada7153fa6621e2230 100644 (file)
@@ -167,6 +167,7 @@ AArch64LegalizerInfo::AArch64LegalizerInfo() {
   // Control-flow
   for (auto Ty : {s1, s8, s16, s32})
     setAction({G_BRCOND, Ty}, Legal);
+  setAction({G_BRINDIRECT, p0}, Legal);
 
   // Select
   for (auto Ty : {s1, s8, s16, s32, s64, p0})
index 0d51462aad23c872512fad8270781b726e3766d5..6b8a9900039247064f9632b8747da524cc3082cf 100644 (file)
@@ -79,6 +79,7 @@
 
   define void @unconditional_br() { ret void }
   define void @conditional_br() { ret void }
+  define void @indirect_br() { ret void }
 
   define void @load_s64_gpr(i64* %addr) { ret void }
   define void @load_s32_gpr(i32* %addr) { ret void }
@@ -1510,6 +1511,28 @@ body:             |
   bb.1:
 ...
 
+---
+# CHECK-LABEL: name: indirect_br
+name:            indirect_br
+legalized:       true
+regBankSelected: true
+
+registers:
+  - { id: 0, class: gpr }
+
+# CHECK:  body:
+# CHECK:   bb.0:
+# CHECK:    %0 = COPY %x0
+# CHECK:    BR %0
+body:             |
+  bb.0:
+    successors: %bb.0, %bb.1
+    %0(p0) = COPY %x0
+    G_BRINDIRECT %0(p0)
+
+  bb.1:
+...
+
 ---
 # CHECK-LABEL: name: load_s64_gpr
 name:            load_s64_gpr
index aa5a07dad4afd629776ea766846ac8bbf7303479..3938a3a89613466dac6a9c7df3a9b65fcb47c7df 100644 (file)
@@ -217,6 +217,42 @@ phi.block:
   ret i32 12
 }
 
+; Tests for indirect br.
+; CHECK-LABEL: name: indirectbr
+; CHECK: body:
+;
+; ABI/constant lowering and IR-level entry basic block.
+; CHECK: {{bb.[0-9]+.entry}}:
+; Make sure we have one successor
+; CHECK-NEXT: successors: %[[BB_L1:bb.[0-9]+.L1]](0x80000000)
+; CHECK: G_BR %[[BB_L1]]
+;
+; Check basic block L1 has 2 successors: BBL1 and BBL2
+; CHECK: [[BB_L1]] (address-taken):
+; CHECK-NEXT: successors: %[[BB_L1]](0x40000000),
+; CHECK:                  %[[BB_L2:bb.[0-9]+.L2]](0x40000000)
+; CHECK: G_BRINDIRECT %{{[0-9]+}}(p0)
+;
+; Check basic block L2 is the return basic block
+; CHECK: [[BB_L2]] (address-taken):
+; CHECK-NEXT: RET_ReallyLR
+
+@indirectbr.L = internal unnamed_addr constant [3 x i8*] [i8* blockaddress(@indirectbr, %L1), i8* blockaddress(@indirectbr, %L2), i8* null], align 8
+
+define void @indirectbr() {
+entry:
+  br label %L1
+L1:                                               ; preds = %entry, %L1
+  %i = phi i32 [ 0, %entry ], [ %inc, %L1 ]
+  %inc = add i32 %i, 1
+  %idxprom = zext i32 %i to i64
+  %arrayidx = getelementptr inbounds [3 x i8*], [3 x i8*]* @indirectbr.L, i64 0, i64 %idxprom
+  %brtarget = load i8*, i8** %arrayidx, align 8
+  indirectbr i8* %brtarget, [label %L1, label %L2]
+L2:                                               ; preds = %L1
+  ret void
+}
+
 ; Tests for or.
 ; CHECK-LABEL: name: ori64
 ; CHECK: [[ARG1:%[0-9]+]](s64) = COPY %x0