forked from OSchip/llvm-project
[RISCV] Implement pseudo instructions for load/store from a symbol address.
Summary: Those pseudo-instructions are making load/store instructions able to load/store from/to a symbol, and its always using PC-relative addressing to generating a symbol address. Reviewers: asb, apazos, rogfer01, jrtc27 Differential Revision: https://reviews.llvm.org/D50496 llvm-svn: 354430
This commit is contained in:
parent
476e1b9937
commit
303217e8b4
|
@ -91,6 +91,10 @@ class RISCVAsmParser : public MCTargetAsmParser {
|
|||
// Helper to emit pseudo instruction "la" used in GOT/PC-rel addressing.
|
||||
void emitLoadAddress(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
|
||||
|
||||
// Helper to emit pseudo load/store instruction with a symbol.
|
||||
void emitLoadStoreSymbol(MCInst &Inst, unsigned Opcode, SMLoc IDLoc,
|
||||
MCStreamer &Out, bool HasTmpReg);
|
||||
|
||||
/// 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
|
||||
|
@ -1105,11 +1109,22 @@ OperandMatchResultTy RISCVAsmParser::parseBareSymbol(OperandVector &Operands) {
|
|||
return MatchOperand_NoMatch;
|
||||
|
||||
StringRef Identifier;
|
||||
AsmToken Tok = getLexer().getTok();
|
||||
|
||||
if (getParser().parseIdentifier(Identifier))
|
||||
return MatchOperand_ParseFail;
|
||||
|
||||
MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
|
||||
Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
|
||||
|
||||
if (Sym->isVariable()) {
|
||||
const MCExpr *V = Sym->getVariableValue(/*SetUsed=*/false);
|
||||
if (!isa<MCSymbolRefExpr>(V)) {
|
||||
getLexer().UnLex(Tok); // Put back if it's not a bare symbol.
|
||||
return MatchOperand_NoMatch;
|
||||
}
|
||||
Res = V;
|
||||
} else
|
||||
Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
|
||||
Operands.push_back(RISCVOperand::createImm(Res, S, E, isRV64()));
|
||||
return MatchOperand_Success;
|
||||
}
|
||||
|
@ -1487,6 +1502,25 @@ void RISCVAsmParser::emitLoadAddress(MCInst &Inst, SMLoc IDLoc,
|
|||
emitAuipcInstPair(DestReg, DestReg, Symbol, VKHi, SecondOpcode, IDLoc, Out);
|
||||
}
|
||||
|
||||
void RISCVAsmParser::emitLoadStoreSymbol(MCInst &Inst, unsigned Opcode,
|
||||
SMLoc IDLoc, MCStreamer &Out,
|
||||
bool HasTmpReg) {
|
||||
// The load/store pseudo-instruction does a pc-relative load with
|
||||
// a symbol.
|
||||
//
|
||||
// The expansion looks like this
|
||||
//
|
||||
// TmpLabel: AUIPC tmp, %pcrel_hi(symbol)
|
||||
// [S|L]X rd, %pcrel_lo(TmpLabel)(tmp)
|
||||
MCOperand DestReg = Inst.getOperand(0);
|
||||
unsigned SymbolOpIdx = HasTmpReg ? 2 : 1;
|
||||
unsigned TmpRegOpIdx = HasTmpReg ? 1 : 0;
|
||||
MCOperand TmpReg = Inst.getOperand(TmpRegOpIdx);
|
||||
const MCExpr *Symbol = Inst.getOperand(SymbolOpIdx).getExpr();
|
||||
emitAuipcInstPair(DestReg, TmpReg, Symbol, RISCVMCExpr::VK_RISCV_PCREL_HI,
|
||||
Opcode, IDLoc, Out);
|
||||
}
|
||||
|
||||
bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
|
||||
MCStreamer &Out) {
|
||||
Inst.setLoc(IDLoc);
|
||||
|
@ -1521,6 +1555,51 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
|
|||
case RISCV::PseudoLA:
|
||||
emitLoadAddress(Inst, IDLoc, Out);
|
||||
return false;
|
||||
case RISCV::PseudoLB:
|
||||
emitLoadStoreSymbol(Inst, RISCV::LB, IDLoc, Out, /*HasTmpReg=*/false);
|
||||
return false;
|
||||
case RISCV::PseudoLBU:
|
||||
emitLoadStoreSymbol(Inst, RISCV::LBU, IDLoc, Out, /*HasTmpReg=*/false);
|
||||
return false;
|
||||
case RISCV::PseudoLH:
|
||||
emitLoadStoreSymbol(Inst, RISCV::LH, IDLoc, Out, /*HasTmpReg=*/false);
|
||||
return false;
|
||||
case RISCV::PseudoLHU:
|
||||
emitLoadStoreSymbol(Inst, RISCV::LHU, IDLoc, Out, /*HasTmpReg=*/false);
|
||||
return false;
|
||||
case RISCV::PseudoLW:
|
||||
emitLoadStoreSymbol(Inst, RISCV::LW, IDLoc, Out, /*HasTmpReg=*/false);
|
||||
return false;
|
||||
case RISCV::PseudoLWU:
|
||||
emitLoadStoreSymbol(Inst, RISCV::LWU, IDLoc, Out, /*HasTmpReg=*/false);
|
||||
return false;
|
||||
case RISCV::PseudoLD:
|
||||
emitLoadStoreSymbol(Inst, RISCV::LD, IDLoc, Out, /*HasTmpReg=*/false);
|
||||
return false;
|
||||
case RISCV::PseudoFLW:
|
||||
emitLoadStoreSymbol(Inst, RISCV::FLW, IDLoc, Out, /*HasTmpReg=*/true);
|
||||
return false;
|
||||
case RISCV::PseudoFLD:
|
||||
emitLoadStoreSymbol(Inst, RISCV::FLD, IDLoc, Out, /*HasTmpReg=*/true);
|
||||
return false;
|
||||
case RISCV::PseudoSB:
|
||||
emitLoadStoreSymbol(Inst, RISCV::SB, IDLoc, Out, /*HasTmpReg=*/true);
|
||||
return false;
|
||||
case RISCV::PseudoSH:
|
||||
emitLoadStoreSymbol(Inst, RISCV::SH, IDLoc, Out, /*HasTmpReg=*/true);
|
||||
return false;
|
||||
case RISCV::PseudoSW:
|
||||
emitLoadStoreSymbol(Inst, RISCV::SW, IDLoc, Out, /*HasTmpReg=*/true);
|
||||
return false;
|
||||
case RISCV::PseudoSD:
|
||||
emitLoadStoreSymbol(Inst, RISCV::SD, IDLoc, Out, /*HasTmpReg=*/true);
|
||||
return false;
|
||||
case RISCV::PseudoFSW:
|
||||
emitLoadStoreSymbol(Inst, RISCV::FSW, IDLoc, Out, /*HasTmpReg=*/true);
|
||||
return false;
|
||||
case RISCV::PseudoFSD:
|
||||
emitLoadStoreSymbol(Inst, RISCV::FSD, IDLoc, Out, /*HasTmpReg=*/true);
|
||||
return false;
|
||||
}
|
||||
|
||||
emitToStreamer(Out, Inst);
|
||||
|
|
|
@ -108,6 +108,35 @@ class Pseudo<dag outs, dag ins, list<dag> pattern, string opcodestr = "", string
|
|||
let isCodeGenOnly = 1;
|
||||
}
|
||||
|
||||
// Pseudo load instructions.
|
||||
class PseudoLoad<string opcodestr, RegisterClass rdty = GPR>
|
||||
: Pseudo<(outs rdty:$rd), (ins bare_symbol:$addr), [], opcodestr, "$rd, $addr"> {
|
||||
let hasSideEffects = 0;
|
||||
let mayLoad = 1;
|
||||
let mayStore = 0;
|
||||
let isCodeGenOnly = 0;
|
||||
let isAsmParserOnly = 1;
|
||||
}
|
||||
|
||||
class PseudoFloatLoad<string opcodestr, RegisterClass rdty = GPR>
|
||||
: Pseudo<(outs rdty:$rd, GPR:$tmp), (ins bare_symbol:$addr), [], opcodestr, "$rd, $addr, $tmp"> {
|
||||
let hasSideEffects = 0;
|
||||
let mayLoad = 1;
|
||||
let mayStore = 0;
|
||||
let isCodeGenOnly = 0;
|
||||
let isAsmParserOnly = 1;
|
||||
}
|
||||
|
||||
// Pseudo store instructions.
|
||||
class PseudoStore<string opcodestr, RegisterClass rsty = GPR>
|
||||
: Pseudo<(outs rsty:$rs, GPR:$tmp), (ins bare_symbol:$addr), [], opcodestr, "$rs, $addr, $tmp"> {
|
||||
let hasSideEffects = 0;
|
||||
let mayLoad = 0;
|
||||
let mayStore = 1;
|
||||
let isCodeGenOnly = 0;
|
||||
let isAsmParserOnly = 1;
|
||||
}
|
||||
|
||||
// Instruction formats are listed in the order they appear in the RISC-V
|
||||
// instruction set manual (R, I, S, B, U, J) with sub-formats (e.g. RVInstR4,
|
||||
// RVInstRAtomic) sorted alphabetically.
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
include "RISCVInstrFormats.td"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// RISC-V specific DAG Nodes.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -240,6 +238,12 @@ def HI20 : SDNodeXForm<imm, [{
|
|||
SDLoc(N), N->getValueType(0));
|
||||
}]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Instruction Formats
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
include "RISCVInstrFormats.td"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Instruction Class Templates
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -497,11 +501,6 @@ def SFENCE_VMA : RVInstR<0b0001001, 0b000, OPC_SYSTEM, (outs),
|
|||
// Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20)
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// TODO lb lh lw
|
||||
// TODO RV64I: ld
|
||||
// TODO sb sh sw
|
||||
// TODO RV64I: sd
|
||||
|
||||
def : InstAlias<"nop", (ADDI X0, X0, 0)>;
|
||||
|
||||
// Note that the size is 32 because up to 8 32-bit instructions are needed to
|
||||
|
@ -513,6 +512,22 @@ let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Size = 32,
|
|||
def PseudoLI : Pseudo<(outs GPR:$rd), (ins ixlenimm_li:$imm), [],
|
||||
"li", "$rd, $imm">;
|
||||
|
||||
def PseudoLB : PseudoLoad<"lb">;
|
||||
def PseudoLBU : PseudoLoad<"lbu">;
|
||||
def PseudoLH : PseudoLoad<"lh">;
|
||||
def PseudoLHU : PseudoLoad<"lhu">;
|
||||
def PseudoLW : PseudoLoad<"lw">;
|
||||
|
||||
def PseudoSB : PseudoStore<"sb">;
|
||||
def PseudoSH : PseudoStore<"sh">;
|
||||
def PseudoSW : PseudoStore<"sw">;
|
||||
|
||||
let Predicates = [IsRV64] in {
|
||||
def PseudoLWU : PseudoLoad<"lwu">;
|
||||
def PseudoLD : PseudoLoad<"ld">;
|
||||
def PseudoSD : PseudoStore<"sd">;
|
||||
} // Predicates = [IsRV64]
|
||||
|
||||
def : InstAlias<"mv $rd, $rs", (ADDI GPR:$rd, GPR:$rs, 0)>;
|
||||
def : InstAlias<"not $rd, $rs", (XORI GPR:$rd, GPR:$rs, -1)>;
|
||||
def : InstAlias<"neg $rd, $rs", (SUB GPR:$rd, X0, GPR:$rs)>;
|
||||
|
|
|
@ -178,9 +178,6 @@ def FMV_D_X : FPUnaryOp_r<0b1111001, 0b000, FPR64, GPR, "fmv.d.x"> {
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
let Predicates = [HasStdExtD] in {
|
||||
// TODO fld
|
||||
// TODO fsd
|
||||
|
||||
def : InstAlias<"fmv.d $rd, $rs", (FSGNJ_D FPR64:$rd, FPR64:$rs, FPR64:$rs)>;
|
||||
def : InstAlias<"fabs.d $rd, $rs", (FSGNJX_D FPR64:$rd, FPR64:$rs, FPR64:$rs)>;
|
||||
def : InstAlias<"fneg.d $rd, $rs", (FSGNJN_D FPR64:$rd, FPR64:$rs, FPR64:$rs)>;
|
||||
|
@ -191,6 +188,9 @@ def : InstAlias<"fgt.d $rd, $rs, $rt",
|
|||
(FLT_D GPR:$rd, FPR64:$rt, FPR64:$rs), 0>;
|
||||
def : InstAlias<"fge.d $rd, $rs, $rt",
|
||||
(FLE_D GPR:$rd, FPR64:$rt, FPR64:$rs), 0>;
|
||||
|
||||
def PseudoFLD : PseudoFloatLoad<"fld", FPR64>;
|
||||
def PseudoFSD : PseudoStore<"fsd", FPR64>;
|
||||
} // Predicates = [HasStdExtD]
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -206,9 +206,6 @@ def : FPUnaryOpDynFrmAlias<FCVT_S_LU, "fcvt.s.lu", FPR32, GPR>;
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
let Predicates = [HasStdExtF] in {
|
||||
// TODO flw
|
||||
// TODO fsw
|
||||
|
||||
def : InstAlias<"fmv.s $rd, $rs", (FSGNJ_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>;
|
||||
def : InstAlias<"fabs.s $rd, $rs", (FSGNJX_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>;
|
||||
def : InstAlias<"fneg.s $rd, $rs", (FSGNJN_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>;
|
||||
|
@ -244,6 +241,9 @@ def : InstAlias<"fsflagsi $imm", (CSRRWI X0, 0x001, uimm5:$imm), 2>;
|
|||
// spellings should be supported by standard tools.
|
||||
def : MnemonicAlias<"fmv.s.x", "fmv.w.x">;
|
||||
def : MnemonicAlias<"fmv.x.s", "fmv.x.w">;
|
||||
|
||||
def PseudoFLW : PseudoFloatLoad<"flw", FPR32>;
|
||||
def PseudoFSW : PseudoStore<"fsw", FPR32>;
|
||||
} // Predicates = [HasStdExtF]
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -6,8 +6,8 @@ fld ft1, -2049(a0) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with
|
|||
fsd ft2, 2048(a1) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo modifier or an integer in the range [-2048, 2047]
|
||||
|
||||
# Memory operand not formatted correctly
|
||||
fld ft1, a0, -200 # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo modifier or an integer in the range [-2048, 2047]
|
||||
fsd ft2, a1, 100 # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo modifier or an integer in the range [-2048, 2047]
|
||||
fld ft1, a0, -200 # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
|
||||
fsd ft2, a1, 100 # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
|
||||
|
||||
# Invalid register names
|
||||
fld ft15, 100(a0) # CHECK: :[[@LINE]]:5: error: invalid operand for instruction
|
||||
|
|
|
@ -6,8 +6,8 @@ flw ft1, -2049(a0) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with
|
|||
fsw ft2, 2048(a1) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo modifier or an integer in the range [-2048, 2047]
|
||||
|
||||
# Memory operand not formatted correctly
|
||||
flw ft1, a0, -200 # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo modifier or an integer in the range [-2048, 2047]
|
||||
fsw ft2, a1, 100 # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo modifier or an integer in the range [-2048, 2047]
|
||||
flw ft1, a0, -200 # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
|
||||
fsw ft2, a1, 100 # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
|
||||
|
||||
# Invalid register names
|
||||
flw ft15, 100(a0) # CHECK: :[[@LINE]]:5: error: invalid operand for instruction
|
||||
|
|
|
@ -158,7 +158,7 @@ add ra, zero, zero, zero # CHECK: :[[@LINE]]:21: error: invalid operand for inst
|
|||
sltiu s2, s3, 0x50, 0x60 # CHECK: :[[@LINE]]:21: error: invalid operand for instruction
|
||||
|
||||
# Memory operand not formatted correctly
|
||||
lw a4, a5, 111 # CHECK: :[[@LINE]]:8: error: operand must be a symbol with %lo/%pcrel_lo modifier or an integer in the range [-2048, 2047]
|
||||
lw a4, a5, 111 # CHECK: :[[@LINE]]:12: error: invalid operand for instruction
|
||||
|
||||
# Too few operands
|
||||
ori a0, a1 # CHECK: :[[@LINE]]:1: error: too few operands for instruction
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
# RUN: llvm-mc %s -triple=riscv64 | FileCheck %s
|
||||
|
||||
# CHECK: .Lpcrel_hi0:
|
||||
# CHECK: auipc a2, %pcrel_hi(a_symbol)
|
||||
# CHECK: lwu a2, %pcrel_lo(.Lpcrel_hi0)(a2)
|
||||
lwu a2, a_symbol
|
||||
|
||||
# CHECK: .Lpcrel_hi1:
|
||||
# CHECK: auipc a3, %pcrel_hi(a_symbol)
|
||||
# CHECK: ld a3, %pcrel_lo(.Lpcrel_hi1)(a3)
|
||||
ld a3, a_symbol
|
||||
|
||||
# CHECK: .Lpcrel_hi2:
|
||||
# CHECK: auipc a4, %pcrel_hi(a_symbol)
|
||||
# CHECK: sd a3, %pcrel_lo(.Lpcrel_hi2)(a4)
|
||||
sd a3, a_symbol, a4
|
|
@ -0,0 +1,12 @@
|
|||
# RUN: llvm-mc %s -triple=riscv32 -mattr=+d | FileCheck %s
|
||||
# RUN: llvm-mc %s -triple=riscv64 -mattr=+d | FileCheck %s
|
||||
|
||||
# CHECK: .Lpcrel_hi0:
|
||||
# CHECK: auipc a2, %pcrel_hi(a_symbol)
|
||||
# CHECK: fld fa2, %pcrel_lo(.Lpcrel_hi0)(a2)
|
||||
fld fa2, a_symbol, a2
|
||||
|
||||
# CHECK: .Lpcrel_hi1:
|
||||
# CHECK: auipc a3, %pcrel_hi(a_symbol)
|
||||
# CHECK: fsd fa2, %pcrel_lo(.Lpcrel_hi1)(a3)
|
||||
fsd fa2, a_symbol, a3
|
|
@ -0,0 +1,12 @@
|
|||
# RUN: llvm-mc %s -triple=riscv32 -mattr=+f | FileCheck %s
|
||||
# RUN: llvm-mc %s -triple=riscv64 -mattr=+f | FileCheck %s
|
||||
|
||||
# CHECK: .Lpcrel_hi0:
|
||||
# CHECK: auipc a2, %pcrel_hi(a_symbol)
|
||||
# CHECK: flw fa2, %pcrel_lo(.Lpcrel_hi0)(a2)
|
||||
flw fa2, a_symbol, a2
|
||||
|
||||
# CHECK: .Lpcrel_hi1:
|
||||
# CHECK: auipc a3, %pcrel_hi(a_symbol)
|
||||
# CHECK: fsw fa2, %pcrel_lo(.Lpcrel_hi1)(a3)
|
||||
fsw fa2, a_symbol, a3
|
|
@ -20,3 +20,10 @@ la x1, %hi(1234) # CHECK: :[[@LINE]]:8: error: operand must be a bare symbol nam
|
|||
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
|
||||
|
||||
sw a2, %hi(a_symbol), a3 # CHECK: :[[@LINE]]:8: error: operand must be a symbol with %lo/%pcrel_lo modifier or an integer in the range [-2048, 2047]
|
||||
sw a2, %lo(a_symbol), a3 # CHECK: :[[@LINE]]:23: error: invalid operand for instruction
|
||||
sw a2, %lo(a_symbol)(a4), a3 # CHECK: :[[@LINE]]:27: error: invalid operand for instruction
|
||||
|
||||
# Too few operands must be rejected
|
||||
sw a2, a_symbol # CHECK: :[[@LINE]]:1: error: too few operands for instruction
|
||||
|
|
|
@ -71,3 +71,49 @@ la a3, ra
|
|||
# CHECK-PIC-RV32: lw a4, %pcrel_lo(.Lpcrel_hi9)(a4)
|
||||
# CHECK-PIC-RV64: ld a4, %pcrel_lo(.Lpcrel_hi9)(a4)
|
||||
la a4, f1
|
||||
|
||||
# CHECK: .Lpcrel_hi10:
|
||||
# CHECK: auipc a0, %pcrel_hi(a_symbol)
|
||||
# CHECK: lb a0, %pcrel_lo(.Lpcrel_hi10)(a0)
|
||||
lb a0, a_symbol
|
||||
|
||||
# CHECK: .Lpcrel_hi11:
|
||||
# CHECK: auipc a1, %pcrel_hi(a_symbol)
|
||||
# CHECK: lh a1, %pcrel_lo(.Lpcrel_hi11)(a1)
|
||||
lh a1, a_symbol
|
||||
|
||||
# CHECK: .Lpcrel_hi12:
|
||||
# CHECK: auipc a2, %pcrel_hi(a_symbol)
|
||||
# CHECK: lhu a2, %pcrel_lo(.Lpcrel_hi12)(a2)
|
||||
lhu a2, a_symbol
|
||||
|
||||
# CHECK: .Lpcrel_hi13:
|
||||
# CHECK: auipc a3, %pcrel_hi(a_symbol)
|
||||
# CHECK: lw a3, %pcrel_lo(.Lpcrel_hi13)(a3)
|
||||
lw a3, a_symbol
|
||||
|
||||
# CHECK: .Lpcrel_hi14:
|
||||
# CHECK: auipc a4, %pcrel_hi(a_symbol)
|
||||
# CHECK: sb a3, %pcrel_lo(.Lpcrel_hi14)(a4)
|
||||
sb a3, a_symbol, a4
|
||||
|
||||
# CHECK: .Lpcrel_hi15:
|
||||
# CHECK: auipc a4, %pcrel_hi(a_symbol)
|
||||
# CHECK: sh a3, %pcrel_lo(.Lpcrel_hi15)(a4)
|
||||
sh a3, a_symbol, a4
|
||||
|
||||
# CHECK: .Lpcrel_hi16:
|
||||
# CHECK: auipc a4, %pcrel_hi(a_symbol)
|
||||
# CHECK: sw a3, %pcrel_lo(.Lpcrel_hi16)(a4)
|
||||
sw a3, a_symbol, a4
|
||||
|
||||
# Check that we can load the address of symbols that are spelled like a register
|
||||
# CHECK: .Lpcrel_hi17:
|
||||
# CHECK: auipc a2, %pcrel_hi(zero)
|
||||
# CHECK: lw a2, %pcrel_lo(.Lpcrel_hi17)(a2)
|
||||
lw a2, zero
|
||||
|
||||
# CHECK: .Lpcrel_hi18:
|
||||
# CHECK: auipc a4, %pcrel_hi(zero)
|
||||
# CHECK: sw a3, %pcrel_lo(.Lpcrel_hi18)(a4)
|
||||
sw a3, zero, a4
|
||||
|
|
Loading…
Reference in New Issue