Index: lib/Target/RISCV/RISCVInstrInfo.h =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.h +++ lib/Target/RISCV/RISCVInstrInfo.h @@ -46,6 +46,22 @@ void movImm32(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, unsigned DstReg, uint64_t Val, MachineInstr::MIFlag Flag = MachineInstr::NoFlags) const; + + bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify) const override; + + unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, ArrayRef Cond, + const DebugLoc &dl, + int *BytesAdded = nullptr) const override; + + unsigned removeBranch(MachineBasicBlock &MBB, + int *BytesRemoved = nullptr) const override; + + bool + reverseBranchCondition(SmallVectorImpl &Cond) const override; }; } #endif Index: lib/Target/RISCV/RISCVInstrInfo.cpp =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.cpp +++ lib/Target/RISCV/RISCVInstrInfo.cpp @@ -95,3 +95,169 @@ .addImm(Lo12) .setMIFlag(Flag); } + +// The contents of values added to Cond are not examined outside of +// RISCVInstrInfo, giving us flexibility in what to push to it. For RISCV, we +// push BranchOpcode, Reg1, Reg2. +static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target, + SmallVectorImpl &Cond) { + // Block ends with fall-through condbranch. + assert(LastInst.getDesc().isConditionalBranch() && + "Unknown conditional branch"); + Target = LastInst.getOperand(2).getMBB(); + Cond.push_back(MachineOperand::CreateImm(LastInst.getOpcode())); + Cond.push_back(LastInst.getOperand(0)); + Cond.push_back(LastInst.getOperand(1)); +} + +static unsigned getOppositeBranchOpcode(int Opc) { + switch (Opc) { + default: + llvm_unreachable("Unrecognized conditional branch"); + case RISCV::BEQ: + return RISCV::BNE; + case RISCV::BNE: + return RISCV::BEQ; + case RISCV::BLT: + return RISCV::BGE; + case RISCV::BGE: + return RISCV::BLT; + case RISCV::BLTU: + return RISCV::BGEU; + case RISCV::BGEU: + return RISCV::BLTU; + } +} + +bool RISCVInstrInfo::analyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify) const { + TBB = FBB = nullptr; + Cond.clear(); + + // If the block has no terminators, it just falls into the block after it. + MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); + if (I == MBB.end() || !isUnpredicatedTerminator(*I)) + return false; + + // Count the number of terminators and find the first unconditional or + // indirect branch. + MachineBasicBlock::iterator FirstUncondOrIndirectBr = MBB.end(); + int NumTerminators = 0; + for (auto J = I.getReverse(); J != MBB.rend() && isUnpredicatedTerminator(*J); + J++) { + NumTerminators++; + if (J->getDesc().isUnconditionalBranch() || + J->getDesc().isIndirectBranch()) { + FirstUncondOrIndirectBr = J.getReverse(); + } + } + + // If AllowModify is true, we can erase any terminators after + // FirstUncondOrIndirectBR. + if (AllowModify && FirstUncondOrIndirectBr != MBB.end()) { + while (std::next(FirstUncondOrIndirectBr) != MBB.end()) { + std::next(FirstUncondOrIndirectBr)->eraseFromParent(); + NumTerminators--; + } + I = FirstUncondOrIndirectBr; + } + + // We can't handle blocks that end in an indirect branch. + if (I->getDesc().isIndirectBranch()) + return true; + + // We can't handle blocks with more than 2 terminators. + if (NumTerminators > 2) + return true; + + // Handle a single unconditional branch. + if (NumTerminators == 1 && I->getDesc().isUnconditionalBranch()) { + TBB = I->getOperand(0).getMBB(); + return false; + } + + // Handle a single conditional branch. + if (NumTerminators == 1 && I->getDesc().isConditionalBranch()) { + parseCondBranch(*I, TBB, Cond); + return false; + } + + // Handle a conditional branch followed by an unconditional branch. + if (NumTerminators == 2 && std::prev(I)->getDesc().isConditionalBranch() && + I->getDesc().isUnconditionalBranch()) { + parseCondBranch(*std::prev(I), TBB, Cond); + FBB = I->getOperand(0).getMBB(); + return false; + } + + // Otherwise, we can't handle this. + return true; +} + +unsigned RISCVInstrInfo::removeBranch(MachineBasicBlock &MBB, + int *BytesRemoved) const { + assert(!BytesRemoved && "Code size not handled"); + MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); + if (I == MBB.end()) + return 0; + + if (!I->getDesc().isUnconditionalBranch() && + !I->getDesc().isConditionalBranch()) + return 0; + + // Remove the branch. + I->eraseFromParent(); + + I = MBB.end(); + + if (I == MBB.begin()) + return 1; + --I; + if (!I->getDesc().isConditionalBranch()) + return 1; + + // Remove the branch. + I->eraseFromParent(); + return 2; +} + +// Inserts a branch into the end of the specific MachineBasicBlock, returning +// the number of instructions inserted. +unsigned RISCVInstrInfo::insertBranch( + MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, + ArrayRef Cond, const DebugLoc &DL, int *BytesAdded) const { + assert(!BytesAdded && "Code size not handled."); + + // Shouldn't be a fall through. + assert(TBB && "InsertBranch must not be told to insert a fallthrough"); + assert((Cond.size() == 3 || Cond.size() == 0) && + "RISCV branch conditions have two components!"); + + // Unconditional branch. + if (Cond.empty()) { + BuildMI(&MBB, DL, get(RISCV::PseudoBR)).addMBB(TBB); + return 1; + } + + // Either a one or two-way conditional branch. + unsigned Opc = Cond[0].getImm(); + BuildMI(&MBB, DL, get(Opc)).add(Cond[1]).add(Cond[2]).addMBB(TBB); + + // One-way conditional branch. + if (!FBB) + return 1; + + // Two-way conditional branch. + BuildMI(&MBB, DL, get(RISCV::PseudoBR)).addMBB(FBB); + return 2; +} + +bool RISCVInstrInfo::reverseBranchCondition( + SmallVectorImpl &Cond) const { + assert((Cond.size() == 3) && "Invalid branch condition!"); + Cond[0].setImm(getOppositeBranchOpcode(Cond[0].getImm())); + return false; +} Index: test/CodeGen/RISCV/analyze-branch.ll =================================================================== --- /dev/null +++ test/CodeGen/RISCV/analyze-branch.ll @@ -0,0 +1,91 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32I %s + +; This test checks that LLVM can do basic stripping and reapplying of branches +; to basic blocks. + +declare void @test_true() +declare void @test_false() + +; !0 corresponds to a branch being taken, !1 to not being takne. +!0 = !{!"branch_weights", i32 64, i32 4} +!1 = !{!"branch_weights", i32 4, i32 64} + +define void @test_bcc_fallthrough_taken(i32 %in) nounwind { +; RV32I-LABEL: test_bcc_fallthrough_taken: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: addi a1, zero, 42 +; RV32I-NEXT: bne a0, a1, .LBB0_3 +; RV32I-NEXT: # %bb.1: # %true +; RV32I-NEXT: lui a0, %hi(test_true) +; RV32I-NEXT: addi a0, a0, %lo(test_true) +; RV32I-NEXT: .LBB0_2: # %true +; RV32I-NEXT: jalr a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret +; RV32I-NEXT: .LBB0_3: # %false +; RV32I-NEXT: lui a0, %hi(test_false) +; RV32I-NEXT: addi a0, a0, %lo(test_false) +; RV32I-NEXT: j .LBB0_2 + %tst = icmp eq i32 %in, 42 + br i1 %tst, label %true, label %false, !prof !0 + +; Expected layout order is: Entry, TrueBlock, FalseBlock +; Entry->TrueBlock is the common path, which should be taken whenever the +; conditional branch is false. + +true: + call void @test_true() + ret void + +false: + call void @test_false() + ret void +} + +define void @test_bcc_fallthrough_nottaken(i32 %in) nounwind { +; RV32I-LABEL: test_bcc_fallthrough_nottaken: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: sw s0, 8(sp) +; RV32I-NEXT: addi s0, sp, 16 +; RV32I-NEXT: addi a1, zero, 42 +; RV32I-NEXT: beq a0, a1, .LBB1_1 +; RV32I-NEXT: # %bb.3: # %false +; RV32I-NEXT: lui a0, %hi(test_false) +; RV32I-NEXT: addi a0, a0, %lo(test_false) +; RV32I-NEXT: .LBB1_2: # %true +; RV32I-NEXT: jalr a0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret +; RV32I-NEXT: .LBB1_1: # %true +; RV32I-NEXT: lui a0, %hi(test_true) +; RV32I-NEXT: addi a0, a0, %lo(test_true) +; RV32I-NEXT: j .LBB1_2 + %tst = icmp eq i32 %in, 42 + br i1 %tst, label %true, label %false, !prof !1 + +; Expected layout order is: Entry, FalseBlock, TrueBlock +; Entry->FalseBlock is the common path, which should be taken whenever the +; conditional branch is false + +true: + call void @test_true() + ret void + +false: + call void @test_false() + ret void +} + +; TODO: how can we expand the coverage of the branch analysis functions? Index: test/CodeGen/RISCV/branch.ll =================================================================== --- test/CodeGen/RISCV/branch.ll +++ test/CodeGen/RISCV/branch.ll @@ -11,49 +11,38 @@ ; RV32I-NEXT: addi s0, sp, 16 ; RV32I-NEXT: lw a3, 0(a1) ; RV32I-NEXT: beq a3, a0, .LBB0_12 -; RV32I-NEXT: j .LBB0_1 -; RV32I-NEXT: .LBB0_1: # %test2 +; RV32I-NEXT: # %bb.1: # %test2 ; RV32I-NEXT: lw a3, 0(a1) ; RV32I-NEXT: bne a3, a0, .LBB0_12 -; RV32I-NEXT: j .LBB0_2 -; RV32I-NEXT: .LBB0_2: # %test3 +; RV32I-NEXT: # %bb.2: # %test3 ; RV32I-NEXT: lw a3, 0(a1) ; RV32I-NEXT: blt a3, a0, .LBB0_12 -; RV32I-NEXT: j .LBB0_3 -; RV32I-NEXT: .LBB0_3: # %test4 +; RV32I-NEXT: # %bb.3: # %test4 ; RV32I-NEXT: lw a3, 0(a1) ; RV32I-NEXT: bge a3, a0, .LBB0_12 -; RV32I-NEXT: j .LBB0_4 -; RV32I-NEXT: .LBB0_4: # %test5 +; RV32I-NEXT: # %bb.4: # %test5 ; RV32I-NEXT: lw a3, 0(a1) ; RV32I-NEXT: bltu a3, a0, .LBB0_12 -; RV32I-NEXT: j .LBB0_5 -; RV32I-NEXT: .LBB0_5: # %test6 +; RV32I-NEXT: # %bb.5: # %test6 ; RV32I-NEXT: lw a3, 0(a1) ; RV32I-NEXT: bgeu a3, a0, .LBB0_12 -; RV32I-NEXT: j .LBB0_6 -; RV32I-NEXT: .LBB0_6: # %test7 +; RV32I-NEXT: # %bb.6: # %test7 ; RV32I-NEXT: lw a3, 0(a1) ; RV32I-NEXT: blt a0, a3, .LBB0_12 -; RV32I-NEXT: j .LBB0_7 -; RV32I-NEXT: .LBB0_7: # %test8 +; RV32I-NEXT: # %bb.7: # %test8 ; RV32I-NEXT: lw a3, 0(a1) ; RV32I-NEXT: bge a0, a3, .LBB0_12 -; RV32I-NEXT: j .LBB0_8 -; RV32I-NEXT: .LBB0_8: # %test9 +; RV32I-NEXT: # %bb.8: # %test9 ; RV32I-NEXT: lw a3, 0(a1) ; RV32I-NEXT: bltu a0, a3, .LBB0_12 -; RV32I-NEXT: j .LBB0_9 -; RV32I-NEXT: .LBB0_9: # %test10 +; RV32I-NEXT: # %bb.9: # %test10 ; RV32I-NEXT: lw a3, 0(a1) ; RV32I-NEXT: bgeu a0, a3, .LBB0_12 -; RV32I-NEXT: j .LBB0_10 -; RV32I-NEXT: .LBB0_10: # %test11 +; RV32I-NEXT: # %bb.10: # %test11 ; RV32I-NEXT: lw a0, 0(a1) ; RV32I-NEXT: andi a0, a2, 1 ; RV32I-NEXT: bnez a0, .LBB0_12 -; RV32I-NEXT: j .LBB0_11 -; RV32I-NEXT: .LBB0_11: # %test12 +; RV32I-NEXT: # %bb.11: # %test12 ; RV32I-NEXT: lw a0, 0(a1) ; RV32I-NEXT: .LBB0_12: # %end ; RV32I-NEXT: lw s0, 8(sp) Index: test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll =================================================================== --- test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll +++ test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll @@ -107,15 +107,12 @@ ; RV32I-NEXT: sw ra, 12(sp) ; RV32I-NEXT: sw s0, 8(sp) ; RV32I-NEXT: addi s0, sp, 16 -; RV32I-NEXT: mv a1, a0 -; RV32I-NEXT: addi a0, zero, 8 -; RV32I-NEXT: andi a2, a1, 255 -; RV32I-NEXT: beqz a2, .LBB3_2 -; RV32I-NEXT: j .LBB3_1 -; RV32I-NEXT: .LBB3_1: # %cond.false -; RV32I-NEXT: addi a0, a1, -1 -; RV32I-NEXT: not a1, a1 -; RV32I-NEXT: and a0, a1, a0 +; RV32I-NEXT: andi a1, a0, 255 +; RV32I-NEXT: beqz a1, .LBB3_1 +; RV32I-NEXT: # %bb.2: # %cond.false +; RV32I-NEXT: addi a1, a0, -1 +; RV32I-NEXT: not a0, a0 +; RV32I-NEXT: and a0, a0, a1 ; RV32I-NEXT: lui a1, 349525 ; RV32I-NEXT: addi a1, a1, 1365 ; RV32I-NEXT: srli a2, a0, 1 @@ -138,7 +135,10 @@ ; RV32I-NEXT: addi a2, a2, %lo(__mulsi3) ; RV32I-NEXT: jalr a2 ; RV32I-NEXT: srli a0, a0, 24 -; RV32I-NEXT: .LBB3_2: # %cond.end +; RV32I-NEXT: j .LBB3_3 +; RV32I-NEXT: .LBB3_1: +; RV32I-NEXT: addi a0, zero, 8 +; RV32I-NEXT: .LBB3_3: # %cond.end ; RV32I-NEXT: lw s0, 8(sp) ; RV32I-NEXT: lw ra, 12(sp) ; RV32I-NEXT: addi sp, sp, 16 @@ -154,17 +154,14 @@ ; RV32I-NEXT: sw ra, 12(sp) ; RV32I-NEXT: sw s0, 8(sp) ; RV32I-NEXT: addi s0, sp, 16 -; RV32I-NEXT: mv a1, a0 -; RV32I-NEXT: addi a0, zero, 16 -; RV32I-NEXT: lui a2, 16 -; RV32I-NEXT: addi a2, a2, -1 -; RV32I-NEXT: and a2, a1, a2 -; RV32I-NEXT: beqz a2, .LBB4_2 -; RV32I-NEXT: j .LBB4_1 -; RV32I-NEXT: .LBB4_1: # %cond.false -; RV32I-NEXT: addi a0, a1, -1 -; RV32I-NEXT: not a1, a1 -; RV32I-NEXT: and a0, a1, a0 +; RV32I-NEXT: lui a1, 16 +; RV32I-NEXT: addi a1, a1, -1 +; RV32I-NEXT: and a1, a0, a1 +; RV32I-NEXT: beqz a1, .LBB4_1 +; RV32I-NEXT: # %bb.2: # %cond.false +; RV32I-NEXT: addi a1, a0, -1 +; RV32I-NEXT: not a0, a0 +; RV32I-NEXT: and a0, a0, a1 ; RV32I-NEXT: lui a1, 349525 ; RV32I-NEXT: addi a1, a1, 1365 ; RV32I-NEXT: srli a2, a0, 1 @@ -187,7 +184,10 @@ ; RV32I-NEXT: addi a2, a2, %lo(__mulsi3) ; RV32I-NEXT: jalr a2 ; RV32I-NEXT: srli a0, a0, 24 -; RV32I-NEXT: .LBB4_2: # %cond.end +; RV32I-NEXT: j .LBB4_3 +; RV32I-NEXT: .LBB4_1: +; RV32I-NEXT: addi a0, zero, 16 +; RV32I-NEXT: .LBB4_3: # %cond.end ; RV32I-NEXT: lw s0, 8(sp) ; RV32I-NEXT: lw ra, 12(sp) ; RV32I-NEXT: addi sp, sp, 16 @@ -203,14 +203,11 @@ ; RV32I-NEXT: sw ra, 12(sp) ; RV32I-NEXT: sw s0, 8(sp) ; RV32I-NEXT: addi s0, sp, 16 -; RV32I-NEXT: mv a1, a0 -; RV32I-NEXT: addi a0, zero, 32 -; RV32I-NEXT: beqz a1, .LBB5_2 -; RV32I-NEXT: j .LBB5_1 -; RV32I-NEXT: .LBB5_1: # %cond.false -; RV32I-NEXT: addi a0, a1, -1 -; RV32I-NEXT: not a1, a1 -; RV32I-NEXT: and a0, a1, a0 +; RV32I-NEXT: beqz a0, .LBB5_1 +; RV32I-NEXT: # %bb.2: # %cond.false +; RV32I-NEXT: addi a1, a0, -1 +; RV32I-NEXT: not a0, a0 +; RV32I-NEXT: and a0, a0, a1 ; RV32I-NEXT: lui a1, 349525 ; RV32I-NEXT: addi a1, a1, 1365 ; RV32I-NEXT: srli a2, a0, 1 @@ -233,7 +230,10 @@ ; RV32I-NEXT: addi a2, a2, %lo(__mulsi3) ; RV32I-NEXT: jalr a2 ; RV32I-NEXT: srli a0, a0, 24 -; RV32I-NEXT: .LBB5_2: # %cond.end +; RV32I-NEXT: j .LBB5_3 +; RV32I-NEXT: .LBB5_1: +; RV32I-NEXT: addi a0, zero, 32 +; RV32I-NEXT: .LBB5_3: # %cond.end ; RV32I-NEXT: lw s0, 8(sp) ; RV32I-NEXT: lw ra, 12(sp) ; RV32I-NEXT: addi sp, sp, 16 @@ -249,13 +249,10 @@ ; RV32I-NEXT: sw ra, 12(sp) ; RV32I-NEXT: sw s0, 8(sp) ; RV32I-NEXT: addi s0, sp, 16 -; RV32I-NEXT: mv a1, a0 -; RV32I-NEXT: addi a0, zero, 32 -; RV32I-NEXT: beqz a1, .LBB6_2 -; RV32I-NEXT: j .LBB6_1 -; RV32I-NEXT: .LBB6_1: # %cond.false -; RV32I-NEXT: srli a0, a1, 1 -; RV32I-NEXT: or a0, a1, a0 +; RV32I-NEXT: beqz a0, .LBB6_1 +; RV32I-NEXT: # %bb.2: # %cond.false +; RV32I-NEXT: srli a1, a0, 1 +; RV32I-NEXT: or a0, a0, a1 ; RV32I-NEXT: srli a1, a0, 2 ; RV32I-NEXT: or a0, a0, a1 ; RV32I-NEXT: srli a1, a0, 4 @@ -287,7 +284,10 @@ ; RV32I-NEXT: addi a2, a2, %lo(__mulsi3) ; RV32I-NEXT: jalr a2 ; RV32I-NEXT: srli a0, a0, 24 -; RV32I-NEXT: .LBB6_2: # %cond.end +; RV32I-NEXT: j .LBB6_3 +; RV32I-NEXT: .LBB6_1: +; RV32I-NEXT: addi a0, zero, 32 +; RV32I-NEXT: .LBB6_3: # %cond.end ; RV32I-NEXT: lw s0, 8(sp) ; RV32I-NEXT: lw ra, 12(sp) ; RV32I-NEXT: addi sp, sp, 16 @@ -309,58 +309,61 @@ ; RV32I-NEXT: sw s5, 20(sp) ; RV32I-NEXT: sw s6, 16(sp) ; RV32I-NEXT: sw s7, 12(sp) +; RV32I-NEXT: sw s8, 8(sp) ; RV32I-NEXT: addi s0, sp, 48 -; RV32I-NEXT: mv s1, a1 -; RV32I-NEXT: mv s2, a0 -; RV32I-NEXT: addi a0, s2, -1 -; RV32I-NEXT: not a1, s2 +; RV32I-NEXT: mv s2, a1 +; RV32I-NEXT: mv s3, a0 +; RV32I-NEXT: addi a0, s3, -1 +; RV32I-NEXT: not a1, s3 ; RV32I-NEXT: and a0, a1, a0 ; RV32I-NEXT: lui a1, 349525 -; RV32I-NEXT: addi s4, a1, 1365 +; RV32I-NEXT: addi s5, a1, 1365 ; RV32I-NEXT: srli a1, a0, 1 -; RV32I-NEXT: and a1, a1, s4 +; RV32I-NEXT: and a1, a1, s5 ; RV32I-NEXT: sub a0, a0, a1 ; RV32I-NEXT: lui a1, 209715 -; RV32I-NEXT: addi s5, a1, 819 -; RV32I-NEXT: and a1, a0, s5 +; RV32I-NEXT: addi s6, a1, 819 +; RV32I-NEXT: and a1, a0, s6 ; RV32I-NEXT: srli a0, a0, 2 -; RV32I-NEXT: and a0, a0, s5 +; RV32I-NEXT: and a0, a0, s6 ; RV32I-NEXT: add a0, a1, a0 ; RV32I-NEXT: srli a1, a0, 4 ; RV32I-NEXT: add a0, a0, a1 ; RV32I-NEXT: lui a1, 4112 -; RV32I-NEXT: addi s3, a1, 257 +; RV32I-NEXT: addi s4, a1, 257 ; RV32I-NEXT: lui a1, %hi(__mulsi3) -; RV32I-NEXT: addi s6, a1, %lo(__mulsi3) +; RV32I-NEXT: addi s7, a1, %lo(__mulsi3) ; RV32I-NEXT: lui a1, 61681 -; RV32I-NEXT: addi s7, a1, -241 -; RV32I-NEXT: and a0, a0, s7 -; RV32I-NEXT: mv a1, s3 -; RV32I-NEXT: jalr s6 -; RV32I-NEXT: addi a1, s1, -1 -; RV32I-NEXT: not a2, s1 -; RV32I-NEXT: and a1, a2, a1 -; RV32I-NEXT: srli a2, a1, 1 -; RV32I-NEXT: and a2, a2, s4 -; RV32I-NEXT: sub a1, a1, a2 -; RV32I-NEXT: and a2, a1, s5 -; RV32I-NEXT: srli a1, a1, 2 +; RV32I-NEXT: addi s8, a1, -241 +; RV32I-NEXT: and a0, a0, s8 +; RV32I-NEXT: mv a1, s4 +; RV32I-NEXT: jalr s7 +; RV32I-NEXT: mv s1, a0 +; RV32I-NEXT: addi a0, s2, -1 +; RV32I-NEXT: not a1, s2 +; RV32I-NEXT: and a0, a1, a0 +; RV32I-NEXT: srli a1, a0, 1 ; RV32I-NEXT: and a1, a1, s5 -; RV32I-NEXT: add a1, a2, a1 -; RV32I-NEXT: srli a2, a1, 4 -; RV32I-NEXT: add a1, a1, a2 -; RV32I-NEXT: and a1, a1, s7 -; RV32I-NEXT: srli s1, a0, 24 -; RV32I-NEXT: mv a0, a1 -; RV32I-NEXT: mv a1, s3 -; RV32I-NEXT: jalr s6 -; RV32I-NEXT: bnez s2, .LBB7_2 -; RV32I-NEXT: # %bb.1: +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: and a1, a0, s6 +; RV32I-NEXT: srli a0, a0, 2 +; RV32I-NEXT: and a0, a0, s6 +; RV32I-NEXT: add a0, a1, a0 +; RV32I-NEXT: srli a1, a0, 4 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: and a0, a0, s8 +; RV32I-NEXT: mv a1, s4 +; RV32I-NEXT: jalr s7 +; RV32I-NEXT: bnez s3, .LBB7_1 +; RV32I-NEXT: # %bb.2: ; RV32I-NEXT: srli a0, a0, 24 -; RV32I-NEXT: addi s1, a0, 32 -; RV32I-NEXT: .LBB7_2: -; RV32I-NEXT: mv a0, s1 +; RV32I-NEXT: addi a0, a0, 32 +; RV32I-NEXT: j .LBB7_3 +; RV32I-NEXT: .LBB7_1: +; RV32I-NEXT: srli a0, s1, 24 +; RV32I-NEXT: .LBB7_3: ; RV32I-NEXT: mv a1, zero +; RV32I-NEXT: lw s8, 8(sp) ; RV32I-NEXT: lw s7, 12(sp) ; RV32I-NEXT: lw s6, 16(sp) ; RV32I-NEXT: lw s5, 20(sp) @@ -509,58 +512,61 @@ ; RV32I-NEXT: sw s5, 20(sp) ; RV32I-NEXT: sw s6, 16(sp) ; RV32I-NEXT: sw s7, 12(sp) +; RV32I-NEXT: sw s8, 8(sp) ; RV32I-NEXT: addi s0, sp, 48 -; RV32I-NEXT: mv s1, a1 -; RV32I-NEXT: mv s2, a0 -; RV32I-NEXT: addi a0, s2, -1 -; RV32I-NEXT: not a1, s2 +; RV32I-NEXT: mv s2, a1 +; RV32I-NEXT: mv s3, a0 +; RV32I-NEXT: addi a0, s3, -1 +; RV32I-NEXT: not a1, s3 ; RV32I-NEXT: and a0, a1, a0 ; RV32I-NEXT: lui a1, 349525 -; RV32I-NEXT: addi s4, a1, 1365 +; RV32I-NEXT: addi s5, a1, 1365 ; RV32I-NEXT: srli a1, a0, 1 -; RV32I-NEXT: and a1, a1, s4 +; RV32I-NEXT: and a1, a1, s5 ; RV32I-NEXT: sub a0, a0, a1 ; RV32I-NEXT: lui a1, 209715 -; RV32I-NEXT: addi s5, a1, 819 -; RV32I-NEXT: and a1, a0, s5 +; RV32I-NEXT: addi s6, a1, 819 +; RV32I-NEXT: and a1, a0, s6 ; RV32I-NEXT: srli a0, a0, 2 -; RV32I-NEXT: and a0, a0, s5 +; RV32I-NEXT: and a0, a0, s6 ; RV32I-NEXT: add a0, a1, a0 ; RV32I-NEXT: srli a1, a0, 4 ; RV32I-NEXT: add a0, a0, a1 ; RV32I-NEXT: lui a1, 4112 -; RV32I-NEXT: addi s3, a1, 257 +; RV32I-NEXT: addi s4, a1, 257 ; RV32I-NEXT: lui a1, %hi(__mulsi3) -; RV32I-NEXT: addi s6, a1, %lo(__mulsi3) +; RV32I-NEXT: addi s7, a1, %lo(__mulsi3) ; RV32I-NEXT: lui a1, 61681 -; RV32I-NEXT: addi s7, a1, -241 -; RV32I-NEXT: and a0, a0, s7 -; RV32I-NEXT: mv a1, s3 -; RV32I-NEXT: jalr s6 -; RV32I-NEXT: addi a1, s1, -1 -; RV32I-NEXT: not a2, s1 -; RV32I-NEXT: and a1, a2, a1 -; RV32I-NEXT: srli a2, a1, 1 -; RV32I-NEXT: and a2, a2, s4 -; RV32I-NEXT: sub a1, a1, a2 -; RV32I-NEXT: and a2, a1, s5 -; RV32I-NEXT: srli a1, a1, 2 +; RV32I-NEXT: addi s8, a1, -241 +; RV32I-NEXT: and a0, a0, s8 +; RV32I-NEXT: mv a1, s4 +; RV32I-NEXT: jalr s7 +; RV32I-NEXT: mv s1, a0 +; RV32I-NEXT: addi a0, s2, -1 +; RV32I-NEXT: not a1, s2 +; RV32I-NEXT: and a0, a1, a0 +; RV32I-NEXT: srli a1, a0, 1 ; RV32I-NEXT: and a1, a1, s5 -; RV32I-NEXT: add a1, a2, a1 -; RV32I-NEXT: srli a2, a1, 4 -; RV32I-NEXT: add a1, a1, a2 -; RV32I-NEXT: and a1, a1, s7 -; RV32I-NEXT: srli s1, a0, 24 -; RV32I-NEXT: mv a0, a1 -; RV32I-NEXT: mv a1, s3 -; RV32I-NEXT: jalr s6 -; RV32I-NEXT: bnez s2, .LBB11_2 -; RV32I-NEXT: # %bb.1: +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: and a1, a0, s6 +; RV32I-NEXT: srli a0, a0, 2 +; RV32I-NEXT: and a0, a0, s6 +; RV32I-NEXT: add a0, a1, a0 +; RV32I-NEXT: srli a1, a0, 4 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: and a0, a0, s8 +; RV32I-NEXT: mv a1, s4 +; RV32I-NEXT: jalr s7 +; RV32I-NEXT: bnez s3, .LBB11_1 +; RV32I-NEXT: # %bb.2: ; RV32I-NEXT: srli a0, a0, 24 -; RV32I-NEXT: addi s1, a0, 32 -; RV32I-NEXT: .LBB11_2: -; RV32I-NEXT: mv a0, s1 +; RV32I-NEXT: addi a0, a0, 32 +; RV32I-NEXT: j .LBB11_3 +; RV32I-NEXT: .LBB11_1: +; RV32I-NEXT: srli a0, s1, 24 +; RV32I-NEXT: .LBB11_3: ; RV32I-NEXT: mv a1, zero +; RV32I-NEXT: lw s8, 8(sp) ; RV32I-NEXT: lw s7, 12(sp) ; RV32I-NEXT: lw s6, 16(sp) ; RV32I-NEXT: lw s5, 20(sp) Index: test/CodeGen/RISCV/jumptable.ll =================================================================== --- test/CodeGen/RISCV/jumptable.ll +++ test/CodeGen/RISCV/jumptable.ll @@ -10,42 +10,37 @@ ; RV32I-NEXT: sw s0, 8(sp) ; RV32I-NEXT: addi s0, sp, 16 ; RV32I-NEXT: addi a2, zero, 2 -; RV32I-NEXT: blt a2, a0, .LBB0_3 -; RV32I-NEXT: j .LBB0_1 -; RV32I-NEXT: .LBB0_1: # %entry +; RV32I-NEXT: blt a2, a0, .LBB0_4 +; RV32I-NEXT: # %bb.1: # %entry ; RV32I-NEXT: addi a3, zero, 1 -; RV32I-NEXT: beq a0, a3, .LBB0_5 -; RV32I-NEXT: j .LBB0_2 -; RV32I-NEXT: .LBB0_2: # %entry -; RV32I-NEXT: beq a0, a2, .LBB0_6 -; RV32I-NEXT: j .LBB0_9 -; RV32I-NEXT: .LBB0_6: # %bb2 +; RV32I-NEXT: beq a0, a3, .LBB0_8 +; RV32I-NEXT: # %bb.2: # %entry +; RV32I-NEXT: bne a0, a2, .LBB0_10 +; RV32I-NEXT: # %bb.3: # %bb2 ; RV32I-NEXT: addi a0, zero, 3 ; RV32I-NEXT: sw a0, 0(a1) -; RV32I-NEXT: j .LBB0_9 -; RV32I-NEXT: .LBB0_3: # %entry -; RV32I-NEXT: addi a3, zero, 3 -; RV32I-NEXT: beq a0, a3, .LBB0_7 -; RV32I-NEXT: j .LBB0_4 +; RV32I-NEXT: j .LBB0_10 ; RV32I-NEXT: .LBB0_4: # %entry +; RV32I-NEXT: addi a3, zero, 3 +; RV32I-NEXT: beq a0, a3, .LBB0_9 +; RV32I-NEXT: # %bb.5: # %entry ; RV32I-NEXT: addi a2, zero, 4 -; RV32I-NEXT: beq a0, a2, .LBB0_8 -; RV32I-NEXT: j .LBB0_9 -; RV32I-NEXT: .LBB0_8: # %bb4 +; RV32I-NEXT: bne a0, a2, .LBB0_10 +; RV32I-NEXT: # %bb.6: # %bb4 ; RV32I-NEXT: addi a0, zero, 1 ; RV32I-NEXT: sw a0, 0(a1) -; RV32I-NEXT: .LBB0_9: # %exit +; RV32I-NEXT: j .LBB0_10 +; RV32I-NEXT: .LBB0_8: # %bb1 +; RV32I-NEXT: addi a0, zero, 4 +; RV32I-NEXT: sw a0, 0(a1) +; RV32I-NEXT: j .LBB0_10 +; RV32I-NEXT: .LBB0_9: # %bb3 +; RV32I-NEXT: sw a2, 0(a1) +; RV32I-NEXT: .LBB0_10: # %exit ; RV32I-NEXT: lw s0, 8(sp) ; RV32I-NEXT: lw ra, 12(sp) ; RV32I-NEXT: addi sp, sp, 16 ; RV32I-NEXT: ret -; RV32I-NEXT: .LBB0_5: # %bb1 -; RV32I-NEXT: addi a0, zero, 4 -; RV32I-NEXT: sw a0, 0(a1) -; RV32I-NEXT: j .LBB0_9 -; RV32I-NEXT: .LBB0_7: # %bb3 -; RV32I-NEXT: sw a2, 0(a1) -; RV32I-NEXT: j .LBB0_9 entry: switch i32 %in, label %exit [ i32 1, label %bb1 Index: test/CodeGen/RISCV/select-cc.ll =================================================================== --- test/CodeGen/RISCV/select-cc.ll +++ test/CodeGen/RISCV/select-cc.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: llc -mtriple=riscv32 -disable-block-placement -verify-machineinstrs < %s \ ; RUN: | FileCheck -check-prefix=RV32I %s define i32 @foo(i32 %a, i32 *%b) {