Skip to content

Commit

Permalink
[LoongArch] Add support for the BranchRelaxation pass
Browse files Browse the repository at this point in the history
When the branch target is out of the range represented by the current
branch instruction's immediate, branch relaxation is required. There
are three types of immediate for branch instructions on LoongArch,
including simm16, simm21 and simm26. And the real branch target
address is PC + sext(simmXX << 2). In addition, the indirect branch
way is implemented to support larger branch target.

BranchRelaxation pass calls `RenumberBlocks` to renumber all of the
machine basic blocks in the function. So the machine basic blocks
number changed in some test cases.

Differential Revision: https://reviews.llvm.org/D137233
  • Loading branch information
XiaodongLoong committed Nov 8, 2022
1 parent 5426a1e commit 57ad3f1
Show file tree
Hide file tree
Showing 9 changed files with 252 additions and 37 deletions.
72 changes: 72 additions & 0 deletions llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
Expand Up @@ -14,6 +14,7 @@
#include "LoongArch.h"
#include "LoongArchMachineFunctionInfo.h"
#include "MCTargetDesc/LoongArchMatInt.h"
#include "llvm/CodeGen/RegisterScavenging.h"

using namespace llvm;

Expand Down Expand Up @@ -154,6 +155,11 @@ void LoongArchInstrInfo::movImm(MachineBasicBlock &MBB,
}

unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
if (MI.getOpcode() == TargetOpcode::INLINEASM) {
const MachineFunction *MF = MI.getParent()->getParent();
const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();
return getInlineAsmLength(MI.getOperand(0).getSymbolName(), *MAI);
}
return MI.getDesc().getSize();
}

Expand Down Expand Up @@ -237,6 +243,29 @@ bool LoongArchInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
return true;
}

bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
int64_t BrOffset) const {
switch (BranchOp) {
default:
llvm_unreachable("Unknown branch instruction!");
case LoongArch::BEQ:
case LoongArch::BNE:
case LoongArch::BLT:
case LoongArch::BGE:
case LoongArch::BLTU:
case LoongArch::BGEU:
return isInt<18>(BrOffset);
case LoongArch::BEQZ:
case LoongArch::BNEZ:
case LoongArch::BCEQZ:
case LoongArch::BCNEZ:
return isInt<23>(BrOffset);
case LoongArch::B:
case LoongArch::PseudoBR:
return isInt<28>(BrOffset);
}
}

unsigned LoongArchInstrInfo::removeBranch(MachineBasicBlock &MBB,
int *BytesRemoved) const {
if (BytesRemoved)
Expand Down Expand Up @@ -308,6 +337,49 @@ unsigned LoongArchInstrInfo::insertBranch(
return 2;
}

void LoongArchInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB,
MachineBasicBlock &DestBB,
MachineBasicBlock &RestoreBB,
const DebugLoc &DL,
int64_t BrOffset,
RegScavenger *RS) const {
assert(RS && "RegScavenger required for long branching");
assert(MBB.empty() &&
"new block should be inserted for expanding unconditional branch");
assert(MBB.pred_size() == 1);

MachineFunction *MF = MBB.getParent();
MachineRegisterInfo &MRI = MF->getRegInfo();

if (!isInt<32>(BrOffset))
report_fatal_error(
"Branch offsets outside of the signed 32-bit range not supported");

Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
auto II = MBB.end();

MachineInstr &MI =
*BuildMI(MBB, II, DL, get(LoongArch::PCALAU12I), ScratchReg)
.addMBB(&DestBB, LoongArchII::MO_PCREL_HI);
BuildMI(MBB, II, DL,
get(STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W),
ScratchReg)
.addReg(ScratchReg)
.addMBB(&DestBB, LoongArchII::MO_PCREL_LO);
BuildMI(MBB, II, DL, get(LoongArch::PseudoBRIND))
.addReg(ScratchReg, RegState::Kill)
.addImm(0);

RS->enterBasicBlockEnd(MBB);
Register Scav = RS->scavengeRegisterBackwards(LoongArch::GPRRegClass,
MI.getIterator(), false, 0);
// TODO: When there is no scavenged register, it needs to specify a register.
assert(Scav != LoongArch::NoRegister && "No register is scavenged!");
MRI.replaceRegWith(ScratchReg, Scav);
MRI.clearVirtRegs();
RS->setRegUsed(Scav);
}

static unsigned getOppositeBranchOpc(unsigned Opc) {
switch (Opc) {
default:
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/Target/LoongArch/LoongArchInstrInfo.h
Expand Up @@ -55,6 +55,9 @@ class LoongArchInstrInfo : public LoongArchGenInstrInfo {
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify) const override;

bool isBranchOffsetInRange(unsigned BranchOpc,
int64_t BrOffset) const override;

unsigned removeBranch(MachineBasicBlock &MBB,
int *BytesRemoved = nullptr) const override;

Expand All @@ -63,6 +66,11 @@ class LoongArchInstrInfo : public LoongArchGenInstrInfo {
const DebugLoc &dl,
int *BytesAdded = nullptr) const override;

void insertIndirectBranch(MachineBasicBlock &MBB,
MachineBasicBlock &NewDestBB,
MachineBasicBlock &RestoreBB, const DebugLoc &DL,
int64_t BrOffset, RegScavenger *RS) const override;

bool
reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;

Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp
Expand Up @@ -104,6 +104,7 @@ class LoongArchPassConfig : public TargetPassConfig {

void addIRPasses() override;
bool addInstSelector() override;
void addPreEmitPass() override;
void addPreEmitPass2() override;
void addPreRegAlloc() override;
};
Expand All @@ -126,6 +127,8 @@ bool LoongArchPassConfig::addInstSelector() {
return false;
}

void LoongArchPassConfig::addPreEmitPass() { addPass(&BranchRelaxationPassID); }

void LoongArchPassConfig::addPreEmitPass2() {
// Schedule the expansion of AtomicPseudos at the last possible moment,
// avoiding the possibility for other passes to break the requirements for
Expand Down
6 changes: 3 additions & 3 deletions llvm/test/CodeGen/LoongArch/analyze-branch.ll
Expand Up @@ -49,14 +49,14 @@ define void @test_bcc_fallthrough_nottaken(i64 %in) nounwind {
; CHECK-NEXT: addi.d $sp, $sp, -16
; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
; CHECK-NEXT: ori $a1, $zero, 42
; CHECK-NEXT: beq $a0, $a1, .LBB1_1
; CHECK-NEXT: # %bb.3: # %false
; CHECK-NEXT: beq $a0, $a1, .LBB1_3
; CHECK-NEXT: # %bb.1: # %false
; CHECK-NEXT: bl %plt(test_false)
; CHECK-NEXT: .LBB1_2: # %true
; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
; CHECK-NEXT: addi.d $sp, $sp, 16
; CHECK-NEXT: ret
; CHECK-NEXT: .LBB1_1: # %true
; CHECK-NEXT: .LBB1_3: # %true
; CHECK-NEXT: bl %plt(test_true)
; CHECK-NEXT: b .LBB1_2
%tst = icmp eq i64 %in, 42
Expand Down
132 changes: 132 additions & 0 deletions llvm/test/CodeGen/LoongArch/branch-relaxation.ll
@@ -0,0 +1,132 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc --mtriple=loongarch32 --filetype=obj --verify-machineinstrs < %s \
; RUN: -o /dev/null 2>&1
; RUN: llc --mtriple=loongarch64 --filetype=obj --verify-machineinstrs < %s \
; RUN: -o /dev/null 2>&1
; RUN: llc --mtriple=loongarch32 --verify-machineinstrs < %s | FileCheck %s --check-prefix=LA32
; RUN: llc --mtriple=loongarch64 --verify-machineinstrs < %s | FileCheck %s --check-prefix=LA64

define i32 @relax_b18(i32 signext %a, i32 signext %b) {
; LA32-LABEL: relax_b18:
; LA32: # %bb.0:
; LA32-NEXT: beq $a0, $a1, .LBB0_1
; LA32-NEXT: b .LBB0_2
; LA32-NEXT: .LBB0_1: # %iftrue
; LA32-NEXT: #APP
; LA32-NEXT: .space 1048576
; LA32-NEXT: #NO_APP
; LA32-NEXT: ori $a0, $zero, 1
; LA32-NEXT: ret
; LA32-NEXT: .LBB0_2: # %iffalse
; LA32-NEXT: move $a0, $zero
; LA32-NEXT: ret
;
; LA64-LABEL: relax_b18:
; LA64: # %bb.0:
; LA64-NEXT: beq $a0, $a1, .LBB0_1
; LA64-NEXT: b .LBB0_2
; LA64-NEXT: .LBB0_1: # %iftrue
; LA64-NEXT: #APP
; LA64-NEXT: .space 1048576
; LA64-NEXT: #NO_APP
; LA64-NEXT: ori $a0, $zero, 1
; LA64-NEXT: ret
; LA64-NEXT: .LBB0_2: # %iffalse
; LA64-NEXT: move $a0, $zero
; LA64-NEXT: ret
%cond = icmp eq i32 %a, %b
br i1 %cond, label %iftrue, label %iffalse

iftrue:
call void asm sideeffect ".space 1048576", ""()
ret i32 1

iffalse:
ret i32 0
}

define i32 @relax_b23(i1 %a) {
; LA32-LABEL: relax_b23:
; LA32: # %bb.0:
; LA32-NEXT: andi $a0, $a0, 1
; LA32-NEXT: bnez $a0, .LBB1_1
; LA32-NEXT: b .LBB1_2
; LA32-NEXT: .LBB1_1: # %iftrue
; LA32-NEXT: #APP
; LA32-NEXT: .space 16777216
; LA32-NEXT: #NO_APP
; LA32-NEXT: ori $a0, $zero, 1
; LA32-NEXT: ret
; LA32-NEXT: .LBB1_2: # %iffalse
; LA32-NEXT: move $a0, $zero
; LA32-NEXT: ret
;
; LA64-LABEL: relax_b23:
; LA64: # %bb.0:
; LA64-NEXT: andi $a0, $a0, 1
; LA64-NEXT: bnez $a0, .LBB1_1
; LA64-NEXT: b .LBB1_2
; LA64-NEXT: .LBB1_1: # %iftrue
; LA64-NEXT: #APP
; LA64-NEXT: .space 16777216
; LA64-NEXT: #NO_APP
; LA64-NEXT: ori $a0, $zero, 1
; LA64-NEXT: ret
; LA64-NEXT: .LBB1_2: # %iffalse
; LA64-NEXT: move $a0, $zero
; LA64-NEXT: ret
br i1 %a, label %iftrue, label %iffalse

iftrue:
call void asm sideeffect ".space 16777216", ""()
ret i32 1

iffalse:
ret i32 0
}

define i32 @relax_b28(i1 %a) {
; LA32-LABEL: relax_b28:
; LA32: # %bb.0:
; LA32-NEXT: andi $a0, $a0, 1
; LA32-NEXT: bnez $a0, .LBB2_1
; LA32-NEXT: # %bb.3:
; LA32-NEXT: pcalau12i $a0, %pc_hi20(.LBB2_2)
; LA32-NEXT: addi.w $a0, $a0, %pc_lo12(.LBB2_2)
; LA32-NEXT: jr $a0
; LA32-NEXT: .LBB2_1: # %iftrue
; LA32-NEXT: #APP
; LA32-NEXT: .space 536870912
; LA32-NEXT: #NO_APP
; LA32-NEXT: ori $a0, $zero, 1
; LA32-NEXT: ret
; LA32-NEXT: .LBB2_2: # %iffalse
; LA32-NEXT: move $a0, $zero
; LA32-NEXT: ret
;
; LA64-LABEL: relax_b28:
; LA64: # %bb.0:
; LA64-NEXT: andi $a0, $a0, 1
; LA64-NEXT: bnez $a0, .LBB2_1
; LA64-NEXT: # %bb.3:
; LA64-NEXT: pcalau12i $a0, %pc_hi20(.LBB2_2)
; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(.LBB2_2)
; LA64-NEXT: jr $a0
; LA64-NEXT: .LBB2_1: # %iftrue
; LA64-NEXT: #APP
; LA64-NEXT: .space 536870912
; LA64-NEXT: #NO_APP
; LA64-NEXT: ori $a0, $zero, 1
; LA64-NEXT: ret
; LA64-NEXT: .LBB2_2: # %iffalse
; LA64-NEXT: move $a0, $zero
; LA64-NEXT: ret
br i1 %a, label %iftrue, label %iffalse

iftrue:
call void asm sideeffect ".space 536870912", ""()
ret i32 1

iffalse:
ret i32 0
}
12 changes: 6 additions & 6 deletions llvm/test/CodeGen/LoongArch/exception-pointer-register.ll
Expand Up @@ -24,14 +24,14 @@ define void @caller(ptr %p) personality ptr @__gxx_personality_v0 {
; LA32-NEXT: .cfi_offset 22, -8
; LA32-NEXT: .cfi_offset 23, -12
; LA32-NEXT: move $fp, $a0
; LA32-NEXT: beqz $a0, .LBB0_1
; LA32-NEXT: # %bb.2: # %bb2
; LA32-NEXT: beqz $a0, .LBB0_2
; LA32-NEXT: # %bb.1: # %bb2
; LA32-NEXT: .Ltmp0:
; LA32-NEXT: move $a0, $fp
; LA32-NEXT: bl %plt(bar)
; LA32-NEXT: .Ltmp1:
; LA32-NEXT: b .LBB0_3
; LA32-NEXT: .LBB0_1: # %bb1
; LA32-NEXT: .LBB0_2: # %bb1
; LA32-NEXT: .Ltmp2:
; LA32-NEXT: move $a0, $fp
; LA32-NEXT: bl %plt(foo)
Expand Down Expand Up @@ -61,14 +61,14 @@ define void @caller(ptr %p) personality ptr @__gxx_personality_v0 {
; LA64-NEXT: .cfi_offset 22, -16
; LA64-NEXT: .cfi_offset 23, -24
; LA64-NEXT: move $fp, $a0
; LA64-NEXT: beqz $a0, .LBB0_1
; LA64-NEXT: # %bb.2: # %bb2
; LA64-NEXT: beqz $a0, .LBB0_2
; LA64-NEXT: # %bb.1: # %bb2
; LA64-NEXT: .Ltmp0:
; LA64-NEXT: move $a0, $fp
; LA64-NEXT: bl %plt(bar)
; LA64-NEXT: .Ltmp1:
; LA64-NEXT: b .LBB0_3
; LA64-NEXT: .LBB0_1: # %bb1
; LA64-NEXT: .LBB0_2: # %bb1
; LA64-NEXT: .Ltmp2:
; LA64-NEXT: move $a0, $fp
; LA64-NEXT: bl %plt(foo)
Expand Down

0 comments on commit 57ad3f1

Please sign in to comment.