Skip to content

Commit 8e0b205

Browse files
committed
[RISCV] Add "lla" pseudo-instruction to assembler
This pseudo-instruction is similar to la but uses PC-relative addressing unconditionally. This is, la is only different to lla when using -fPIC. This pseudo-instruction seems often forgotten in several specs but it is definitely mentioned in binutils opcodes/riscv-opc.c. The semantics are defined both in page 37 of the "RISC-V Reader" book but also in function macro found in gas/config/tc-riscv.c. This is a very first step towards adding PIC support for Linux in the RISC-V backend. The lla pseudo-instruction expands to a sequence of auipc + addi with a couple of pc-rel relocations where the second points to the first one. This is described in https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#pc-relative-symbol-addresses For now, this patch only introduces support of that pseudo instruction at the assembler parser. Differential Revision: https://reviews.llvm.org/D49661 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@339314 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent dad5e8a commit 8e0b205

File tree

4 files changed

+103
-3
lines changed

4 files changed

+103
-3
lines changed

lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ class RISCVAsmParser : public MCTargetAsmParser {
7373
// synthesize the desired immedate value into the destination register.
7474
void emitLoadImm(unsigned DestReg, int64_t Value, MCStreamer &Out);
7575

76+
// Helper to emit pseudo instruction "lla" used in PC-rel addressing.
77+
void emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
78+
7679
/// Helper for processing MC instructions that have been successfully matched
7780
/// by MatchAndEmitInstruction. Modifications to the emitted instructions,
7881
/// like the expansion of pseudo instructions (e.g., "li"), can be performed
@@ -964,6 +967,26 @@ bool RISCVAsmParser::parseOperand(OperandVector &Operands,
964967
return true;
965968
}
966969

970+
/// Return true if the operand at the OperandIdx for opcode Name should be
971+
/// 'forced' to be parsed as an immediate. This is required for
972+
/// pseudoinstructions such as tail or call, which allow bare symbols to be used
973+
/// that could clash with register names.
974+
static bool shouldForceImediateOperand(StringRef Name, unsigned OperandIdx) {
975+
// FIXME: This may not scale so perhaps we want to use a data-driven approach
976+
// instead.
977+
switch (OperandIdx) {
978+
case 0:
979+
// call imm
980+
// tail imm
981+
return Name == "tail" || Name == "call";
982+
case 1:
983+
// lla rdest, imm
984+
return Name == "lla";
985+
default:
986+
return false;
987+
}
988+
}
989+
967990
bool RISCVAsmParser::ParseInstruction(ParseInstructionInfo &Info,
968991
StringRef Name, SMLoc NameLoc,
969992
OperandVector &Operands) {
@@ -975,18 +998,20 @@ bool RISCVAsmParser::ParseInstruction(ParseInstructionInfo &Info,
975998
return false;
976999

9771000
// Parse first operand
978-
bool ForceImmediate = (Name == "call" || Name == "tail");
979-
if (parseOperand(Operands, ForceImmediate))
1001+
if (parseOperand(Operands, shouldForceImediateOperand(Name, 0)))
9801002
return true;
9811003

9821004
// Parse until end of statement, consuming commas between operands
1005+
unsigned OperandIdx = 1;
9831006
while (getLexer().is(AsmToken::Comma)) {
9841007
// Consume comma token
9851008
getLexer().Lex();
9861009

9871010
// Parse next operand
988-
if (parseOperand(Operands, false))
1011+
if (parseOperand(Operands, shouldForceImediateOperand(Name, OperandIdx)))
9891012
return true;
1013+
1014+
++OperandIdx;
9901015
}
9911016

9921017
if (getLexer().isNot(AsmToken::EndOfStatement)) {
@@ -1184,6 +1209,39 @@ void RISCVAsmParser::emitLoadImm(unsigned DestReg, int64_t Value,
11841209
.addImm(Lo12));
11851210
}
11861211

1212+
void RISCVAsmParser::emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc,
1213+
MCStreamer &Out) {
1214+
// The local load address pseudo-instruction "lla" is used in PC-relative
1215+
// addressing of symbols:
1216+
// lla rdest, symbol
1217+
// expands to
1218+
// TmpLabel: AUIPC rdest, %pcrel_hi(symbol)
1219+
// ADDI rdest, %pcrel_lo(TmpLabel)
1220+
MCContext &Ctx = getContext();
1221+
1222+
MCSymbol *TmpLabel = Ctx.createTempSymbol(
1223+
"pcrel_hi", /* AlwaysAddSuffix */ true, /* CanBeUnnamed */ false);
1224+
Out.EmitLabel(TmpLabel);
1225+
1226+
MCOperand DestReg = Inst.getOperand(0);
1227+
const RISCVMCExpr *Symbol = RISCVMCExpr::create(
1228+
Inst.getOperand(1).getExpr(), RISCVMCExpr::VK_RISCV_PCREL_HI, Ctx);
1229+
1230+
MCInst &AUIPC =
1231+
MCInstBuilder(RISCV::AUIPC).addOperand(DestReg).addExpr(Symbol);
1232+
emitToStreamer(Out, AUIPC);
1233+
1234+
const MCExpr *RefToLinkTmpLabel =
1235+
RISCVMCExpr::create(MCSymbolRefExpr::create(TmpLabel, Ctx),
1236+
RISCVMCExpr::VK_RISCV_PCREL_LO, Ctx);
1237+
1238+
MCInst &ADDI = MCInstBuilder(RISCV::ADDI)
1239+
.addOperand(DestReg)
1240+
.addOperand(DestReg)
1241+
.addExpr(RefToLinkTmpLabel);
1242+
emitToStreamer(Out, ADDI);
1243+
}
1244+
11871245
bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
11881246
MCStreamer &Out) {
11891247
Inst.setLoc(IDLoc);
@@ -1198,6 +1256,9 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
11981256
Imm = SignExtend64<32>(Imm);
11991257
emitLoadImm(Reg, Imm, Out);
12001258
return false;
1259+
} else if (Inst.getOpcode() == RISCV::PseudoLLA) {
1260+
emitLoadLocalAddress(Inst, IDLoc, Out);
1261+
return false;
12011262
}
12021263

12031264
emitToStreamer(Out, Inst);

lib/Target/RISCV/RISCVInstrInfo.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,11 @@ def : Pat<(Tail (iPTR tglobaladdr:$dst)),
759759
def : Pat<(Tail (iPTR texternalsym:$dst)),
760760
(PseudoTAIL texternalsym:$dst)>;
761761

762+
let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 0,
763+
isAsmParserOnly = 1 in
764+
def PseudoLLA : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
765+
"lla", "$dst, $src">;
766+
762767
/// Loads
763768

764769
multiclass LdPat<PatFrag LoadOp, RVInst Inst> {

test/MC/RISCV/lla-invalid.s

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# RUN: not llvm-mc -triple=riscv32 < %s 2>&1 | FileCheck %s
2+
# RUN: not llvm-mc -triple=riscv64 < %s 2>&1 | FileCheck %s
3+
4+
# Non bare symbols must be rejected
5+
lla a2, %lo(a_symbol) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
6+
lla a2, %hi(a_symbol) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name

test/MC/RISCV/rvi-pseudos.s

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# RUN: llvm-mc %s -triple=riscv32 | FileCheck %s
2+
# RUN: llvm-mc %s -triple=riscv64 | FileCheck %s
3+
4+
# CHECK: .Lpcrel_hi0:
5+
# CHECK: auipc a0, %pcrel_hi(a_symbol)
6+
# CHECK: addi a0, a0, %pcrel_lo(.Lpcrel_hi0)
7+
lla a0, a_symbol
8+
9+
# CHECK: .Lpcrel_hi1:
10+
# CHECK: auipc a1, %pcrel_hi(another_symbol)
11+
# CHECK: addi a1, a1, %pcrel_lo(.Lpcrel_hi1)
12+
lla a1, another_symbol
13+
14+
# Check that we can load the address of symbols that are spelled like a register
15+
# CHECK: .Lpcrel_hi2:
16+
# CHECK: auipc a2, %pcrel_hi(zero)
17+
# CHECK: addi a2, a2, %pcrel_lo(.Lpcrel_hi2)
18+
lla a2, zero
19+
20+
# CHECK: .Lpcrel_hi3:
21+
# CHECK: auipc a3, %pcrel_hi(ra)
22+
# CHECK: addi a3, a3, %pcrel_lo(.Lpcrel_hi3)
23+
lla a3, ra
24+
25+
# CHECK: .Lpcrel_hi4:
26+
# CHECK: auipc a4, %pcrel_hi(f1)
27+
# CHECK: addi a4, a4, %pcrel_lo(.Lpcrel_hi4)
28+
lla a4, f1

0 commit comments

Comments
 (0)