Index: include/llvm/CodeGen/GlobalISel/IRTranslator.h =================================================================== --- include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -182,6 +182,8 @@ bool translateIndirectBr(const User &U, MachineIRBuilder &MIRBuilder); + bool translateSwitch(const User &U, MachineIRBuilder &MIRBuilder); + bool translateExtractValue(const User &U, MachineIRBuilder &MIRBuilder); bool translateInsertValue(const User &U, MachineIRBuilder &MIRBuilder); @@ -297,9 +299,6 @@ // Stubs to keep the compiler happy while we implement the rest of the // translation. - bool translateSwitch(const User &U, MachineIRBuilder &MIRBuilder) { - return false; - } bool translateResume(const User &U, MachineIRBuilder &MIRBuilder) { return false; } Index: lib/CodeGen/GlobalISel/IRTranslator.cpp =================================================================== --- lib/CodeGen/GlobalISel/IRTranslator.cpp +++ lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -213,6 +213,45 @@ return true; } +bool IRTranslator::translateSwitch(const User &U, + MachineIRBuilder &MIRBuilder) { + // For now, just translate as a chain of conditional branches. + // FIXME: could we share most of the logic/code in + // SelectionDAGBuilder::visitSwitch between SelectionDAG and GlobalISel? + // At first sight, it seems most of the logic in there is independent of + // SelectionDAG-specifics and a lot of work went in to optimize switch + // lowering in there. + + const SwitchInst &SwInst = cast(U); + const unsigned SwCondValue = getOrCreateVReg(*SwInst.getCondition()); + + LLT LLTi1 = LLT(*Type::getInt1Ty(U.getContext()), *DL); + for(auto& CaseIt: SwInst.cases()) { + const unsigned CaseValueReg = getOrCreateVReg(*CaseIt.getCaseValue()); + const unsigned Tst = MRI->createGenericVirtualRegister(LLTi1); + MIRBuilder.buildICmp(CmpInst::ICMP_EQ, Tst, CaseValueReg, SwCondValue); + MachineBasicBlock &CurBB = MIRBuilder.getMBB(); + MachineBasicBlock &TrueBB = getOrCreateBB(*CaseIt.getCaseSuccessor()); + + MIRBuilder.buildBrCond(Tst, TrueBB); + CurBB.addSuccessor(&TrueBB); + + MachineBasicBlock* FalseBB = + MF->CreateMachineBasicBlock(SwInst.getParent()); + MF->push_back(FalseBB); + MIRBuilder.buildBr(*FalseBB); + CurBB.addSuccessor(FalseBB); + + MIRBuilder.setMBB(*FalseBB); + } + // handle default case + MachineBasicBlock &DefaultBB = getOrCreateBB(*SwInst.getDefaultDest()); + MIRBuilder.buildBr(DefaultBB); + MIRBuilder.getMBB().addSuccessor(&DefaultBB); + + return true; +} + bool IRTranslator::translateLoad(const User &U, MachineIRBuilder &MIRBuilder) { const LoadInst &LI = cast(U); Index: test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll =================================================================== --- test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll +++ test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll @@ -136,6 +136,59 @@ ret void } +; Tests for switch. +; This gets lowered to a very straightforward sequence of comparisons for now. +; CHECK-LABEL: name: switch +; CHECK: body: +; +; CHECK: {{bb.[0-9]+.entry}}: +; CHECK-NEXT: successors: %[[BB_CASE100:bb.[0-9]+.case100]](0x40000000), %[[BB_NOTCASE100_CHECKNEXT:bb.[0-9]+.entry]](0x40000000) +; CHECK: %0(s32) = COPY %w0 +; CHECK: %[[reg100:[0-9]+]](s32) = G_CONSTANT i32 100 +; CHECK: %[[reg0:[0-9]+]](s32) = G_CONSTANT i32 0 +; CHECK: %[[reg1:[0-9]+]](s32) = G_CONSTANT i32 1 +; CHECK: %[[regicmp:[0-9]+]](s1) = G_ICMP intpred(eq), %[[reg100]](s32), %0 +; CHECK: G_BRCOND %[[regicmp]](s1), %[[BB_CASE100]] +; CHECK: G_BR %[[BB_NOTCASE100_CHECKNEXT]] +; +; CHECK: [[BB_CASE100]]: +; CHECK-NEXT: successors: %[[BB_RET:bb.[0-9]+.return]](0x80000000) +; CHECK: %[[regretc100:[0-9]+]](s32) = G_ADD %0, %[[reg1]] +; CHECK: G_BR %[[BB_RET]] +; +; CHECK: [[BB_NOTCASE100_CHECKNEXT]]: +; CHECK-NEXT: successors: %[[BB_DEFAULT:bb.[0-9]+.default]](0x80000000) +; CHECK: G_BR %[[BB_DEFAULT]] +; +; CHECK: [[BB_DEFAULT]]: +; CHECK-NEXT: successors: %[[BB_RET]](0x80000000) +; CHECK: %[[regretdefault:[0-9]+]](s32) = G_ADD %0, %[[reg0]] +; CHECK: G_BR %[[BB_RET]] +; +; CHECK: [[BB_RET]]: +; CHECK-NEXT: %[[regret:[0-9]+]](s32) = PHI %[[regretdefault]](s32), %[[BB_DEFAULT]], %[[regretc100]](s32), %[[BB_CASE100]] +; CHECK: %w0 = COPY %[[regret]](s32) +; CHECK: RET_ReallyLR implicit %w0 +define i32 @switch(i32 %argc) { +entry: + switch i32 %argc, label %default [ + i32 100, label %case100 + ] + +default: + %0 = add i32 %argc, 0 + br label %return + +case100: + %1 = add i32 %argc, 1 + br label %return + +return: + %2 = phi i32 [ %0, %default ], [ %1, %case100 ] + ret i32 %2 +} + + ; Tests for or. ; CHECK-LABEL: name: ori64 ; CHECK: [[ARG1:%[0-9]+]](s64) = COPY %x0