8000 Add support for pc-relative addressing on 64-bit RISC-V by Disasm · Pull Request #16 · rust-lang/llvm-project · GitHub
[go: up one dir, main page]

Skip to content

Add support for pc-relative addressing on 64-bit RISC-V #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 1, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
[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
  • Loading branch information
asb authored and Disasm committed Jun 30, 2019
commit ff06710884ebda808aa5feee72964f171314766e
88 changes: 71 additions & 17 deletions llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstBuilder.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCParser/MCAsmLexer.h"
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
Expand Down Expand Up @@ -79,9 +80,18 @@ class RISCVAsmParser : public MCTargetAsmParser {
// synthesize the desired immedate value into the destination register.
void emitLoadImm(unsigned DestReg, int64_t Value, MCStreamer &Out);

// Helper to emit a combination of AUIPC and SecondOpcode. Used to implement
// helpers such as emitLoadLocalAddress and emitLoadAddress.
void emitAuipcInstPair(MCOperand DestReg, MCOperand TmpReg,
const MCExpr *Symbol, RISCVMCExpr::VariantKind VKHi,
unsigned SecondOpcode, SMLoc IDLoc, MCStreamer &Out);

// Helper to emit pseudo instruction "lla" used in PC-rel addressing.
void emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);

// Helper to emit pseudo instruction "la" used in GOT/PC-rel addressing.
void emitLoadAddress(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);

/// Helper for processing MC instructions that have been successfully matched
/// by MatchAndEmitInstruction. Modifications to the emitted instructions,
/// like the expansion of pseudo instructions (e.g., "li"), can be performed
Expand Down Expand Up @@ -1410,42 +1420,82 @@ void RISCVAsmParser::emitLoadImm(unsigned DestReg, int64_t Value,
}
}

void RISCVAsmParser::emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc,
MCStreamer &Out) {
// The local load address pseudo-instruction "lla" is used in PC-relative
// addressing of symbols:
// lla rdest, symbol
// expands to
// TmpLabel: AUIPC rdest, %pcrel_hi(symbol)
// ADDI rdest, %pcrel_lo(TmpLabel)
void RISCVAsmParser::emitAuipcInstPair(MCOperand DestReg, MCOperand TmpReg,
const MCExpr *Symbol,
RISCVMCExpr::VariantKind VKHi,
unsigned SecondOpcode, SMLoc IDLoc,
MCStreamer &Out) {
// A pair of instructions for PC-relative addressing; expands to
// TmpLabel: AUIPC TmpReg, VKHi(symbol)
// OP DestReg, TmpReg, %pcrel_lo(TmpLabel)
MCContext &Ctx = getContext();

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

MCOperand DestReg = Inst.getOperand(0);
const RISCVMCExpr *Symbol = RISCVMCExpr::create(
Inst.getOperand(1).getExpr(), RISCVMCExpr::VK_RISCV_PCREL_HI, Ctx);

const RISCVMCExpr *SymbolHi = RISCVMCExpr::create(Symbol, VKHi, Ctx);
emitToStreamer(
Out, MCInstBuilder(RISCV::AUIPC).addOperand(DestReg).addExpr(Symbol));
Out, MCInstBuilder(RISCV::AUIPC).addOperand(TmpReg).addExpr(SymbolHi));

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

emitToStreamer(Out, MCInstBuilder(RISCV::ADDI)
.addOperand(DestReg)
emitToStreamer(Out, MCInstBuilder(SecondOpcode)
.addOperand(DestReg)
.addOperand(TmpReg)
.addExpr(RefToLinkTmpLabel));
}

void RISCVAsmParser::emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc,
MCStreamer &Out) {
// The load local address pseudo-instruction "lla" is used in PC-relative
// addressing of local symbols:
// lla rdest, symbol
// expands to
// TmpLabel: AUIPC rdest, %pcrel_hi(symbol)
// ADDI rdest, rdest, %pcrel_lo(TmpLabel)
MCOperand DestReg = Inst.getOperand(0);
const MCExpr *Symbol = Inst.getOperand(1).getExpr();
emitAuipcInstPair(DestReg, DestReg, Symbol, RISCVMCExpr::VK_RISCV_PCREL_HI,
RISCV::ADDI, IDLoc, Out);
}

void RISCVAsmParser::emitLoadAddress(MCInst &Inst, SMLoc IDLoc,
MCStreamer &Out) {
// The load address pseudo-instruction "la" is used in PC-relative and
// GOT-indirect addressing of global symbols:
// la rdest, symbol
// expands to either (for non-PIC)
// TmpLabel: AUIPC rdest, %pcrel_hi(symbol)
// ADDI rdest, rdest, %pcrel_lo(TmpLabel)
// or (for PIC)
// TmpLabel: AUIPC rdest, %got_pcrel_hi(symbol)
// Lx rdest, %pcrel_lo(TmpLabel)(rdest)
MCOperand DestReg = Inst.getOperand(0);
const MCExpr *Symbol = Inst.getOperand(1).getExpr();
unsigned SecondOpcode;
RISCVMCExpr::VariantKind VKHi;
// FIXME: Should check .option (no)pic when implemented
if (getContext().getObjectFileInfo()->isPositionIndependent()) {
SecondOpcode = isRV64() ? RISCV::LD : RISCV::LW;
VKHi = RISCVMCExpr::VK_RISCV_GOT_HI;
} else {
SecondOpcode = RISCV::ADDI;
VKHi = RISCVMCExpr::VK_RISCV_PCREL_HI;
}
emitAuipcInstPair(DestReg, DestReg, Symbol, VKHi, SecondOpcode, IDLoc, Out);
}

bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
MCStreamer &Out) {
Inst.setLoc(IDLoc);

if (Inst.getOpcode() == RISCV::PseudoLI) {
switch (Inst.getOpcode()) {
default:
break;
case RISCV::PseudoLI: {
unsigned Reg = Inst.getOperand(0).getReg();
const MCOperand &Op1 = Inst.getOperand(1);
if (Op1.isExpr()) {
Expand All @@ -1465,9 +1515,13 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
Imm = SignExtend64<32>(Imm);
emitLoadImm(Reg, Imm, Out);
return false;
} else if (Inst.getOpcode() == RISCV::PseudoLLA) {
}
case RISCV::PseudoLLA:
emitLoadLocalAddress(Inst, IDLoc, Out);
return false;
case RISCV::PseudoLA:
emitLoadAddress(Inst, IDLoc, Out);
return false;
}

emitToStreamer(Out, Inst);
Expand Down
6 changes: 5 additions & 1 deletion llvm/lib/Target/RISCV/RISCVInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,6 @@ def SFENCE_VMA : RVInstR<0b0001001, 0b000, OPC_SYSTEM, (outs),
// Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20)
//===----------------------------------------------------------------------===//

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

let hasSideEffects = 0, mayLoad = 1, mayStore = 0, isCodeGenOnly = 0,
isAsmParserOnly = 1 in
def PseudoLA : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
"la", "$dst, $src">;

/// Loads

multiclass LdPat<PatFrag LoadOp, RVInst Inst> {
Expand Down
22 changes: 22 additions & 0 deletions llvm/test/MC/RISCV/rvi-pseudos-invalid.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# RUN: not llvm-mc %s -triple=riscv64 2>&1 | FileCheck %s
# RUN: not llvm-mc %s -triple=riscv64 2>&1 | FileCheck %s

lla x1, 1234 # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
lla x1, %pcrel_hi(1234) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
lla x1, %pcrel_lo(1234) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
lla x1, %pcrel_hi(foo) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
lla x1, %pcrel_lo(foo) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
lla x1, %hi(1234) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
lla x1, %lo(1234) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
lla x1, %hi(foo) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
lla x1, %lo(foo) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name

la x1, 1234 # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name
la x1, %pcrel_hi(1234) # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name
la x1, %pcrel_lo(1234) # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name
la x1, %pcrel_hi(foo) # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name
la x1, %pcrel_lo(foo) # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name
la x1, %hi(1234) # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name
la x1, %lo(1234) # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name
la x1, %hi(foo) # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name
la x1, %lo(foo) # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol name
49 changes: 47 additions & 2 deletions llvm/test/MC/RISCV/rvi-pseudos.s
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# RUN: llvm-mc %s -triple=riscv32 | FileCheck %s
# RUN: llvm-mc %s -triple=riscv64 | FileCheck %s
# RUN: llvm-mc %s -triple=riscv32 | FileCheck %s --check-prefixes=CHECK,CHECK-NOPIC
# RUN: llvm-mc %s -triple=riscv64 | FileCheck %s --check-prefixes=CHECK,CHECK-NOPIC
# RUN: llvm-mc %s -triple=riscv32 -position-independent \
# RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-PIC,CHECK-PIC-RV32
# RUN: llvm-mc %s -triple=riscv64 -position-independent \
# RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-PIC,CHECK-PIC-RV64

# CHECK: .Lpcrel_hi0:
# CHECK: auipc a0, %pcrel_hi(a_symbol)
Expand All @@ -26,3 +30,44 @@ lla a3, ra
# CHECK: auipc a4, %pcrel_hi(f1)
# CHECK: addi a4, a4, %pcrel_lo(.Lpcrel_hi4)
lla a4, f1

# CHECK: .Lpcrel_hi5:
# CHECK-NOPIC: auipc a0, %pcrel_hi(a_symbol)
# CHECK-NOPIC: addi a0, a0, %pcrel_lo(.Lpcrel_hi5)
# CHECK-PIC: auipc a0, %got_pcrel_hi(a_symbol)
# CHECK-PIC-RV32: lw a0, %pcrel_lo(.Lpcrel_hi5)(a0)
# CHECK-PIC-RV64: ld a0, %pcrel_lo(.Lpcrel_hi5)(a0)
la a0, a_symbol

# CHECK: .Lpcrel_hi6:
# CHECK-NOPIC: auipc a1, %pcrel_hi(another_symbol)
# CHECK-NOPIC: addi a1, a1, %pcrel_lo(.Lpcrel_hi6)
# CHECK-PIC: auipc a1, %got_pcrel_hi(another_symbol)
# CHECK-PIC-RV32: lw a1, %pcrel_lo(.Lpcrel_hi6)(a1)
# CHECK-PIC-RV64: ld a1, %pcrel_lo(.Lpcrel_hi6)(a1)
la a1, another_symbol

# Check that we can load the address of symbols that are spelled like a register
# CHECK: .Lpcrel_hi7:
# CHECK-NOPIC: auipc a2, %pcrel_hi(zero)
# CHECK-NOPIC: addi a2, a2, %pcrel_lo(.Lpcrel_hi7)
# CHECK-PIC: auipc a2, %got_pcrel_hi(zero)
# CHECK-PIC-RV32: lw a2, %pcrel_lo(.Lpcrel_hi7)(a2)
# CHECK-PIC-RV64: ld a2, %pcrel_lo(.Lpcrel_hi7)(a2)
la a2, zero

# CHECK: .Lpcrel_hi8:
# CHECK-NOPIC: auipc a3, %pcrel_hi(ra)
# CHECK-NOPIC: addi a3, a3, %pcrel_lo(.Lpcrel_hi8)
# CHECK-PIC: auipc a3, %got_pcrel_hi(ra)
# CHECK-PIC-RV32: lw a3, %pcrel_lo(.Lpcrel_hi8)(a3)
# CHECK-PIC-RV64: ld a3, %pcrel_lo(.Lpcrel_hi8)(a3)
la a3, ra

# CHECK: .Lpcrel_hi9:
# CHECK-NOPIC: auipc a4, %pcrel_hi(f1)
# CHECK-NOPIC: addi a4, a4, %pcrel_lo(.Lpcrel_hi9)
# CHECK-PIC: auipc a4, %got_pcrel_hi(f1)
# CHECK-PIC-RV32: lw a4, %pcrel_lo(.Lpcrel_hi9)(a4)
# CHECK-PIC-RV64: ld a4, %pcrel_lo(.Lpcrel_hi9)(a4)
la a4, f1
0