mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-19 02:52:53 +02:00
[GlobalISel] Add support for indirectbr
Differential Revision: https://reviews.llvm.org/D28079 llvm-svn: 293470
This commit is contained in:
parent
47c6fb27f5
commit
942514e271
@ -190,6 +190,8 @@ private:
|
|||||||
|
|
||||||
bool translateSwitch(const User &U, MachineIRBuilder &MIRBuilder);
|
bool translateSwitch(const User &U, MachineIRBuilder &MIRBuilder);
|
||||||
|
|
||||||
|
bool translateIndirectBr(const User &U, MachineIRBuilder &MIRBuilder);
|
||||||
|
|
||||||
bool translateExtractValue(const User &U, MachineIRBuilder &MIRBuilder);
|
bool translateExtractValue(const User &U, MachineIRBuilder &MIRBuilder);
|
||||||
|
|
||||||
bool translateInsertValue(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
|
// Stubs to keep the compiler happy while we implement the rest of the
|
||||||
// translation.
|
// translation.
|
||||||
bool translateIndirectBr(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool translateResume(const User &U, MachineIRBuilder &MIRBuilder) {
|
bool translateResume(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -322,6 +322,16 @@ public:
|
|||||||
/// \return The newly created instruction.
|
/// \return The newly created instruction.
|
||||||
MachineInstrBuilder buildBrCond(unsigned Tst, MachineBasicBlock &BB);
|
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
|
/// Build and insert \p Res = G_CONSTANT \p Val
|
||||||
///
|
///
|
||||||
/// G_CONSTANT is an integer constant with the specified size and value. \p
|
/// G_CONSTANT is an integer constant with the specified size and value. \p
|
||||||
|
@ -445,4 +445,13 @@ def G_BRCOND : Instruction {
|
|||||||
let isTerminator = 1;
|
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.
|
// TODO: Add the other generic opcodes.
|
||||||
|
@ -251,6 +251,9 @@ HANDLE_TARGET_OPCODE(G_STORE)
|
|||||||
/// Generic conditional branch instruction.
|
/// Generic conditional branch instruction.
|
||||||
HANDLE_TARGET_OPCODE(G_BRCOND)
|
HANDLE_TARGET_OPCODE(G_BRCOND)
|
||||||
|
|
||||||
|
/// Generic indirect branch instruction.
|
||||||
|
HANDLE_TARGET_OPCODE(G_BRINDIRECT)
|
||||||
|
|
||||||
/// Generic intrinsic use (without side effects).
|
/// Generic intrinsic use (without side effects).
|
||||||
HANDLE_TARGET_OPCODE(G_INTRINSIC)
|
HANDLE_TARGET_OPCODE(G_INTRINSIC)
|
||||||
|
|
||||||
|
@ -252,6 +252,21 @@ bool IRTranslator::translateSwitch(const User &U,
|
|||||||
return true;
|
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) {
|
bool IRTranslator::translateLoad(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||||
const LoadInst &LI = cast<LoadInst>(U);
|
const LoadInst &LI = cast<LoadInst>(U);
|
||||||
|
|
||||||
|
@ -217,6 +217,10 @@ MachineInstrBuilder MachineIRBuilder::buildBr(MachineBasicBlock &Dest) {
|
|||||||
return buildInstr(TargetOpcode::G_BR).addMBB(&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) {
|
MachineInstrBuilder MachineIRBuilder::buildCopy(unsigned Res, unsigned Op) {
|
||||||
return buildInstr(TargetOpcode::COPY).addDef(Res).addUse(Op);
|
return buildInstr(TargetOpcode::COPY).addDef(Res).addUse(Op);
|
||||||
}
|
}
|
||||||
|
@ -525,6 +525,11 @@ bool AArch64InstructionSelector::select(MachineInstr &I) const {
|
|||||||
return constrainSelectedInstRegOperands(*MIB.getInstr(), TII, TRI, RBI);
|
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_FCONSTANT:
|
||||||
case TargetOpcode::G_CONSTANT: {
|
case TargetOpcode::G_CONSTANT: {
|
||||||
const bool isFP = Opcode == TargetOpcode::G_FCONSTANT;
|
const bool isFP = Opcode == TargetOpcode::G_FCONSTANT;
|
||||||
|
@ -167,6 +167,7 @@ AArch64LegalizerInfo::AArch64LegalizerInfo() {
|
|||||||
// Control-flow
|
// Control-flow
|
||||||
for (auto Ty : {s1, s8, s16, s32})
|
for (auto Ty : {s1, s8, s16, s32})
|
||||||
setAction({G_BRCOND, Ty}, Legal);
|
setAction({G_BRCOND, Ty}, Legal);
|
||||||
|
setAction({G_BRINDIRECT, p0}, Legal);
|
||||||
|
|
||||||
// Select
|
// Select
|
||||||
for (auto Ty : {s1, s8, s16, s32, s64, p0})
|
for (auto Ty : {s1, s8, s16, s32, s64, p0})
|
||||||
|
@ -79,6 +79,7 @@
|
|||||||
|
|
||||||
define void @unconditional_br() { ret void }
|
define void @unconditional_br() { ret void }
|
||||||
define void @conditional_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_s64_gpr(i64* %addr) { ret void }
|
||||||
define void @load_s32_gpr(i32* %addr) { ret void }
|
define void @load_s32_gpr(i32* %addr) { ret void }
|
||||||
@ -1510,6 +1511,28 @@ body: |
|
|||||||
bb.1:
|
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
|
# CHECK-LABEL: name: load_s64_gpr
|
||||||
name: load_s64_gpr
|
name: load_s64_gpr
|
||||||
|
@ -217,6 +217,42 @@ phi.block:
|
|||||||
ret i32 12
|
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.
|
; Tests for or.
|
||||||
; CHECK-LABEL: name: ori64
|
; CHECK-LABEL: name: ori64
|
||||||
; CHECK: [[ARG1:%[0-9]+]](s64) = COPY %x0
|
; CHECK: [[ARG1:%[0-9]+]](s64) = COPY %x0
|
||||||
|
Loading…
Reference in New Issue
Block a user