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,197 @@ .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 { + // Implementation derived from AArch64InstrInfo::analyzeBranch. + 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()) + return false; + + // From here on, iterator I always holds a non-NULL MachineInstr*. This is + // maintained by only decrementing I when I != MBB.begin(). + + if (!isUnpredicatedTerminator(*I)) + return false; + + // Get the last instruction in the block. + MachineInstr *LastInst = &*I; + + // If there is only one terminator instruction, process it. + const MCInstrDesc *LastMCID = &LastInst->getDesc(); + if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) { + if (LastMCID->isUnconditionalBranch()) { + TBB = LastInst->getOperand(0).getMBB(); + return false; + } + if (LastMCID->isConditionalBranch()) { + // Block ends with fall-through condbranch. + parseCondBranch(LastInst, TBB, Cond); + return false; + } + return true; // Can't handle indirect branch. + } + + // Get the instruction before it if it is a terminator. + MachineInstr *SecondLastInst = &*I; + const MCInstrDesc *SecondLastMCID = &SecondLastInst->getDesc(); + + // If AllowModify is true and the block ends with two or more unconditional + // branches, delete all but the first unconditional branch. + if (AllowModify && LastMCID->isUnconditionalBranch()) { + while (SecondLastMCID->isUnconditionalBranch()) { + LastInst->eraseFromParent(); + LastInst = SecondLastInst; + LastMCID = &LastInst->getDesc(); + if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) { + // Return now the only terminator is an unconditional branch. + TBB = LastInst->getOperand(0).getMBB(); + return false; + } else { + SecondLastInst = &*I; + SecondLastMCID = &SecondLastInst->getDesc(); + } + } + } + + // If there are three terminators, we don't know what sort of block this is. + if (I != MBB.begin() && isUnpredicatedTerminator(*--I)) + return true; + + // If the block ends with a bcc and a br, handle it. + if (SecondLastMCID->isConditionalBranch() && + LastMCID->isUnconditionalBranch()) { + parseCondBranch(SecondLastInst, TBB, Cond); + FBB = LastInst->getOperand(0).getMBB(); + return false; + } + + // If the block ends with two unconditional branches, handle it. The second + // one is not executed, so remove it. + if (SecondLastMCID->isUnconditionalBranch() && + LastMCID->isUnconditionalBranch()) { + TBB = SecondLastInst->getOperand(0).getMBB(); + I = LastInst; + if (AllowModify) + I->eraseFromParent(); + return false; + } + + // ...likewise if it ends with an indirect branch followed by an unconditional + // branch. + if (SecondLastMCID->isIndirectBranch() && LastMCID->isUnconditionalBranch()) { + I = LastInst; + if (AllowModify) + I->eraseFromParent(); + return true; + } + + // Otherwise, 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 ra, a0, 0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: jalr zero, ra, 0 +; RV32I-NEXT: .LBB0_3: # %false +; RV32I-NEXT: lui a0, %hi(test_false) +; RV32I-NEXT: addi a0, a0, %lo(test_false) +; RV32I-NEXT: jal zero, .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 ra, a0, 0 +; RV32I-NEXT: lw s0, 8(sp) +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: jalr zero, ra, 0 +; RV32I-NEXT: .LBB1_1: # %true +; RV32I-NEXT: lui a0, %hi(test_true) +; RV32I-NEXT: addi a0, a0, %lo(test_true) +; RV32I-NEXT: jal zero, .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: jal zero, .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: jal zero, .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: jal zero, .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: jal zero, .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: jal zero, .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: jal zero, .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: jal zero, .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: jal zero, .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: jal zero, .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: jal zero, .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: bne a0, zero, .LBB0_12 -; RV32I-NEXT: jal zero, .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: addi a1, a0, 0 -; RV32I-NEXT: addi a0, zero, 8 -; RV32I-NEXT: andi a2, a1, 255 -; RV32I-NEXT: beq a2, zero, .LBB3_2 -; RV32I-NEXT: jal zero, .LBB3_1 -; RV32I-NEXT: .LBB3_1: # %cond.false -; RV32I-NEXT: addi a0, a1, -1 -; RV32I-NEXT: xori a1, a1, -1 -; RV32I-NEXT: and a0, a1, a0 +; RV32I-NEXT: andi a1, a0, 255 +; RV32I-NEXT: beq a1, zero, .LBB3_1 +; RV32I-NEXT: # %bb.2: # %cond.false +; RV32I-NEXT: addi a1, a0, -1 +; RV32I-NEXT: xori a0, a0, -1 +; 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 ra, a2, 0 ; RV32I-NEXT: srli a0, a0, 24 -; RV32I-NEXT: .LBB3_2: # %cond.end +; RV32I-NEXT: jal zero, .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: addi a1, a0, 0 -; 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: beq a2, zero, .LBB4_2 -; RV32I-NEXT: jal zero, .LBB4_1 -; RV32I-NEXT: .LBB4_1: # %cond.false -; RV32I-NEXT: addi a0, a1, -1 -; RV32I-NEXT: xori a1, a1, -1 -; 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: beq a1, zero, .LBB4_1 +; RV32I-NEXT: # %bb.2: # %cond.false +; RV32I-NEXT: addi a1, a0, -1 +; RV32I-NEXT: xori a0, a0, -1 +; 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 ra, a2, 0 ; RV32I-NEXT: srli a0, a0, 24 -; RV32I-NEXT: .LBB4_2: # %cond.end +; RV32I-NEXT: jal zero, .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: addi a1, a0, 0 -; RV32I-NEXT: addi a0, zero, 32 -; RV32I-NEXT: beq a1, zero, .LBB5_2 -; RV32I-NEXT: jal zero, .LBB5_1 -; RV32I-NEXT: .LBB5_1: # %cond.false -; RV32I-NEXT: addi a0, a1, -1 -; RV32I-NEXT: xori a1, a1, -1 -; RV32I-NEXT: and a0, a1, a0 +; RV32I-NEXT: beq a0, zero, .LBB5_1 +; RV32I-NEXT: # %bb.2: # %cond.false +; RV32I-NEXT: addi a1, a0, -1 +; RV32I-NEXT: xori a0, a0, -1 +; 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 ra, a2, 0 ; RV32I-NEXT: srli a0, a0, 24 -; RV32I-NEXT: .LBB5_2: # %cond.end +; RV32I-NEXT: jal zero, .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: addi a1, a0, 0 -; RV32I-NEXT: addi a0, zero, 32 -; RV32I-NEXT: beq a1, zero, .LBB6_2 -; RV32I-NEXT: jal zero, .LBB6_1 -; RV32I-NEXT: .LBB6_1: # %cond.false -; RV32I-NEXT: srli a0, a1, 1 -; RV32I-NEXT: or a0, a1, a0 +; RV32I-NEXT: beq a0, zero, .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 ra, a2, 0 ; RV32I-NEXT: srli a0, a0, 24 -; RV32I-NEXT: .LBB6_2: # %cond.end +; RV32I-NEXT: jal zero, .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: addi s1, a1, 0 -; RV32I-NEXT: addi s2, a0, 0 -; RV32I-NEXT: addi a0, s2, -1 -; RV32I-NEXT: xori a1, s2, -1 +; RV32I-NEXT: addi s2, a1, 0 +; RV32I-NEXT: addi s3, a0, 0 +; RV32I-NEXT: addi a0, s3, -1 +; RV32I-NEXT: xori a1, s3, -1 ; 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: addi a1, s3, 0 -; RV32I-NEXT: jalr ra, s6, 0 -; RV32I-NEXT: addi a1, s1, -1 -; RV32I-NEXT: xori a2, s1, -1 -; 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: addi a1, s4, 0 +; RV32I-NEXT: jalr ra, s7, 0 +; RV32I-NEXT: addi s1, a0, 0 +; RV32I-NEXT: addi a0, s2, -1 +; RV32I-NEXT: xori a1, s2, -1 +; 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: addi a0, a1, 0 -; RV32I-NEXT: addi a1, s3, 0 -; RV32I-NEXT: jalr ra, s6, 0 -; RV32I-NEXT: bne s2, zero, .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: addi a1, s4, 0 +; RV32I-NEXT: jalr ra, s7, 0 +; RV32I-NEXT: bne s3, zero, .LBB7_1 +; RV32I-NEXT: # %bb.2: ; RV32I-NEXT: srli a0, a0, 24 -; RV32I-NEXT: addi s1, a0, 32 -; RV32I-NEXT: .LBB7_2: -; RV32I-NEXT: addi a0, s1, 0 +; RV32I-NEXT: addi a0, a0, 32 +; RV32I-NEXT: jal zero, .LBB7_3 +; RV32I-NEXT: .LBB7_1: +; RV32I-NEXT: srli a0, s1, 24 +; RV32I-NEXT: .LBB7_3: ; RV32I-NEXT: addi a1, zero, 0 +; 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: addi s1, a1, 0 -; RV32I-NEXT: addi s2, a0, 0 -; RV32I-NEXT: addi a0, s2, -1 -; RV32I-NEXT: xori a1, s2, -1 +; RV32I-NEXT: addi s2, a1, 0 +; RV32I-NEXT: addi s3, a0, 0 +; RV32I-NEXT: addi a0, s3, -1 +; RV32I-NEXT: xori a1, s3, -1 ; 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: addi a1, s3, 0 -; RV32I-NEXT: jalr ra, s6, 0 -; RV32I-NEXT: addi a1, s1, -1 -; RV32I-NEXT: xori a2, s1, -1 -; 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: addi a1, s4, 0 +; RV32I-NEXT: jalr ra, s7, 0 +; RV32I-NEXT: addi s1, a0, 0 +; RV32I-NEXT: addi a0, s2, -1 +; RV32I-NEXT: xori a1, s2, -1 +; 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: addi a0, a1, 0 -; RV32I-NEXT: addi a1, s3, 0 -; RV32I-NEXT: jalr ra, s6, 0 -; RV32I-NEXT: bne s2, zero, .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: addi a1, s4, 0 +; RV32I-NEXT: jalr ra, s7, 0 +; RV32I-NEXT: bne s3, zero, .LBB11_1 +; RV32I-NEXT: # %bb.2: ; RV32I-NEXT: srli a0, a0, 24 -; RV32I-NEXT: addi s1, a0, 32 -; RV32I-NEXT: .LBB11_2: -; RV32I-NEXT: addi a0, s1, 0 +; RV32I-NEXT: addi a0, a0, 32 +; RV32I-NEXT: jal zero, .LBB11_3 +; RV32I-NEXT: .LBB11_1: +; RV32I-NEXT: srli a0, s1, 24 +; RV32I-NEXT: .LBB11_3: ; RV32I-NEXT: addi a1, zero, 0 +; 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: jal zero, .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: jal zero, .LBB0_2 -; RV32I-NEXT: .LBB0_2: # %entry -; RV32I-NEXT: beq a0, a2, .LBB0_6 -; RV32I-NEXT: jal zero, .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: jal zero, .LBB0_9 -; RV32I-NEXT: .LBB0_3: # %entry -; RV32I-NEXT: addi a3, zero, 3 -; RV32I-NEXT: beq a0, a3, .LBB0_7 -; RV32I-NEXT: jal zero, .LBB0_4 +; RV32I-NEXT: jal zero, .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: jal zero, .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: jal zero, .LBB0_10 +; RV32I-NEXT: .LBB0_8: # %bb1 +; RV32I-NEXT: addi a0, zero, 4 +; RV32I-NEXT: sw a0, 0(a1) +; RV32I-NEXT: jal zero, .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: jalr zero, ra, 0 -; RV32I-NEXT: .LBB0_5: # %bb1 -; RV32I-NEXT: addi a0, zero, 4 -; RV32I-NEXT: sw a0, 0(a1) -; RV32I-NEXT: jal zero, .LBB0_9 -; RV32I-NEXT: .LBB0_7: # %bb3 -; RV32I-NEXT: sw a2, 0(a1) -; RV32I-NEXT: jal zero, .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) {