mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-20 03:23:01 +02:00
[RISCV] Implement branch analysis
This is a prerequisite for the branch relaxation pass, and allows a number of optimisation passes (e.g. BranchFolding and MachineBlockPlacement) to work. Differential Revision: https://reviews.llvm.org/D40808 llvm-svn: 322222
This commit is contained in:
parent
272abbd2f8
commit
1534210353
@ -95,3 +95,169 @@ void RISCVInstrInfo::movImm32(MachineBasicBlock &MBB,
|
||||
.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<MachineOperand> &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<MachineOperand> &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<MachineOperand> 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<MachineOperand> &Cond) const {
|
||||
assert((Cond.size() == 3) && "Invalid branch condition!");
|
||||
Cond[0].setImm(getOppositeBranchOpcode(Cond[0].getImm()));
|
||||
return false;
|
||||
}
|
||||
|
@ -46,6 +46,22 @@ public:
|
||||
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<MachineOperand> &Cond,
|
||||
bool AllowModify) const override;
|
||||
|
||||
unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
|
||||
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
|
||||
const DebugLoc &dl,
|
||||
int *BytesAdded = nullptr) const override;
|
||||
|
||||
unsigned removeBranch(MachineBasicBlock &MBB,
|
||||
int *BytesRemoved = nullptr) const override;
|
||||
|
||||
bool
|
||||
reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
91
test/CodeGen/RISCV/analyze-branch.ll
Normal file
91
test/CodeGen/RISCV/analyze-branch.ll
Normal file
@ -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?
|
@ -11,49 +11,38 @@ define void @foo(i32 %a, i32 *%b, i1 %c) {
|
||||
; 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)
|
||||
|
@ -107,15 +107,12 @@ define i8 @test_cttz_i8(i8 %a) nounwind {
|
||||
; 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 @@ define i8 @test_cttz_i8(i8 %a) nounwind {
|
||||
; 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 @@ define i16 @test_cttz_i16(i16 %a) nounwind {
|
||||
; 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 @@ define i16 @test_cttz_i16(i16 %a) nounwind {
|
||||
; 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 @@ define i32 @test_cttz_i32(i32 %a) nounwind {
|
||||
; 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 @@ define i32 @test_cttz_i32(i32 %a) nounwind {
|
||||
; 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 @@ define i32 @test_ctlz_i32(i32 %a) nounwind {
|
||||
; 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 @@ define i32 @test_ctlz_i32(i32 %a) nounwind {
|
||||
; 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 @@ define i64 @test_cttz_i64(i64 %a) nounwind {
|
||||
; 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 @@ define i64 @test_cttz_i64_zero_undef(i64 %a) nounwind {
|
||||
; 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)
|
||||
|
@ -10,42 +10,37 @@ define void @jt(i32 %in, i32* %out) {
|
||||
; 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
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user