From: Kristof Beyls Date: Mon, 30 Jan 2017 09:13:18 +0000 (+0000) Subject: [GlobalISel] Add support for indirectbr X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e9939d4d42144198e000143b5b3a3adf9f3add95;p=llvm [GlobalISel] Add support for indirectbr Differential Revision: https://reviews.llvm.org/D28079 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@293470 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/include/llvm/CodeGen/GlobalISel/IRTranslator.h index 79a6da42160..07df370ee59 100644 --- a/include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ b/include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -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; } diff --git a/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h index 94d179f10d6..353aab5e12b 100644 --- a/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -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 diff --git a/include/llvm/Target/GenericOpcodes.td b/include/llvm/Target/GenericOpcodes.td index 8694eb5797d..d3b2835d1bd 100644 --- a/include/llvm/Target/GenericOpcodes.td +++ b/include/llvm/Target/GenericOpcodes.td @@ -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. diff --git a/include/llvm/Target/TargetOpcodes.def b/include/llvm/Target/TargetOpcodes.def index 04e9a3ebbc6..cd62a19fdf1 100644 --- a/include/llvm/Target/TargetOpcodes.def +++ b/include/llvm/Target/TargetOpcodes.def @@ -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) diff --git a/lib/CodeGen/GlobalISel/IRTranslator.cpp b/lib/CodeGen/GlobalISel/IRTranslator.cpp index 1a667d60166..58bd65ef323 100644 --- a/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -252,6 +252,21 @@ bool IRTranslator::translateSwitch(const User &U, return true; } +bool IRTranslator::translateIndirectBr(const User &U, + MachineIRBuilder &MIRBuilder) { + const IndirectBrInst &BrInst = cast(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(U); diff --git a/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index ae1550d0d3d..01457260ca6 100644 --- a/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -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); } diff --git a/lib/Target/AArch64/AArch64InstructionSelector.cpp b/lib/Target/AArch64/AArch64InstructionSelector.cpp index 5c03ea930af..21d80ca9f81 100644 --- a/lib/Target/AArch64/AArch64InstructionSelector.cpp +++ b/lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -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; diff --git a/lib/Target/AArch64/AArch64LegalizerInfo.cpp b/lib/Target/AArch64/AArch64LegalizerInfo.cpp index 9d774f6b282..86037c97731 100644 --- a/lib/Target/AArch64/AArch64LegalizerInfo.cpp +++ b/lib/Target/AArch64/AArch64LegalizerInfo.cpp @@ -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}) diff --git a/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir b/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir index 0d51462aad2..6b8a9900039 100644 --- a/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir +++ b/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir @@ -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 diff --git a/test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll b/test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll index aa5a07dad4a..3938a3a8961 100644 --- a/test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll +++ b/test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll @@ -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