[RISCV] Add symbol parsing support for the Xqcibi branch immediate instructions (#134233)
This patch adds support for parsing symbols in the Xqcibi branch
immediate instructions. While the 32 bit branch instructions use the
same instruction format and relocation as the existing branch
instructions in RISCV, the 48 bit ones use the `InstFormatQC_EB`
instruction format and the `R_RISCV_QC_E_BRANCH` relocation that is
defined in `BinaryFormat/ELFRelocs/RISCV_nonstandard.def.`
Vendor relocation support will be added in a later patch.
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
index 37cd79e..10a2655 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -92,6 +92,7 @@
{"fixup_riscv_tlsdesc_load_lo12", 20, 12, 0},
{"fixup_riscv_tlsdesc_add_lo12", 20, 12, 0},
{"fixup_riscv_tlsdesc_call", 0, 0, 0},
+ {"fixup_riscv_qc_e_branch", 0, 48, MCFixupKindInfo::FKF_IsPCRel},
};
static_assert((std::size(Infos)) == RISCV::NumTargetFixupKinds,
"Not all fixup kinds added to Infos array");
@@ -165,6 +166,7 @@
// in the range [-2048, 2046].
return Offset > 2046 || Offset < -2048;
case RISCV::fixup_riscv_branch:
+ case RISCV::fixup_riscv_qc_e_branch:
// For conditional branch instructions the immediate must be
// in the range [-4096, 4095].
return !isInt<13>(Offset);
@@ -464,6 +466,7 @@
Value = (Sbit << 19) | (Lo10 << 9) | (Mid1 << 8) | Hi8;
return Value;
}
+ case RISCV::fixup_riscv_qc_e_branch:
case RISCV::fixup_riscv_branch: {
if (!isInt<13>(Value))
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
index 5faeb98..2e73ba5 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
@@ -120,6 +120,8 @@
return ELF::R_RISCV_CALL_PLT;
case RISCV::fixup_riscv_call_plt:
return ELF::R_RISCV_CALL_PLT;
+ case RISCV::fixup_riscv_qc_e_branch:
+ return ELF::R_RISCV_QC_E_BRANCH;
}
}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
index 821372d..df7916a 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
@@ -77,6 +77,9 @@
fixup_riscv_tlsdesc_load_lo12,
fixup_riscv_tlsdesc_add_lo12,
fixup_riscv_tlsdesc_call,
+ // 12-bit fixup for symbol references in the 48-bit Xqcibi branch immediate
+ // instructions
+ fixup_riscv_qc_e_branch,
// Used as a sentinel, must be the last
fixup_riscv_invalid,
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
index 69ad3d9..fc98859 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -569,6 +569,8 @@
FixupKind = RISCV::fixup_riscv_rvc_branch;
} else if (MIFrm == RISCVII::InstFormatI) {
FixupKind = RISCV::fixup_riscv_12_i;
+ } else if (MIFrm == RISCVII::InstFormatQC_EB) {
+ FixupKind = RISCV::fixup_riscv_qc_e_branch;
}
}
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index 93eb82b..64d6f6d 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -550,7 +550,7 @@
class QCIBranchInst48_rii<bits<5> funct5, DAGOperand InTyImm16, string opcodestr>
: RVInst48<(outs),
(ins GPRNoX0:$rs1, InTyImm16:$imm16, bare_simm13_lsb0:$imm12),
- opcodestr, "$rs1, $imm16, $imm12", [], InstFormatOther> {
+ opcodestr, "$rs1, $imm16, $imm12", [], InstFormatQC_EB> {
bits<5> rs1;
bits<16> imm16;
bits<12> imm12;
diff --git a/llvm/test/MC/RISCV/xqcibi-relocations.s b/llvm/test/MC/RISCV/xqcibi-relocations.s
new file mode 100644
index 0000000..4899e5f
--- /dev/null
+++ b/llvm/test/MC/RISCV/xqcibi-relocations.s
@@ -0,0 +1,44 @@
+# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcibi %s -show-encoding \
+# RUN: | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s
+# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqcibi %s -o %t.o
+# RUN: llvm-readobj -r %t.o | FileCheck -check-prefix=RELOC %s
+
+# Check prefixes:
+# RELOC - Check the relocation in the object.
+# FIXUP - Check the fixup on the instruction.
+# INSTR - Check the instruction is handled properly by the ASMPrinter.
+
+.text
+
+# Check that branch to an undefined symbol is handled
+# FIXME: This should be relaxed to an inverse branch and jump
+qc.bnei x6, 10, foo
+# RELOC: R_RISCV_BRANCH foo 0x0
+# INSTR: qc.bnei t1, 10, foo
+# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_branch
+
+# FIXME: This should be relaxed to an inverse branch and jump
+qc.e.bgeui x8, 12, foo
+# RELOC: R_RISCV_CUSTOM193 foo 0x0
+# INSTR: qc.e.bgeui s0, 12, foo
+# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_qc_e_branch
+
+# Check that a label in a different section is handled similar to an undefined symbol
+# FIXME: This should be relaxed to an inverse branch and jump
+qc.e.bltui x4, 9, .bar
+# RELOC: R_RISCV_CUSTOM193 .bar 0x0
+# INSTR: qc.e.bltui tp, 9, .bar
+# FIXUP: fixup A - offset: 0, value: .bar, kind: fixup_riscv_qc_e_branch
+
+# Check that branches to a defined symbol are handled correctly
+qc.e.beqi x7, 8, .L1
+# INSTR: qc.e.beqi t2, 8, .L1
+# FIXUP: fixup A - offset: 0, value: .L1, kind: fixup_riscv_qc_e_branch
+
+.L1:
+ ret
+
+.section .t2
+
+.bar:
+ ret