[llvm] 98117f1 - [RISCV] MC relaxation for out-of-range conditional branch.
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Fri Feb 3 12:34:08 PST 2023
Author: Craig Topper
Date: 2023-02-03T12:33:44-08:00
New Revision: 98117f1a743cbddefa3dd1c678ce01478fa98454
URL: https://github.com/llvm/llvm-project/commit/98117f1a743cbddefa3dd1c678ce01478fa98454
DIFF: https://github.com/llvm/llvm-project/commit/98117f1a743cbddefa3dd1c678ce01478fa98454.diff
LOG: [RISCV] MC relaxation for out-of-range conditional branch.
If .L1 is not within +-4KiB range,
convert
```
bge a0, a1, .L1
```
to
```
blt a0, a1, 8
j .L1
```
In this patch, if the symbol is unresolved at assembly time, do not do
this relaxation.
Fix the bug reported in https://bugs.llvm.org/show_bug.cgi?id=47910
Co-authored-by: Hsiangkai Wang
Reviewed By: asb
Differential Revision: https://reviews.llvm.org/D108961
Added:
llvm/test/MC/RISCV/long-conditional-jump.s
Modified:
llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
llvm/lib/Target/RISCV/RISCVInstrInfo.td
llvm/test/MC/RISCV/fixups-diagnostics.s
llvm/test/MC/RISCV/rv64-relax-all.s
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
index 56c2a0de5bcd1..22cc65d7184b8 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -143,6 +143,15 @@ bool RISCVAsmBackend::fixupNeedsRelaxationAdvanced(const MCFixup &Fixup,
const MCRelaxableFragment *DF,
const MCAsmLayout &Layout,
const bool WasForced) const {
+ int64_t Offset = int64_t(Value);
+ unsigned Kind = Fixup.getTargetKind();
+
+ // We only do conditional branch relaxation when the symbol is resolved.
+ // For conditional branch, the immediate must be in the range
+ // [-4096, 4094].
+ if (Kind == RISCV::fixup_riscv_branch)
+ return Resolved && !isInt<13>(Offset);
+
// Return true if the symbol is actually unresolved.
// Resolved could be always false when shouldForceRelocation return true.
// We use !WasForced to indicate that the symbol is unresolved and not forced
@@ -150,8 +159,7 @@ bool RISCVAsmBackend::fixupNeedsRelaxationAdvanced(const MCFixup &Fixup,
if (!Resolved && !WasForced)
return true;
- int64_t Offset = int64_t(Value);
- switch (Fixup.getTargetKind()) {
+ switch (Kind) {
default:
return false;
case RISCV::fixup_riscv_rvc_branch:
@@ -174,12 +182,24 @@ void RISCVAsmBackend::relaxInstruction(MCInst &Inst,
case RISCV::C_BEQZ:
case RISCV::C_BNEZ:
case RISCV::C_J:
- case RISCV::C_JAL:
+ case RISCV::C_JAL: {
bool Success = RISCVRVC::uncompress(Res, Inst, STI);
assert(Success && "Can't uncompress instruction");
(void)Success;
break;
}
+ case RISCV::BEQ:
+ case RISCV::BNE:
+ case RISCV::BLT:
+ case RISCV::BGE:
+ case RISCV::BLTU:
+ case RISCV::BGEU:
+ Res.setOpcode(getRelaxedOpcode(Inst.getOpcode()));
+ Res.addOperand(Inst.getOperand(0));
+ Res.addOperand(Inst.getOperand(1));
+ Res.addOperand(Inst.getOperand(2));
+ break;
+ }
Inst = std::move(Res);
}
@@ -321,6 +341,18 @@ unsigned RISCVAsmBackend::getRelaxedOpcode(unsigned Op) const {
case RISCV::C_J:
case RISCV::C_JAL: // fall through.
return RISCV::JAL;
+ case RISCV::BEQ:
+ return RISCV::PseudoLongBEQ;
+ case RISCV::BNE:
+ return RISCV::PseudoLongBNE;
+ case RISCV::BLT:
+ return RISCV::PseudoLongBLT;
+ case RISCV::BGE:
+ return RISCV::PseudoLongBGE;
+ case RISCV::BLTU:
+ return RISCV::PseudoLongBLTU;
+ case RISCV::BGEU:
+ return RISCV::PseudoLongBGEU;
}
}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
index 9f5561bfd2aee..c01f3aae447d9 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -61,6 +61,10 @@ class RISCVMCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ void expandLongCondBr(const MCInst &MI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
/// TableGen'erated function for getting the binary encoding for an
/// instruction.
uint64_t getBinaryCodeForInstr(const MCInst &MI,
@@ -179,6 +183,81 @@ void RISCVMCCodeEmitter::expandAddTPRel(const MCInst &MI, raw_ostream &OS,
support::endian::write(OS, Binary, support::little);
}
+static unsigned getInvertedBranchOp(unsigned BrOp) {
+ switch (BrOp) {
+ default:
+ llvm_unreachable("Unexpected branch opcode!");
+ case RISCV::PseudoLongBEQ:
+ return RISCV::BNE;
+ case RISCV::PseudoLongBNE:
+ return RISCV::BEQ;
+ case RISCV::PseudoLongBLT:
+ return RISCV::BGE;
+ case RISCV::PseudoLongBGE:
+ return RISCV::BLT;
+ case RISCV::PseudoLongBLTU:
+ return RISCV::BGEU;
+ case RISCV::PseudoLongBGEU:
+ return RISCV::BLTU;
+ }
+}
+
+// Expand PseudoLongBxx to an inverted conditional branch and an unconditional
+// jump.
+void RISCVMCCodeEmitter::expandLongCondBr(const MCInst &MI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ MCRegister SrcReg1 = MI.getOperand(0).getReg();
+ MCRegister SrcReg2 = MI.getOperand(1).getReg();
+ MCOperand SrcSymbol = MI.getOperand(2);
+ unsigned Opcode = MI.getOpcode();
+ bool IsEqTest =
+ Opcode == RISCV::PseudoLongBNE || Opcode == RISCV::PseudoLongBEQ;
+
+ bool UseCompressedBr = false;
+ if (IsEqTest && (STI.getFeatureBits()[RISCV::FeatureStdExtC] ||
+ STI.getFeatureBits()[RISCV::FeatureExtZca])) {
+ if (RISCV::X8 <= SrcReg1.id() && SrcReg1.id() <= RISCV::X15 &&
+ SrcReg2.id() == RISCV::X0) {
+ UseCompressedBr = true;
+ } else if (RISCV::X8 <= SrcReg2.id() && SrcReg2.id() <= RISCV::X15 &&
+ SrcReg1.id() == RISCV::X0) {
+ std::swap(SrcReg1, SrcReg2);
+ UseCompressedBr = true;
+ }
+ }
+
+ uint32_t Offset;
+ if (UseCompressedBr) {
+ unsigned InvOpc =
+ Opcode == RISCV::PseudoLongBNE ? RISCV::C_BEQZ : RISCV::C_BNEZ;
+ MCInst TmpInst = MCInstBuilder(InvOpc).addReg(SrcReg1).addImm(6);
+ uint16_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);
+ support::endian::write<uint16_t>(OS, Binary, support::little);
+ Offset = 2;
+ } else {
+ unsigned InvOpc = getInvertedBranchOp(Opcode);
+ MCInst TmpInst =
+ MCInstBuilder(InvOpc).addReg(SrcReg1).addReg(SrcReg2).addImm(8);
+ uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);
+ support::endian::write(OS, Binary, support::little);
+ Offset = 4;
+ }
+
+ // Emit an unconditional jump to the destination.
+ MCInst TmpInst =
+ MCInstBuilder(RISCV::JAL).addReg(RISCV::X0).addOperand(SrcSymbol);
+ uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);
+ support::endian::write(OS, Binary, support::little);
+
+ Fixups.clear();
+ if (SrcSymbol.isExpr()) {
+ Fixups.push_back(MCFixup::create(Offset, SrcSymbol.getExpr(),
+ MCFixupKind(RISCV::fixup_riscv_jal),
+ MI.getLoc()));
+ }
+}
+
void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
@@ -203,6 +282,15 @@ void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
expandAddTPRel(MI, OS, Fixups, STI);
MCNumEmitted += 1;
return;
+ case RISCV::PseudoLongBEQ:
+ case RISCV::PseudoLongBNE:
+ case RISCV::PseudoLongBLT:
+ case RISCV::PseudoLongBGE:
+ case RISCV::PseudoLongBLTU:
+ case RISCV::PseudoLongBGEU:
+ expandLongCondBr(MI, OS, Fixups, STI);
+ MCNumEmitted += 2;
+ return;
}
switch (Size) {
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index fb313b935ff9c..81c25373352f9 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -1469,6 +1469,26 @@ let Predicates = [HasStdExtC, OptForMinSize] in {
def : BrccCompessOpt<SETNE, BNE>;
}
+class LongBccPseudo : Pseudo<(outs),
+ (ins GPR:$rs1, GPR:$rs2, simm21_lsb0_jal:$imm20),
+ []> {
+ let Size = 8;
+ let isBarrier = 1;
+ let isBranch = 1;
+ let hasSideEffects = 0;
+ let mayStore = 0;
+ let mayLoad = 0;
+ let isAsmParserOnly = 1;
+ let hasNoSchedulingInfo = 1;
+}
+
+def PseudoLongBEQ : LongBccPseudo;
+def PseudoLongBNE : LongBccPseudo;
+def PseudoLongBLT : LongBccPseudo;
+def PseudoLongBGE : LongBccPseudo;
+def PseudoLongBLTU : LongBccPseudo;
+def PseudoLongBGEU : LongBccPseudo;
+
let isBarrier = 1, isBranch = 1, isTerminator = 1 in
def PseudoBR : Pseudo<(outs), (ins simm21_lsb0_jal:$imm20), [(br bb:$imm20)]>,
PseudoInstExpansion<(JAL X0, simm21_lsb0_jal:$imm20)>;
diff --git a/llvm/test/MC/RISCV/fixups-diagnostics.s b/llvm/test/MC/RISCV/fixups-diagnostics.s
index d346605221c75..3c99673b81fc2 100644
--- a/llvm/test/MC/RISCV/fixups-diagnostics.s
+++ b/llvm/test/MC/RISCV/fixups-diagnostics.s
@@ -3,7 +3,6 @@
jal a0, far_distant # CHECK: :[[@LINE]]:3: error: fixup value out of range
jal a0, unaligned # CHECK: :[[@LINE]]:3: error: fixup value must be 2-byte aligned
- beq a0, a1, distant # CHECK: :[[@LINE]]:3: error: fixup value out of range
blt t0, t1, unaligned # CHECK: :[[@LINE]]:3: error: fixup value must be 2-byte aligned
.byte 0
@@ -12,7 +11,5 @@ unaligned:
.byte 0
.byte 0
- .space 1<<12
-distant:
.space 1<<20
far_distant:
diff --git a/llvm/test/MC/RISCV/long-conditional-jump.s b/llvm/test/MC/RISCV/long-conditional-jump.s
new file mode 100644
index 0000000000000..27d3d105838d3
--- /dev/null
+++ b/llvm/test/MC/RISCV/long-conditional-jump.s
@@ -0,0 +1,93 @@
+# RUN: llvm-mc -filetype=obj -triple=riscv64 %s \
+# RUN: | llvm-objdump -d -M no-aliases - \
+# RUN: | FileCheck --check-prefix=CHECK-INST %s
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c %s \
+# RUN: | llvm-objdump -d -M no-aliases - \
+# RUN: | FileCheck --check-prefix=CHECK-INST-C %s
+
+ .text
+ .p2align 3
+ .type test, at function
+test:
+# CHECK-INST: beq a0, a1, 0x8
+# CHECK-INST-NEXT: jal zero, 0x1458
+# CHECK-INST-C: beq a0, a1, 0x8
+# CHECK-INST-C-NEXT: jal zero, 0x1458
+ bne a0, a1, .L1
+.fill 1300, 4, 0
+.L1:
+ ret
+# CHECK-INST: bne a0, a1, 0x1464
+# CHECK-INST-NEXT: jal zero, 0x28b4
+# CHECK-INST-C: bne a0, a1, 0x1462
+# CHECK-INST-C-NEXT: jal zero, 0x28b2
+ beq a0, a1, .L2
+.fill 1300, 4, 0
+.L2:
+ ret
+# CHECK-INST: bge a0, a1, 0x28c0
+# CHECK-INST-NEXT: jal zero, 0x3d10
+# CHECK-INST-C: bge a0, a1, 0x28bc
+# CHECK-INST-C-NEXT: jal zero, 0x3d0c
+ blt a0, a1, .L3
+.fill 1300, 4, 0
+.L3:
+ ret
+# CHECK-INST: blt a0, a1, 0x3d1c
+# CHECK-INST-NEXT: jal zero, 0x516c
+# CHECK-INST-C: blt a0, a1, 0x3d16
+# CHECK-INST-C-NEXT: jal zero, 0x5166
+ bge a0, a1, .L4
+.fill 1300, 4, 0
+.L4:
+ ret
+# CHECK-INST: bgeu a0, a1, 0x5178
+# CHECK-INST-NEXT: jal zero, 0x65c8
+# CHECK-INST-C: bgeu a0, a1, 0x5170
+# CHECK-INST-C-NEXT: jal zero, 0x65c0
+ bltu a0, a1, .L5
+.fill 1300, 4, 0
+.L5:
+ ret
+# CHECK-INST: bltu a0, a1, 0x65d4
+# CHECK-INST-NEXT: jal zero, 0x7a24
+# CHECK-INST-C: bltu a0, a1, 0x65ca
+# CHECK-INST-C-NEXT: jal zero, 0x7a1a
+ bgeu a0, a1, .L6
+.fill 1300, 4, 0
+.L6:
+ ret
+# CHECK-INST: bne a0, zero, 0x7a30
+# CHECK-INST-NEXT: jal zero, 0x8e80
+# CHECK-INST-C: c.bnez a0, 0x7a22
+# CHECK-INST-C-NEXT: jal zero, 0x8e72
+ beqz a0, .L7
+.fill 1300, 4, 0
+.L7:
+ ret
+# CHECK-INST: bne zero, a0, 0x8e8c
+# CHECK-INST-NEXT: jal zero, 0xa2dc
+# CHECK-INST-C: c.bnez a0, 0x8e7a
+# CHECK-INST-C-NEXT: jal zero, 0xa2ca
+ beq x0, a0, .L8
+.fill 1300, 4, 0
+.L8:
+ ret
+# CHECK-INST: beq a0, zero, 0xa2e8
+# CHECK-INST-NEXT: jal zero, 0xb738
+# CHECK-INST-C: c.beqz a0, 0xa2d2
+# CHECK-INST-C-NEXT: jal zero, 0xb722
+ bnez a0, .L9
+.fill 1300, 4, 0
+.L9:
+ ret
+# CHECK-INST: beq a6, zero, 0xb744
+# CHECK-INST-NEXT: jal zero, 0xcb94
+# CHECK-INST-C: beq a6, zero, 0xb72c
+# CHECK-INST-C-NEXT: jal zero, 0xcb7c
+ bnez x16, .L10
+.fill 1300, 4, 0
+.L10:
+ ret
+.Lfunc_end0:
+ .size test, .Lfunc_end0-test
diff --git a/llvm/test/MC/RISCV/rv64-relax-all.s b/llvm/test/MC/RISCV/rv64-relax-all.s
index 84ef373b741b4..70a3f77540c99 100644
--- a/llvm/test/MC/RISCV/rv64-relax-all.s
+++ b/llvm/test/MC/RISCV/rv64-relax-all.s
@@ -7,7 +7,8 @@
NEAR:
# INSTR: c.beqz a0, 0x0 <NEAR>
-# RELAX-INSTR: beq a0, zero, 0x0 <NEAR>
+# RELAX-INSTR: c.bnez a0, 0x6
+# RELAX-INSTR-NEXT:jal zero, 0x0 <NEAR>
c.beqz a0, NEAR
# INSTR: c.j 0x0 <NEAR>
More information about the llvm-commits
mailing list