Skip to content

Commit eccd7aa

Browse files
authored
[RISCV] Add symbol parsing support for Xqcilb long branch instructions (#135044)
This patch adds support for parsing symbols in the Xqcilb long branch instructions. The instructions use the `R_RISCV_QC_E_JUMP_PLT` relocation and the `InstFormatQC_EJ` instruction format. Vendor relocation support will be added in a later patch.
1 parent 3b70715 commit eccd7aa

File tree

10 files changed

+186
-2
lines changed

10 files changed

+186
-2
lines changed

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ class RISCVAsmParser : public MCTargetAsmParser {
202202
ParseStatus parseOperandWithSpecifier(OperandVector &Operands);
203203
ParseStatus parseBareSymbol(OperandVector &Operands);
204204
ParseStatus parseCallSymbol(OperandVector &Operands);
205+
ParseStatus parsePseudoQCJumpSymbol(OperandVector &Operands);
205206
ParseStatus parsePseudoJumpSymbol(OperandVector &Operands);
206207
ParseStatus parseJALOffset(OperandVector &Operands);
207208
ParseStatus parseVTypeI(OperandVector &Operands);
@@ -590,6 +591,17 @@ struct RISCVOperand final : public MCParsedAsmOperand {
590591
(VK == RISCVMCExpr::VK_CALL || VK == RISCVMCExpr::VK_CALL_PLT);
591592
}
592593

594+
bool isPseudoQCJumpSymbol() const {
595+
int64_t Imm;
596+
// Must be of 'immediate' type but not a constant.
597+
if (!isImm() || evaluateConstantImm(getImm(), Imm))
598+
return false;
599+
600+
RISCVMCExpr::Specifier VK = RISCVMCExpr::VK_None;
601+
return RISCVAsmParser::classifySymbolRef(getImm(), VK) &&
602+
VK == RISCVMCExpr::VK_QC_E_JUMP_PLT;
603+
}
604+
593605
bool isPseudoJumpSymbol() const {
594606
int64_t Imm;
595607
// Must be of 'immediate' type but not a constant.
@@ -2136,6 +2148,38 @@ ParseStatus RISCVAsmParser::parseCallSymbol(OperandVector &Operands) {
21362148
return ParseStatus::Success;
21372149
}
21382150

2151+
ParseStatus RISCVAsmParser::parsePseudoQCJumpSymbol(OperandVector &Operands) {
2152+
SMLoc S = getLoc();
2153+
const MCExpr *Res;
2154+
2155+
if (getLexer().getKind() != AsmToken::Identifier)
2156+
return ParseStatus::NoMatch;
2157+
2158+
std::string Identifier(getTok().getIdentifier());
2159+
SMLoc E = getTok().getEndLoc();
2160+
2161+
if (getLexer().peekTok().is(AsmToken::At)) {
2162+
Lex();
2163+
Lex();
2164+
SMLoc PLTLoc = getLoc();
2165+
StringRef PLT;
2166+
E = getTok().getEndLoc();
2167+
if (getParser().parseIdentifier(PLT) || PLT != "plt")
2168+
return Error(PLTLoc,
2169+
"'@plt' is the only valid operand for this instruction");
2170+
} else {
2171+
Lex();
2172+
}
2173+
2174+
RISCVMCExpr::Specifier Kind = RISCVMCExpr::VK_QC_E_JUMP_PLT;
2175+
2176+
MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
2177+
Res = MCSymbolRefExpr::create(Sym, getContext());
2178+
Res = RISCVMCExpr::create(Res, Kind, getContext());
2179+
Operands.push_back(RISCVOperand::createImm(Res, S, E, isRV64()));
2180+
return ParseStatus::Success;
2181+
}
2182+
21392183
ParseStatus RISCVAsmParser::parsePseudoJumpSymbol(OperandVector &Operands) {
21402184
SMLoc S = getLoc();
21412185
SMLoc E;

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
9595
{"fixup_riscv_qc_e_branch", 0, 48, MCFixupKindInfo::FKF_IsPCRel},
9696
{"fixup_riscv_qc_e_32", 16, 32, 0},
9797
{"fixup_riscv_qc_abs20_u", 12, 20, 0},
98+
{"fixup_riscv_qc_e_jump_plt", 0, 48, MCFixupKindInfo::FKF_IsPCRel},
9899
};
99100
static_assert((std::size(Infos)) == RISCV::NumTargetFixupKinds,
100101
"Not all fixup kinds added to Infos array");
@@ -575,6 +576,21 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
575576
Value = (Bit19 << 31) | (Bit14_0 << 16) | (Bit18_15 << 12);
576577
return Value;
577578
}
579+
case RISCV::fixup_riscv_qc_e_jump_plt: {
580+
if (!isInt<32>(Value))
581+
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
582+
if (Value & 0x1)
583+
Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned");
584+
uint64_t Bit31_16 = (Value >> 16) & 0xffff;
585+
uint64_t Bit12 = (Value >> 12) & 0x1;
586+
uint64_t Bit10_5 = (Value >> 5) & 0x3f;
587+
uint64_t Bit15_13 = (Value >> 13) & 0x7;
588+
uint64_t Bit4_1 = (Value >> 1) & 0xf;
589+
uint64_t Bit11 = (Value >> 11) & 0x1;
590+
Value = (Bit31_16 << 32ull) | (Bit12 << 31) | (Bit10_5 << 25) |
591+
(Bit15_13 << 17) | (Bit4_1 << 8) | (Bit11 << 7);
592+
return Value;
593+
}
578594
}
579595
}
580596

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,
119119
return ELF::R_RISCV_CALL_PLT;
120120
case RISCV::fixup_riscv_qc_e_branch:
121121
return ELF::R_RISCV_QC_E_BRANCH;
122+
case RISCV::fixup_riscv_qc_e_jump_plt:
123+
return ELF::R_RISCV_QC_E_JUMP_PLT;
122124
}
123125
}
124126

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ enum Fixups {
8484
fixup_riscv_qc_e_32,
8585
// 20-bit fixup for symbol references in the 32-bit qc.li instruction
8686
fixup_riscv_qc_abs20_u,
87+
// 32-bit fixup for symbol references in the 48-bit qc.j/qc.jal instructions
88+
fixup_riscv_qc_e_jump_plt,
8789

8890
// Used as a sentinel, must be the last
8991
fixup_riscv_invalid,

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ class RISCVMCCodeEmitter : public MCCodeEmitter {
5656
SmallVectorImpl<MCFixup> &Fixups,
5757
const MCSubtargetInfo &STI) const;
5858

59+
void expandQCJump(const MCInst &MI, SmallVectorImpl<char> &CB,
60+
SmallVectorImpl<MCFixup> &Fixups,
61+
const MCSubtargetInfo &STI) const;
62+
5963
void expandTLSDESCCall(const MCInst &MI, SmallVectorImpl<char> &CB,
6064
SmallVectorImpl<MCFixup> &Fixups,
6165
const MCSubtargetInfo &STI) const;
@@ -169,6 +173,26 @@ void RISCVMCCodeEmitter::expandFunctionCall(const MCInst &MI,
169173
support::endian::write(CB, Binary, llvm::endianness::little);
170174
}
171175

176+
void RISCVMCCodeEmitter::expandQCJump(const MCInst &MI,
177+
SmallVectorImpl<char> &CB,
178+
SmallVectorImpl<MCFixup> &Fixups,
179+
const MCSubtargetInfo &STI) const {
180+
MCOperand Func = MI.getOperand(0);
181+
assert(Func.isExpr() && "Expected expression");
182+
183+
auto Opcode =
184+
(MI.getOpcode() == RISCV::PseudoQC_E_J) ? RISCV::QC_E_J : RISCV::QC_E_JAL;
185+
MCInst Jump = MCInstBuilder(Opcode).addExpr(Func.getExpr());
186+
187+
uint64_t Bits = getBinaryCodeForInstr(Jump, Fixups, STI) & 0xffff'ffff'ffffu;
188+
SmallVector<char, 8> Encoding;
189+
support::endian::write(Encoding, Bits, llvm::endianness::little);
190+
assert(Encoding[6] == 0 && Encoding[7] == 0 &&
191+
"Unexpected encoding for 48-bit instruction");
192+
Encoding.truncate(6);
193+
CB.append(Encoding);
194+
}
195+
172196
void RISCVMCCodeEmitter::expandTLSDESCCall(const MCInst &MI,
173197
SmallVectorImpl<char> &CB,
174198
SmallVectorImpl<MCFixup> &Fixups,
@@ -440,6 +464,11 @@ void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI,
440464
expandTLSDESCCall(MI, CB, Fixups, STI);
441465
MCNumEmitted += 1;
442466
return;
467+
case RISCV::PseudoQC_E_J:
468+
case RISCV::PseudoQC_E_JAL:
469+
expandQCJump(MI, CB, Fixups, STI);
470+
MCNumEmitted += 1;
471+
return;
443472
}
444473

445474
switch (Size) {
@@ -656,6 +685,9 @@ uint64_t RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
656685
case RISCVMCExpr::VK_QC_ABS20:
657686
FixupKind = RISCV::fixup_riscv_qc_abs20_u;
658687
break;
688+
case RISCVMCExpr::VK_QC_E_JUMP_PLT:
689+
FixupKind = RISCV::fixup_riscv_qc_e_jump_plt;
690+
break;
659691
}
660692
} else if (Kind == MCExpr::SymbolRef || Kind == MCExpr::Binary) {
661693
// FIXME: Sub kind binary exprs have chance of underflow.

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ const RISCVMCExpr *RISCVMCExpr::create(const MCExpr *Expr, Specifier S,
3434

3535
void RISCVMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
3636
Specifier S = getSpecifier();
37-
bool HasVariant = ((S != VK_None) && (S != VK_CALL) && (S != VK_CALL_PLT));
37+
bool HasVariant = ((S != VK_None) && (S != VK_CALL) && (S != VK_CALL_PLT) &&
38+
(S != VK_QC_E_JUMP_PLT));
3839

3940
if (HasVariant)
4041
OS << '%' << getSpecifierName(S) << '(';
@@ -167,6 +168,8 @@ StringRef RISCVMCExpr::getSpecifierName(Specifier S) {
167168
return "pltpcrel";
168169
case VK_QC_ABS20:
169170
return "qc.abs20";
171+
case VK_QC_E_JUMP_PLT:
172+
return "qc_e_jump_plt";
170173
}
171174
llvm_unreachable("Invalid ELF symbol kind");
172175
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class RISCVMCExpr : public MCTargetExpr {
4444
VK_TLSDESC_ADD_LO,
4545
VK_TLSDESC_CALL,
4646
VK_QC_ABS20,
47+
VK_QC_E_JUMP_PLT
4748
};
4849

4950
private:

llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,18 @@ def simm32_lsb0 : Operand<OtherVT> {
153153
let OperandType = "OPERAND_PCREL";
154154
}
155155

156+
def PseudoQCJumpSymbol : AsmOperandClass {
157+
let Name = "PseudoQCJumpSymbol";
158+
let RenderMethod = "addImmOperands";
159+
let DiagnosticType = "InvalidPseudoQCJumpSymbol";
160+
let DiagnosticString = "operand must be a valid jump target";
161+
let ParserMethod = "parsePseudoQCJumpSymbol";
162+
}
163+
164+
def pseudo_qc_jump_symbol : Operand<XLenVT> {
165+
let ParserMatchClass = PseudoQCJumpSymbol;
166+
}
167+
156168
//===----------------------------------------------------------------------===//
157169
// Instruction Formats
158170
//===----------------------------------------------------------------------===//
@@ -708,7 +720,7 @@ class QCIRVInstEI<bits<3> funct3, bits<2> funct2, string opcodestr>
708720
let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
709721
class QCIRVInst48EJ<bits<2> func2, string opcodestr>
710722
: RVInst48<(outs), (ins simm32_lsb0:$imm31),
711-
opcodestr, "$imm31", [], InstFormatOther> {
723+
opcodestr, "$imm31", [], InstFormatQC_EJ> {
712724
bits<31> imm31;
713725

714726
let Inst{47-32} = imm31{30-15};
@@ -1219,6 +1231,16 @@ def PseudoQC_E_SH : PseudoStore<"qc.e.sh">;
12191231
def PseudoQC_E_SW : PseudoStore<"qc.e.sw">;
12201232
} // Predicates = [HasVendorXqcilo, IsRV32]
12211233

1234+
let isCall = 0, isBarrier = 1, isTerminator = 1,
1235+
isCodeGenOnly = 0, hasSideEffects = 0, mayStore = 0, mayLoad = 0 in
1236+
def PseudoQC_E_J : Pseudo<(outs), (ins pseudo_qc_jump_symbol:$func), [],
1237+
"qc.e.j", "$func">;
1238+
1239+
let isCall = 1, Defs = [X1], isCodeGenOnly = 0, hasSideEffects = 0,
1240+
mayStore = 0, mayLoad = 0 in
1241+
def PseudoQC_E_JAL: Pseudo<(outs), (ins pseudo_qc_jump_symbol:$func), [],
1242+
"qc.e.jal", "$func">;
1243+
12221244
//===----------------------------------------------------------------------===//
12231245
// Code Gen Patterns
12241246
//===----------------------------------------------------------------------===//

llvm/test/MC/RISCV/xqcilb-invalid.s

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@ qc.e.jal 2147483649
2222

2323
# CHECK-MINUS: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcilb' (Qualcomm uC Long Branch Extension)
2424
qc.e.jal 2147483640
25+
26+
# CHECK: :[[@LINE+1]]:12: error: '@plt' is the only valid operand for this instruction
27+
qc.e.j foo@rlt
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcilb %s -show-encoding \
2+
# RUN: | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s
3+
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqcilb %s -o %t.o
4+
# RUN: llvm-readobj -r %t.o | FileCheck -check-prefix=RELOC %s
5+
6+
# Check prefixes:
7+
# RELOC - Check the relocation in the object.
8+
# FIXUP - Check the fixup on the instruction.
9+
# INSTR - Check the instruction is handled properly by the ASMPrinter.
10+
11+
.text
12+
13+
qc.e.j foo
14+
# RELOC: R_RISCV_CUSTOM195 foo 0x0
15+
# INSTR: qc.e.j foo
16+
# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_qc_e_jump_plt
17+
18+
qc.e.j foo@plt
19+
# RELOC: R_RISCV_CUSTOM195 foo 0x0
20+
# INSTR: qc.e.j foo
21+
# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_qc_e_jump_plt
22+
23+
qc.e.jal foo@plt
24+
# RELOC: R_RISCV_CUSTOM195 foo 0x0
25+
# INSTR: qc.e.jal foo
26+
# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_qc_e_jump_plt
27+
28+
qc.e.jal foo
29+
# RELOC: R_RISCV_CUSTOM195 foo 0x0
30+
# INSTR: qc.e.jal foo
31+
# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_qc_e_jump_plt
32+
33+
# Check that a label in a different section is handled similar to an undefined symbol
34+
qc.e.j .bar
35+
# RELOC: R_RISCV_CUSTOM195 .bar 0x0
36+
# INSTR: qc.e.j .bar
37+
# FIXUP: fixup A - offset: 0, value: .bar, kind: fixup_riscv_qc_e_jump_plt
38+
39+
qc.e.jal .bar
40+
# RELOC: R_RISCV_CUSTOM195 .bar 0x0
41+
# INSTR: qc.e.jal .bar
42+
# FIXUP: fixup A - offset: 0, value: .bar, kind: fixup_riscv_qc_e_jump_plt
43+
44+
# Check that jumps to a defined symbol are handled correctly
45+
qc.e.j .L1
46+
# INSTR:qc.e.j .L1
47+
# FIXUP: fixup A - offset: 0, value: .L1, kind: fixup_riscv_qc_e_jump_plt
48+
49+
qc.e.jal .L1
50+
# INSTR:qc.e.jal .L1
51+
# FIXUP: fixup A - offset: 0, value: .L1, kind: fixup_riscv_qc_e_jump_plt
52+
53+
.L1:
54+
ret
55+
56+
.section .t2
57+
58+
.bar:
59+
ret

0 commit comments

Comments
 (0)