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);
// 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;
}
/// \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
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.
/// 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)
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);
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);
}
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;
// 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})
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 }
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
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