Skip to content

Commit 22531c4

Browse files
committed
[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 8eb87e5 commit 22531c4

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
@@ -20,6 +20,7 @@
2020
#include "llvm/MC/MCExpr.h"
2121
#include "llvm/MC/MCInst.h"
2222
#include "llvm/MC/MCInstBuilder.h"
23+
#include "llvm/MC/MCObjectFileInfo.h"
2324
#include "llvm/MC/MCParser/MCAsmLexer.h"
2425
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
2526
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
@@ -78,9 +79,18 @@ class RISCVAsmParser : public MCTargetAsmParser {
7879
// synthesize the desired immedate value into the destination register.
7980
void emitLoadImm(unsigned DestReg, int64_t Value, MCStreamer &Out);
8081

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

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

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

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

1426-
MCOperand DestReg = Inst.getOperand(0);
1427-
const RISCVMCExpr *Symbol = RISCVMCExpr::create(
1428-
Inst.getOperand(1).getExpr(), RISCVMCExpr::VK_RISCV_PCREL_HI, Ctx);
1429-
1436+
const RISCVMCExpr *SymbolHi = RISCVMCExpr::create(Symbol, VKHi, Ctx);
14301437
emitToStreamer(
1431-
Out, MCInstBuilder(RISCV::AUIPC).addOperand(DestReg).addExpr(Symbol));
1438+
Out, MCInstBuilder(RISCV::AUIPC).addOperand(TmpReg).addExpr(SymbolHi));
14321439

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

1437-
emitToStreamer(Out, MCInstBuilder(RISCV::ADDI)
1438-
.addOperand(DestReg)
1444+
emitToStreamer(Out, MCInstBuilder(SecondOpcode)
14391445
.addOperand(DestReg)
1446+
.addOperand(TmpReg)
14401447
.addExpr(RefToLinkTmpLabel));
14411448
}
14421449

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

1447-
if (Inst.getOpcode() == RISCV::PseudoLI) {
1494+
switch (Inst.getOpcode()) {
1495+
default:
1496+
break;
1497+
case RISCV::PseudoLI: {
14481498
unsigned Reg = Inst.getOperand(0).getReg();
14491499
const MCOperand &Op1 = Inst.getOperand(1);
14501500
if (Op1.isExpr()) {
@@ -1464,9 +1514,13 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
14641514
Imm = SignExtend64<32>(Imm);
14651515
emitLoadImm(Reg, Imm, Out);
14661516
return false;
1467-
} else if (Inst.getOpcode() == RISCV::PseudoLLA) {
1517+
}
1518+
case RISCV::PseudoLLA:
14681519
emitLoadLocalAddress(Inst, IDLoc, Out);
14691520
return false;
1521+
case RISCV::PseudoLA:
1522+
emitLoadAddress(Inst, IDLoc, Out);
1523+
return false;
14701524
}
14711525

14721526
emitToStreamer(Out, Inst);

llvm/lib/Target/RISCV/RISCVInstrInfo.td

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

500-
// TODO la
501500
// TODO lb lh lw
502501
// TODO RV64I: ld
503502
// TODO sb sh sw
@@ -845,6 +844,11 @@ let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 0,
845844
def PseudoLLA : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
846845
"lla", "$dst, $src">;
847846

847+
let hasSideEffects = 0, mayLoad = 1, mayStore = 0, isCodeGenOnly = 0,
848+
isAsmParserOnly = 1 in
849+
def PseudoLA : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
850+
"la", "$dst, $src">;
851+
848852
/// Loads
849853

850854
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)