#include "LoongArch.h"
#include "LoongArchMachineFunctionInfo.h"
#include "MCTargetDesc/LoongArchMatInt.h"
+#include "llvm/CodeGen/RegisterScavenging.h"
using namespace llvm;
}
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();
}
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)
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:
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;
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;
void addIRPasses() override;
bool addInstSelector() override;
+ void addPreEmitPass() override;
void addPreEmitPass2() override;
void addPreRegAlloc() override;
};
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
; 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
--- /dev/null
+; 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
+}
; 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)
; 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)
; LA32-NEXT: blt $a2, $a0, .LBB0_4
; LA32-NEXT: # %bb.1: # %entry
; LA32-NEXT: ori $a3, $zero, 1
-; LA32-NEXT: beq $a0, $a3, .LBB0_8
+; LA32-NEXT: beq $a0, $a3, .LBB0_7
; LA32-NEXT: # %bb.2: # %entry
-; LA32-NEXT: bne $a0, $a2, .LBB0_10
+; LA32-NEXT: bne $a0, $a2, .LBB0_9
; LA32-NEXT: # %bb.3: # %bb2
; LA32-NEXT: ori $a0, $zero, 3
; LA32-NEXT: st.w $a0, $a1, 0
; LA32-NEXT: ret
; LA32-NEXT: .LBB0_4: # %entry
; LA32-NEXT: ori $a3, $zero, 3
-; LA32-NEXT: beq $a0, $a3, .LBB0_9
+; LA32-NEXT: beq $a0, $a3, .LBB0_8
; LA32-NEXT: # %bb.5: # %entry
; LA32-NEXT: ori $a2, $zero, 4
-; LA32-NEXT: bne $a0, $a2, .LBB0_10
+; LA32-NEXT: bne $a0, $a2, .LBB0_9
; LA32-NEXT: # %bb.6: # %bb4
; LA32-NEXT: ori $a0, $zero, 1
; LA32-NEXT: st.w $a0, $a1, 0
; LA32-NEXT: ret
-; LA32-NEXT: .LBB0_8: # %bb1
+; LA32-NEXT: .LBB0_7: # %bb1
; LA32-NEXT: ori $a0, $zero, 4
; LA32-NEXT: st.w $a0, $a1, 0
; LA32-NEXT: ret
-; LA32-NEXT: .LBB0_9: # %bb3
+; LA32-NEXT: .LBB0_8: # %bb3
; LA32-NEXT: st.w $a2, $a1, 0
-; LA32-NEXT: .LBB0_10: # %exit
+; LA32-NEXT: .LBB0_9: # %exit
; LA32-NEXT: ret
;
; LA64-LABEL: switch_4_arms:
; LA64-NEXT: blt $a2, $a0, .LBB0_4
; LA64-NEXT: # %bb.1: # %entry
; LA64-NEXT: ori $a3, $zero, 1
-; LA64-NEXT: beq $a0, $a3, .LBB0_8
+; LA64-NEXT: beq $a0, $a3, .LBB0_7
; LA64-NEXT: # %bb.2: # %entry
-; LA64-NEXT: bne $a0, $a2, .LBB0_10
+; LA64-NEXT: bne $a0, $a2, .LBB0_9
; LA64-NEXT: # %bb.3: # %bb2
; LA64-NEXT: ori $a0, $zero, 3
; LA64-NEXT: st.w $a0, $a1, 0
; LA64-NEXT: ret
; LA64-NEXT: .LBB0_4: # %entry
; LA64-NEXT: ori $a3, $zero, 3
-; LA64-NEXT: beq $a0, $a3, .LBB0_9
+; LA64-NEXT: beq $a0, $a3, .LBB0_8
; LA64-NEXT: # %bb.5: # %entry
; LA64-NEXT: ori $a2, $zero, 4
-; LA64-NEXT: bne $a0, $a2, .LBB0_10
+; LA64-NEXT: bne $a0, $a2, .LBB0_9
; LA64-NEXT: # %bb.6: # %bb4
; LA64-NEXT: ori $a0, $zero, 1
; LA64-NEXT: st.w $a0, $a1, 0
; LA64-NEXT: ret
-; LA64-NEXT: .LBB0_8: # %bb1
+; LA64-NEXT: .LBB0_7: # %bb1
; LA64-NEXT: ori $a0, $zero, 4
; LA64-NEXT: st.w $a0, $a1, 0
; LA64-NEXT: ret
-; LA64-NEXT: .LBB0_9: # %bb3
+; LA64-NEXT: .LBB0_8: # %bb3
; LA64-NEXT: st.w $a2, $a1, 0
-; LA64-NEXT: .LBB0_10: # %exit
+; LA64-NEXT: .LBB0_9: # %exit
; LA64-NEXT: ret
;
; LA32-JT-LABEL: switch_4_arms:
; CHECK-NEXT: .cfi_def_cfa 22, 0
; CHECK-NEXT: st.w $zero, $fp, -16
; CHECK-NEXT: st.w $zero, $fp, -12
-; CHECK-NEXT: beqz $zero, .LBB0_1
-; CHECK-NEXT: # %bb.2:
+; CHECK-NEXT: beqz $zero, .LBB0_3
+; CHECK-NEXT: # %bb.1:
; CHECK-NEXT: ori $a0, $zero, 1
; CHECK-NEXT: st.w $a0, $fp, -24
; CHECK-NEXT: ld.w $a0, $fp, -16
; CHECK-NEXT: beqz $a0, .LBB0_4
-; CHECK-NEXT: .LBB0_5:
+; CHECK-NEXT: .LBB0_2:
; CHECK-NEXT: ori $a0, $zero, 1
; CHECK-NEXT: st.w $a0, $fp, -24
-; CHECK-NEXT: b .LBB0_6
-; CHECK-NEXT: .LBB0_1:
+; CHECK-NEXT: b .LBB0_5
+; CHECK-NEXT: .LBB0_3:
; CHECK-NEXT: ori $a0, $zero, 2
; CHECK-NEXT: st.w $a0, $fp, -20
; CHECK-NEXT: ori $a0, $zero, 1
; CHECK-NEXT: ori $a0, $zero, 4
; CHECK-NEXT: st.w $a0, $fp, -28
; CHECK-NEXT: ld.w $a0, $fp, -16
-; CHECK-NEXT: bnez $a0, .LBB0_5
+; CHECK-NEXT: bnez $a0, .LBB0_2
; CHECK-NEXT: .LBB0_4:
; CHECK-NEXT: ori $a0, $zero, 2
; CHECK-NEXT: st.w $a0, $fp, -20
; CHECK-NEXT: st.w $a0, $fp, -24
; CHECK-NEXT: ori $a0, $zero, 4
; CHECK-NEXT: st.w $a0, $fp, -28
-; CHECK-NEXT: .LBB0_6:
+; CHECK-NEXT: .LBB0_5:
; CHECK-NEXT: move $a0, $zero
; CHECK-NEXT: ld.w $fp, $sp, 24 # 4-byte Folded Reload
; CHECK-NEXT: ld.w $ra, $sp, 28 # 4-byte Folded Reload
; CHECK-NEXT: .cfi_def_cfa 22, 0
; CHECK-NEXT: st.w $zero, $fp, -16
; CHECK-NEXT: st.w $zero, $fp, -12
-; CHECK-NEXT: beqz $zero, .LBB0_1
-; CHECK-NEXT: # %bb.2:
+; CHECK-NEXT: beqz $zero, .LBB0_3
+; CHECK-NEXT: # %bb.1:
; CHECK-NEXT: ori $a0, $zero, 1
; CHECK-NEXT: st.w $a0, $fp, -24
; CHECK-NEXT: ld.w $a0, $fp, -16
; CHECK-NEXT: beqz $a0, .LBB0_4
-; CHECK-NEXT: .LBB0_5:
+; CHECK-NEXT: .LBB0_2:
; CHECK-NEXT: ori $a0, $zero, 1
; CHECK-NEXT: st.w $a0, $fp, -24
-; CHECK-NEXT: b .LBB0_6
-; CHECK-NEXT: .LBB0_1:
+; CHECK-NEXT: b .LBB0_5
+; CHECK-NEXT: .LBB0_3:
; CHECK-NEXT: ori $a0, $zero, 2
; CHECK-NEXT: st.w $a0, $fp, -20
; CHECK-NEXT: ori $a0, $zero, 1
; CHECK-NEXT: ori $a0, $zero, 4
; CHECK-NEXT: st.w $a0, $fp, -28
; CHECK-NEXT: ld.w $a0, $fp, -16
-; CHECK-NEXT: bnez $a0, .LBB0_5
+; CHECK-NEXT: bnez $a0, .LBB0_2
; CHECK-NEXT: .LBB0_4:
; CHECK-NEXT: ori $a0, $zero, 2
; CHECK-NEXT: st.w $a0, $fp, -20
; CHECK-NEXT: st.w $a0, $fp, -24
; CHECK-NEXT: ori $a0, $zero, 4
; CHECK-NEXT: st.w $a0, $fp, -28
-; CHECK-NEXT: .LBB0_6:
+; CHECK-NEXT: .LBB0_5:
; CHECK-NEXT: move $a0, $zero
; CHECK-NEXT: ld.w $fp, $sp, 24 # 4-byte Folded Reload
; CHECK-NEXT: ld.w $ra, $sp, 28 # 4-byte Folded Reload