Skip to content

Commit ff06710

Browse files
asbDisasm
authored andcommitted
[RISCV] Add assembler support for LA pseudo-instruction
This patch also introduces the emitAuipcInstPair helper, which is then used for both emitLoadAddress and emitLoadLocalAddress. Differential Revision: https://reviews.llvm.org/D55325 Patch by James Clarke. llvm-svn: 354111
1 parent 8f7bc42 commit ff06710

File tree

4 files changed

+145
-20
lines changed

4 files changed

+145
-20
lines changed

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

Lines changed: 71 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "llvm/MC/MCExpr.h"
2222
#include "llvm/MC/MCInst.h"
2323
#include "llvm/MC/MCInstBuilder.h"
24+
#include "llvm/MC/MCObjectFileInfo.h"
2425
#include "llvm/MC/MCParser/MCAsmLexer.h"
2526
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
2627
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
@@ -79,9 +80,18 @@ class RISCVAsmParser : public MCTargetAsmParser {
7980
// synthesize the desired immedate value into the destination register.
8081
void emitLoadImm(unsigned DestReg, int64_t Value, MCStreamer &Out);
8182

83+
// Helper to emit a combination of AUIPC and SecondOpcode. Used to implement
84+
// helpers such as emitLoadLocalAddress and emitLoadAddress.
85+
void emitAuipcInstPair(MCOperand DestReg, MCOperand TmpReg,
86+
const MCExpr *Symbol, RISCVMCExpr::VariantKind VKHi,
87+
unsigned SecondOpcode, SMLoc IDLoc, MCStreamer &Out);
88+
8289
// Helper to emit pseudo instruction "lla" used in PC-rel addressing.
8390
void emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
8491

92+
// Helper to emit pseudo instruction "la" used in GOT/PC-rel addressing.
93+
void emitLoadAddress(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
94+
8595
/// Helper for processing MC instructions that have been successfully matched
8696
/// by MatchAndEmitInstruction. Modifications to the emitted instructions,
8797
/// like the expansion of pseudo instructions (e.g., "li"), can be performed
@@ -1410,42 +1420,82 @@ void RISCVAsmParser::emitLoadImm(unsigned DestReg, int64_t Value,
14101420
}
14111421
}
14121422

1413-
void RISCVAsmParser::emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc,
1414-
MCStreamer &Out) {
1415-
// The local load address pseudo-instruction "lla" is used in PC-relative
1416-
// addressing of symbols:
1417-
// lla rdest, symbol
1418-
// expands to
1419-
// TmpLabel: AUIPC rdest, %pcrel_hi(symbol)
1420-
// ADDI rdest, %pcrel_lo(TmpLabel)
1423+
void RISCVAsmParser::emitAuipcInstPair(MCOperand DestReg, MCOperand TmpReg,
1424+
const MCExpr *Symbol,
1425+
RISCVMCExpr::VariantKind VKHi,
1426+
unsigned SecondOpcode, SMLoc IDLoc,
1427+
MCStreamer &Out) {
1428+
// A pair of instructions for PC-relative addressing; expands to
1429+
// TmpLabel: AUIPC TmpReg, VKHi(symbol)
1430+
// OP DestReg, TmpReg, %pcrel_lo(TmpLabel)
14211431
MCContext &Ctx = getContext();
14221432

14231433
MCSymbol *TmpLabel = Ctx.createTempSymbol(
14241434
"pcrel_hi", /* AlwaysAddSuffix */ true, /* CanBeUnnamed */ false);
14251435
Out.EmitLabel(TmpLabel);
14261436

1427-
MCOperand DestReg = Inst.getOperand(0);
1428-
const RISCVMCExpr *Symbol = RISCVMCExpr::create(
1429-
Inst.getOperand(1).getExpr(), RISCVMCExpr::VK_RISCV_PCREL_HI, Ctx);
1430-
1437+
const RISCVMCExpr *SymbolHi = RISCVMCExpr::create(Symbol, VKHi, Ctx);
14311438
emitToStreamer(
1432-
Out, MCInstBuilder(RISCV::AUIPC).addOperand(DestReg).addExpr(Symbol));
1439+
Out, MCInstBuilder(RISCV::AUIPC).addOperand(TmpReg).addExpr(SymbolHi));
14331440

14341441
const MCExpr *RefToLinkTmpLabel =
14351442
RISCVMCExpr::create(MCSymbolRefExpr::create(TmpLabel, Ctx),
14361443
RISCVMCExpr::VK_RISCV_PCREL_LO, Ctx);
14371444

1438-
emitToStreamer(Out, MCInstBuilder(RISCV::ADDI)
1439-
.addOperand(DestReg)
1445+
emitToStreamer(Out, MCInstBuilder(SecondOpcode)
14401446
.addOperand(DestReg)
1447+
.addOperand(TmpReg)
14411448
.addExpr(RefToLinkTmpLabel));
14421449
}
14431450

1451+
void RISCVAsmParser::emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc,
1452+
MCStreamer &Out) {
1453+
// The load local address pseudo-instruction "lla" is used in PC-relative
1454+
// addressing of local symbols:
1455+
// lla rdest, symbol
1456+
// expands to
1457+
// TmpLabel: AUIPC rdest, %pcrel_hi(symbol)
1458+
// ADDI rdest, rdest, %pcrel_lo(TmpLabel)
1459+
MCOperand DestReg = Inst.getOperand(0);
1460+
const MCExpr *Symbol = Inst.getOperand(1).getExpr();
1461+
emitAuipcInstPair(DestReg, DestReg, Symbol, RISCVMCExpr::VK_RISCV_PCREL_HI,
1462+
RISCV::ADDI, IDLoc, Out);
1463+
}
1464+
1465+
void RISCVAsmParser::emitLoadAddress(MCInst &Inst, SMLoc IDLoc,
1466+
MCStreamer &Out) {
1467+
// The load address pseudo-instruction "la" is used in PC-relative and
1468+
// GOT-indirect addressing of global symbols:
1469+
// la rdest, symbol
1470+
// expands to either (for non-PIC)
1471+
// TmpLabel: AUIPC rdest, %pcrel_hi(symbol)
1472+
// ADDI rdest, rdest, %pcrel_lo(TmpLabel)
1473+
// or (for PIC)
1474+
// TmpLabel: AUIPC rdest, %got_pcrel_hi(symbol)
1475+
// Lx rdest, %pcrel_lo(TmpLabel)(rdest)
1476+
MCOperand DestReg = Inst.getOperand(0);
1477+
const MCExpr *Symbol = Inst.getOperand(1).getExpr();
1478+
unsigned SecondOpcode;
1479+
RISCVMCExpr::VariantKind VKHi;
1480+
// FIXME: Should check .option (no)pic when implemented
1481+
if (getContext().getObjectFileInfo()->isPositionIndependent()) {
1482+
SecondOpcode = isRV64() ? RISCV::LD : RISCV::LW;
1483+
VKHi = RISCVMCExpr::VK_RISCV_GOT_HI;
1484+
} else {
1485+
SecondOpcode = RISCV::ADDI;
1486+
VKHi = RISCVMCExpr::VK_RISCV_PCREL_HI;
1487+
}
1488+
emitAuipcInstPair(DestReg, DestReg, Symbol, VKHi, SecondOpcode, IDLoc, Out);
1489+
}
1490+
14441491
bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
14451492
MCStreamer &Out) {
14461493
Inst.setLoc(IDLoc);
14471494

1448-
if (Inst.getOpcode() == RISCV::PseudoLI) {
1495+
switch (Inst.getOpcode()) {
1496+
default:
1497+
break;
1498+
case RISCV::PseudoLI: {
14491499
unsigned Reg = Inst.getOperand(0).getReg();
14501500
const MCOperand &Op1 = Inst.getOperand(1);
14511501
if (Op1.isExpr()) {
@@ -1465,9 +1515,13 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
14651515
Imm = SignExtend64<32>(Imm);
14661516
emitLoadImm(Reg, Imm, Out);
14671517
return false;
1468-
} else if (Inst.getOpcode() == RISCV::PseudoLLA) {
1518+
}
1519+
case RISCV::PseudoLLA:
14691520
emitLoadLocalAddress(Inst, IDLoc, Out);
14701521
return false;
1522+
case RISCV::PseudoLA:
1523+
emitLoadAddress(Inst, IDLoc, Out);
1524+
return false;
14711525
}
14721526

14731527
emitToStreamer(Out, Inst);

llvm/lib/Target/RISCV/RISCVInstrInfo.td

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,6 @@ def SFENCE_VMA : RVInstR<0b0001001, 0b000, OPC_SYSTEM, (outs),
493493
// Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20)
494494
//===----------------------------------------------------------------------===//
495495

496-
// TODO la
497496
// TODO lb lh lw
498497
// TODO RV64I: ld
499498
// TODO sb sh sw
@@ -841,6 +840,11 @@ let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 0,
841840
def PseudoLLA : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
842841
"lla", "$dst, $src">;
843842

843+
let hasSideEffects = 0, mayLoad = 1, mayStore = 0, isCodeGenOnly = 0,
844+
isAsmParserOnly = 1 in
845+
def PseudoLA : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
846+
"la", "$dst, $src">;
847+
844848
/// Loads
845849

846850
multiclass LdPat<PatFrag LoadOp, RVInst Inst> {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# RUN: not llvm-mc %s -triple=riscv64 2>&1 | FileCheck %s
2+
# RUN: not llvm-mc %s -triple=riscv64 2>&1 | FileCheck %s
3+
4+
lla x1, 1234 # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
5+
lla x1, %pcrel_hi(1234) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
6+
lla x1, %pcrel_lo(1234) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
7+
lla x1, %pcrel_hi(foo) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
8+
lla x1, %pcrel_lo(foo) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
9+
lla x1, %hi(1234) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
10+
lla x1, %lo(1234) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
11+
lla x1, %hi(foo) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
12+
lla x1, %lo(foo) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
13+
14+
la x1, 1234 # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name
15+
la x1, %pcrel_hi(1234) # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name
16+
la x1, %pcrel_lo(1234) # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name
17+
la x1, %pcrel_hi(foo) # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name
18+
la x1, %pcrel_lo(foo) # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name
19+
la x1, %hi(1234) # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name
20+
la x1, %lo(1234) # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name
21+
la x1, %hi(foo) # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name
22+
la x1, %lo(foo) # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name

llvm/test/MC/RISCV/rvi-pseudos.s

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
# RUN: llvm-mc %s -triple=riscv32 | FileCheck %s
2-
# RUN: llvm-mc %s -triple=riscv64 | FileCheck %s
1+
# RUN: llvm-mc %s -triple=riscv32 | FileCheck %s --check-prefixes=CHECK,CHECK-NOPIC
2+
# RUN: llvm-mc %s -triple=riscv64 | FileCheck %s --check-prefixes=CHECK,CHECK-NOPIC
3+
# RUN: llvm-mc %s -triple=riscv32 -position-independent \
4+
# RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-PIC,CHECK-PIC-RV32
5+
# RUN: llvm-mc %s -triple=riscv64 -position-independent \
6+
# RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-PIC,CHECK-PIC-RV64
37

48
# CHECK: .Lpcrel_hi0:
59
# CHECK: auipc a0, %pcrel_hi(a_symbol)
@@ -26,3 +30,44 @@ lla a3, ra
2630
# CHECK: auipc a4, %pcrel_hi(f1)
2731
# CHECK: addi a4, a4, %pcrel_lo(.Lpcrel_hi4)
2832
lla a4, f1
33+
34+
# CHECK: .Lpcrel_hi5:
35+
# CHECK-NOPIC: auipc a0, %pcrel_hi(a_symbol)
36+
# CHECK-NOPIC: addi a0, a0, %pcrel_lo(.Lpcrel_hi5)
37+
# CHECK-PIC: auipc a0, %got_pcrel_hi(a_symbol)
38+
# CHECK-PIC-RV32: lw a0, %pcrel_lo(.Lpcrel_hi5)(a0)
39+
# CHECK-PIC-RV64: ld a0, %pcrel_lo(.Lpcrel_hi5)(a0)
40+
la a0, a_symbol
41+
42+
# CHECK: .Lpcrel_hi6:
43+
# CHECK-NOPIC: auipc a1, %pcrel_hi(another_symbol)
44+
# CHECK-NOPIC: addi a1, a1, %pcrel_lo(.Lpcrel_hi6)
45+
# CHECK-PIC: auipc a1, %got_pcrel_hi(another_symbol)
46+
# CHECK-PIC-RV32: lw a1, %pcrel_lo(.Lpcrel_hi6)(a1)
47+
# CHECK-PIC-RV64: ld a1, %pcrel_lo(.Lpcrel_hi6)(a1)
48+
la a1, another_symbol
49+
50+
# Check that we can load the address of symbols that are spelled like a register
51+
# CHECK: .Lpcrel_hi7:
52+
# CHECK-NOPIC: auipc a2, %pcrel_hi(zero)
53+
# CHECK-NOPIC: addi a2, a2, %pcrel_lo(.Lpcrel_hi7)
54+
# CHECK-PIC: auipc a2, %got_pcrel_hi(zero)
55+
# CHECK-PIC-RV32: lw a2, %pcrel_lo(.Lpcrel_hi7)(a2)
56+
# CHECK-PIC-RV64: ld a2, %pcrel_lo(.Lpcrel_hi7)(a2)
57+
la a2, zero
58+
59+
# CHECK: .Lpcrel_hi8:
60+
# CHECK-NOPIC: auipc a3, %pcrel_hi(ra)
61+
# CHECK-NOPIC: addi a3, a3, %pcrel_lo(.Lpcrel_hi8)
62+
# CHECK-PIC: auipc a3, %got_pcrel_hi(ra)
63+
# CHECK-PIC-RV32: lw a3, %pcrel_lo(.Lpcrel_hi8)(a3)
64+
# CHECK-PIC-RV64: ld a3, %pcrel_lo(.Lpcrel_hi8)(a3)
65+
la a3, ra
66+
67+
# CHECK: .Lpcrel_hi9:
68+
# CHECK-NOPIC: auipc a4, %pcrel_hi(f1)
69+
# CHECK-NOPIC: addi a4, a4, %pcrel_lo(.Lpcrel_hi9)
70+
# CHECK-PIC: auipc a4, %got_pcrel_hi(f1)
71+
# CHECK-PIC-RV32: lw a4, %pcrel_lo(.Lpcrel_hi9)(a4)
72+
# CHECK-PIC-RV64: ld a4, %pcrel_lo(.Lpcrel_hi9)(a4)
73+
la a4, f1

0 commit comments

Comments
 (0)