Index: llvm/trunk/include/llvm/CodeGen/GlobalISel/IRTranslator.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ llvm/trunk/include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -180,6 +180,8 @@ /// \pre \p U is a branch instruction. bool translateBr(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); @@ -292,12 +294,8 @@ return translateBinaryOp(TargetOpcode::G_FREM, U, MIRBuilder); } - // Stubs to keep the compiler happy while we implement the rest of the // translation. - bool translateSwitch(const User &U, MachineIRBuilder &MIRBuilder) { - return false; - } bool translateIndirectBr(const User &U, MachineIRBuilder &MIRBuilder) { return false; } Index: llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp =================================================================== --- llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -195,6 +195,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: llvm/trunk/test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll =================================================================== --- llvm/trunk/test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll +++ llvm/trunk/test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll @@ -100,6 +100,75 @@ 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]+}}: +; CHECK-NEXT: successors: %[[BB_CASE100:bb.[0-9]+]](0x40000000), %[[BB_NOTCASE100_CHECKNEXT:bb.[0-9]+.entry]](0x40000000) +; CHECK: %0(s32) = COPY %w0 +; CHECK: %[[reg100:[0-9]+]](s32) = G_CONSTANT i32 100 +; CHECK: %[[reg200:[0-9]+]](s32) = G_CONSTANT i32 200 +; CHECK: %[[reg0:[0-9]+]](s32) = G_CONSTANT i32 0 +; CHECK: %[[reg1:[0-9]+]](s32) = G_CONSTANT i32 1 +; CHECK: %[[reg2:[0-9]+]](s32) = G_CONSTANT i32 2 +; CHECK: %[[regicmp100:[0-9]+]](s1) = G_ICMP intpred(eq), %[[reg100]](s32), %0 +; CHECK: G_BRCOND %[[regicmp100]](s1), %[[BB_CASE100]] +; CHECK: G_BR %[[BB_NOTCASE100_CHECKNEXT]] +; +; CHECK: [[BB_CASE100]]: +; CHECK-NEXT: successors: %[[BB_RET:bb.[0-9]+]](0x80000000) +; CHECK: %[[regretc100:[0-9]+]](s32) = G_ADD %0, %[[reg1]] +; CHECK: G_BR %[[BB_RET]] +; CHECK: [[BB_NOTCASE100_CHECKNEXT]]: +; CHECK-NEXT: successors: %[[BB_CASE200:bb.[0-9]+]](0x40000000), %[[BB_NOTCASE200_CHECKNEXT:bb.[0-9]+.entry]](0x40000000) +; CHECK: %[[regicmp200:[0-9]+]](s1) = G_ICMP intpred(eq), %[[reg200]](s32), %0 +; CHECK: G_BRCOND %[[regicmp200]](s1), %[[BB_CASE200]] +; CHECK: G_BR %[[BB_NOTCASE200_CHECKNEXT]] +; +; CHECK: [[BB_CASE200]]: +; CHECK-NEXT: successors: %[[BB_RET:bb.[0-9]+]](0x80000000) +; CHECK: %[[regretc200:[0-9]+]](s32) = G_ADD %0, %[[reg2]] +; CHECK: G_BR %[[BB_RET]] +; CHECK: [[BB_NOTCASE200_CHECKNEXT]]: +; CHECK-NEXT: successors: %[[BB_DEFAULT:bb.[0-9]+]](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 + i32 200, label %case200 + ] + +default: + %tmp0 = add i32 %argc, 0 + br label %return + +case100: + %tmp1 = add i32 %argc, 1 + br label %return + +case200: + %tmp2 = add i32 %argc, 2 + br label %return + +return: + %res = phi i32 [ %tmp0, %default ], [ %tmp1, %case100 ], [ %tmp2, %case200 ] + ret i32 %res +} + + ; Tests for or. ; CHECK-LABEL: name: ori64 ; CHECK: [[ARG1:%[0-9]+]](s64) = COPY %x0