Skip to content

Commit 1d2f5ea

Browse files
authored
[RISCV] Add symbol parsing support for Xqcili load large immediate instructions (#134581)
This patch adds support for parsing symbols in the Xqcili load large immediate instructions. The 32 bit `qc.li` instructions uses the `R_RISCV_QC_ABS20_U` relocation while the 48 bit `qc.e.li` instruction uses the `R_RISCV_QC_E_32` relocation and the `InstFormatQC_EAI` instruction format. Vendor relocation support will be added in a later patch.
1 parent 9b8f534 commit 1d2f5ea

File tree

12 files changed

+152
-23
lines changed

12 files changed

+152
-23
lines changed

llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,21 @@ struct RISCVOperand final : public MCParsedAsmOperand {
551551
return IsValid && VK == RISCVMCExpr::VK_None;
552552
}
553553

554+
// True if operand is a symbol with no modifiers, or a constant with no
555+
// modifiers and isInt<N>(Op).
556+
template <int N> bool isBareSimmN() const {
557+
if (!isImm())
558+
return false;
559+
560+
int64_t Imm;
561+
if (evaluateConstantImm(getImm(), Imm))
562+
return isInt<N>(fixImmediateForRV32(Imm, isRV64Imm()));
563+
564+
RISCVMCExpr::Specifier VK = RISCVMCExpr::VK_None;
565+
return RISCVAsmParser::classifySymbolRef(getImm(), VK) &&
566+
VK == RISCVMCExpr::VK_None;
567+
}
568+
554569
// Predicate methods for AsmOperands defined in RISCVInstrInfo.td
555570

556571
bool isBareSymbol() const {
@@ -794,9 +809,7 @@ struct RISCVOperand final : public MCParsedAsmOperand {
794809
bool isSImm6() const { return isSImm<6>(); }
795810
bool isSImm11() const { return isSImm<11>(); }
796811
bool isSImm16() const { return isSImm<16>(); }
797-
bool isSImm20() const { return isSImm<20>(); }
798812
bool isSImm26() const { return isSImm<26>(); }
799-
bool isSImm32() const { return isSImm<32>(); }
800813

801814
bool isSImm5NonZero() const {
802815
return isSImmPred([](int64_t Imm) { return Imm != 0 && isInt<5>(Imm); });
@@ -876,6 +889,19 @@ struct RISCVOperand final : public MCParsedAsmOperand {
876889
return isUImmPred([](int64_t Imm) { return isUInt<16>(Imm) && Imm != 0; });
877890
}
878891

892+
bool isSImm20LI() const {
893+
if (!isImm())
894+
return false;
895+
896+
int64_t Imm;
897+
if (evaluateConstantImm(getImm(), Imm))
898+
return isInt<20>(fixImmediateForRV32(Imm, isRV64Imm()));
899+
900+
RISCVMCExpr::Specifier VK = RISCVMCExpr::VK_None;
901+
return RISCVAsmParser::classifySymbolRef(getImm(), VK) &&
902+
VK == RISCVMCExpr::VK_QC_ABS20;
903+
}
904+
879905
bool isUImm20LUI() const {
880906
if (!isImm())
881907
return false;
@@ -1519,6 +1545,11 @@ bool RISCVAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
15191545
return generateImmOutOfRangeError(
15201546
Operands, ErrorInfo, -(1 << 15), (1 << 15) - 1,
15211547
"immediate must be non-zero in the range");
1548+
case Match_InvalidSImm20LI:
1549+
return generateImmOutOfRangeError(
1550+
Operands, ErrorInfo, -(1 << 19), (1 << 19) - 1,
1551+
"operand must be a symbol with a %qc.abs20 specifier or an integer "
1552+
" in the range");
15221553
case Match_InvalidUImm20LUI:
15231554
return generateImmOutOfRangeError(
15241555
Operands, ErrorInfo, 0, (1 << 20) - 1,
@@ -1555,10 +1586,7 @@ bool RISCVAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
15551586
case Match_InvalidSImm26:
15561587
return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 25),
15571588
(1 << 25) - 1);
1558-
case Match_InvalidSImm20:
1559-
return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 19),
1560-
(1 << 19) - 1);
1561-
case Match_InvalidSImm32:
1589+
case Match_InvalidBareSImm32:
15621590
return generateImmOutOfRangeError(Operands, ErrorInfo,
15631591
std::numeric_limits<int32_t>::min(),
15641592
std::numeric_limits<uint32_t>::max());

llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
9393
{"fixup_riscv_tlsdesc_add_lo12", 20, 12, 0},
9494
{"fixup_riscv_tlsdesc_call", 0, 0, 0},
9595
{"fixup_riscv_qc_e_branch", 0, 48, MCFixupKindInfo::FKF_IsPCRel},
96+
{"fixup_riscv_qc_e_32", 16, 32, 0},
97+
{"fixup_riscv_qc_abs20_u", 12, 20, 0},
9698
};
9799
static_assert((std::size(Infos)) == RISCV::NumTargetFixupKinds,
98100
"Not all fixup kinds added to Infos array");
@@ -559,7 +561,20 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
559561
(Bit5 << 2);
560562
return Value;
561563
}
562-
564+
case RISCV::fixup_riscv_qc_e_32: {
565+
if (!isInt<32>(Value))
566+
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
567+
return ((Value & 0xffffffff) << 16);
568+
}
569+
case RISCV::fixup_riscv_qc_abs20_u: {
570+
if (!isInt<20>(Value))
571+
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
572+
unsigned Bit19 = (Value >> 19) & 0x1;
573+
unsigned Bit14_0 = Value & 0x7fff;
574+
unsigned Bit18_15 = (Value >> 15) & 0xf;
575+
Value = (Bit19 << 31) | (Bit14_0 << 16) | (Bit18_15 << 12);
576+
return Value;
577+
}
563578
}
564579
}
565580

llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,9 +340,9 @@ enum OperandType : unsigned {
340340
OPERAND_SIMM12_LSB00000,
341341
OPERAND_SIMM16,
342342
OPERAND_SIMM16_NONZERO,
343-
OPERAND_SIMM20,
343+
OPERAND_SIMM20_LI,
344344
OPERAND_SIMM26,
345-
OPERAND_SIMM32,
345+
OPERAND_BARE_SIMM32,
346346
OPERAND_CLUI_IMM,
347347
OPERAND_VTYPEI10,
348348
OPERAND_VTYPEI11,

llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,
173173
return ELF::R_RISCV_RELAX;
174174
case RISCV::fixup_riscv_align:
175175
return ELF::R_RISCV_ALIGN;
176+
case RISCV::fixup_riscv_qc_e_32:
177+
return ELF::R_RISCV_QC_E_32;
178+
case RISCV::fixup_riscv_qc_abs20_u:
179+
return ELF::R_RISCV_QC_ABS20_U;
176180
}
177181
}
178182

llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ enum Fixups {
8080
// 12-bit fixup for symbol references in the 48-bit Xqcibi branch immediate
8181
// instructions
8282
fixup_riscv_qc_e_branch,
83+
// 32-bit fixup for symbol references in the 48-bit qc.e.li instruction
84+
fixup_riscv_qc_e_32,
85+
// 20-bit fixup for symbol references in the 32-bit qc.li instruction
86+
fixup_riscv_qc_abs20_u,
8387

8488
// Used as a sentinel, must be the last
8589
fixup_riscv_invalid,

llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,9 @@ uint64_t RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
653653
case RISCVMCExpr::VK_TLSDESC_CALL:
654654
FixupKind = RISCV::fixup_riscv_tlsdesc_call;
655655
break;
656+
case RISCVMCExpr::VK_QC_ABS20:
657+
FixupKind = RISCV::fixup_riscv_qc_abs20_u;
658+
break;
656659
}
657660
} else if (Kind == MCExpr::SymbolRef || Kind == MCExpr::Binary) {
658661
// FIXME: Sub kind binary exprs have chance of underflow.
@@ -668,6 +671,8 @@ uint64_t RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
668671
FixupKind = RISCV::fixup_riscv_12_i;
669672
} else if (MIFrm == RISCVII::InstFormatQC_EB) {
670673
FixupKind = RISCV::fixup_riscv_qc_e_branch;
674+
} else if (MIFrm == RISCVII::InstFormatQC_EAI) {
675+
FixupKind = RISCV::fixup_riscv_qc_e_32;
671676
}
672677
}
673678

llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ RISCVMCExpr::getSpecifierForName(StringRef name) {
116116
.Case("tlsdesc_load_lo", VK_TLSDESC_LOAD_LO)
117117
.Case("tlsdesc_add_lo", VK_TLSDESC_ADD_LO)
118118
.Case("tlsdesc_call", VK_TLSDESC_CALL)
119+
.Case("qc.abs20", VK_QC_ABS20)
119120
// Used in data directives
120121
.Case("pltpcrel", VK_PLTPCREL)
121122
.Case("gotpcrel", VK_GOTPCREL)
@@ -164,6 +165,8 @@ StringRef RISCVMCExpr::getSpecifierName(Specifier S) {
164165
return "gotpcrel";
165166
case VK_PLTPCREL:
166167
return "pltpcrel";
168+
case VK_QC_ABS20:
169+
return "qc.abs20";
167170
}
168171
llvm_unreachable("Invalid ELF symbol kind");
169172
}

llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class RISCVMCExpr : public MCTargetExpr {
4343
VK_TLSDESC_LOAD_LO,
4444
VK_TLSDESC_ADD_LO,
4545
VK_TLSDESC_CALL,
46+
VK_QC_ABS20,
4647
};
4748

4849
private:

llvm/lib/Target/RISCV/RISCVInstrInfo.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2654,9 +2654,7 @@ bool RISCVInstrInfo::verifyInstruction(const MachineInstr &MI,
26542654
CASE_OPERAND_SIMM(6)
26552655
CASE_OPERAND_SIMM(11)
26562656
CASE_OPERAND_SIMM(12)
2657-
CASE_OPERAND_SIMM(20)
26582657
CASE_OPERAND_SIMM(26)
2659-
CASE_OPERAND_SIMM(32)
26602658
// clang-format on
26612659
case RISCVOp::OPERAND_SIMM5_PLUS1:
26622660
Ok = (isInt<5>(Imm) && Imm != -16) || Imm == 16;
@@ -2673,6 +2671,12 @@ bool RISCVInstrInfo::verifyInstruction(const MachineInstr &MI,
26732671
case RISCVOp::OPERAND_SIMM12_LSB00000:
26742672
Ok = isShiftedInt<7, 5>(Imm);
26752673
break;
2674+
case RISCVOp::OPERAND_SIMM20_LI:
2675+
Ok = isInt<20>(Imm);
2676+
break;
2677+
case RISCVOp::OPERAND_BARE_SIMM32:
2678+
Ok = isInt<32>(Imm);
2679+
break;
26762680
case RISCVOp::OPERAND_UIMMLOG2XLEN:
26772681
Ok = STI.is64Bit() ? isUInt<6>(Imm) : isUInt<5>(Imm);
26782682
break;

llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -103,22 +103,38 @@ def simm16nonzero : RISCVOp<XLenVT>,
103103
let OperandType = "OPERAND_SIMM16_NONZERO";
104104
}
105105

106-
def simm20 : RISCVSImmLeafOp<20>;
106+
def simm20_li : RISCVOp<XLenVT> {
107+
let ParserMatchClass = SImmAsmOperand<20, "LI">;
108+
let EncoderMethod = "getImmOpValue";
109+
let DecoderMethod = "decodeSImmOperand<20>";
110+
let OperandType = "OPERAND_SIMM20_LI";
111+
let MCOperandPredicate = [{
112+
int64_t Imm;
113+
if (MCOp.evaluateAsConstantImm(Imm))
114+
return isInt<20>(Imm);
115+
return MCOp.isBareSymbolRef();
116+
}];
117+
}
107118

108119
def simm26 : RISCVSImmLeafOp<26>;
109120

121+
class BareSImmNAsmOperand<int width>
122+
: ImmAsmOperand<"BareS", width, ""> {
123+
let PredicateMethod = "isBareSimmN<" # width # ">";
124+
}
125+
110126
// 32-bit Immediate, used by RV32 Instructions in 32-bit operations, so no
111127
// sign-/zero-extension. This is represented internally as a signed 32-bit value.
112-
def simm32 : RISCVOp<XLenVT> {
113-
let ParserMatchClass = SImmAsmOperand<32, "">;
128+
def bare_simm32 : RISCVOp<XLenVT> {
129+
let ParserMatchClass = BareSImmNAsmOperand<32>;
114130
let EncoderMethod = "getImmOpValue";
115131
let DecoderMethod = "decodeSImmOperand<32>";
116-
let OperandType = "OPERAND_SIMM32";
132+
let OperandType = "OPERAND_BARE_SIMM32";
117133
let MCOperandPredicate = [{
118134
int64_t Imm;
119135
if (MCOp.evaluateAsConstantImm(Imm))
120136
return isInt<32>(Imm);
121-
return false;
137+
return MCOp.isBareSymbolRef();
122138
}];
123139
}
124140

@@ -256,7 +272,7 @@ def InsnQC_EAI : DirectiveInsnQC_EAI<(outs AnyReg:$rd),
256272
(ins uimm7_opcode:$opcode,
257273
uimm3:$func3,
258274
uimm1:$func1,
259-
simm32:$imm32),
275+
bare_simm32:$imm32),
260276
"$opcode, $func3, $func1, $rd, $imm32">;
261277
def InsnQC_EI : DirectiveInsnQC_EI<(outs AnyReg:$rd),
262278
(ins uimm7_opcode:$opcode,
@@ -303,7 +319,7 @@ def : InstAlias<".insn_qc.eai $opcode, $func3, $func1, $rd, $imm32",
303319
uimm7_opcode:$opcode,
304320
uimm3:$func3,
305321
uimm1:$func1,
306-
simm32:$imm32)>;
322+
bare_simm32:$imm32)>;
307323
def : InstAlias<".insn_qc.ei $opcode, $func3, $func2, $rd, $rs1, $imm26",
308324
(InsnQC_EI AnyReg:$rd,
309325
uimm7_opcode:$opcode,
@@ -671,7 +687,7 @@ class QCIRVInstESStore<bits<3> funct3, bits<2> funct2, string opcodestr>
671687
opcodestr, "$rs2, ${imm}(${rs1})">;
672688

673689
class QCIRVInstEAI<bits<3> funct3, bits<1> funct1, string opcodestr>
674-
: RVInst48<(outs GPRNoX0:$rd_wb), (ins GPRNoX0:$rd, simm32:$imm),
690+
: RVInst48<(outs GPRNoX0:$rd_wb), (ins GPRNoX0:$rd, bare_simm32:$imm),
675691
opcodestr, "$rd, $imm", [], InstFormatOther> {
676692
bits<5> rd;
677693
bits<32> imm;
@@ -1009,15 +1025,15 @@ let Predicates = [HasVendorXqcilb, IsRV32] in {
10091025

10101026
let Predicates = [HasVendorXqcili, IsRV32] in {
10111027
let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
1012-
def QC_LI : RVInstU<OPC_OP_IMM_32, (outs GPRNoX0:$rd), (ins simm20:$imm20),
1028+
def QC_LI : RVInstU<OPC_OP_IMM_32, (outs GPRNoX0:$rd), (ins simm20_li:$imm20),
10131029
"qc.li", "$rd, $imm20"> {
10141030
let Inst{31} = imm20{19};
10151031
let Inst{30-16} = imm20{14-0};
10161032
let Inst{15-12} = imm20{18-15};
10171033
}
10181034

1019-
def QC_E_LI : RVInst48<(outs GPRNoX0:$rd), (ins simm32:$imm),
1020-
"qc.e.li", "$rd, $imm", [], InstFormatOther> {
1035+
def QC_E_LI : RVInst48<(outs GPRNoX0:$rd), (ins bare_simm32:$imm),
1036+
"qc.e.li", "$rd, $imm", [], InstFormatQC_EAI> {
10211037
bits<5> rd;
10221038
bits<32> imm;
10231039

0 commit comments

Comments
 (0)