Skip to content

Commit

Permalink
[RISCV] Add new lga pseudoinstruction
Browse files Browse the repository at this point in the history
This mirrors lla and is always GOT-relative, allowing an explicit
request to use the GOT without having to expand the instruction. This
then means la is just defined in terms of lla and lga in the assembler,
based on whether PIC is enabled, and at the codegen level we replace la
entirely with lga since we only ever use la there when we want to load
from the GOT (and assert that to be the case).

See riscv-non-isa/riscv-asm-manual#50

Reviewed By: asb, MaskRay

Differential Revision: https://reviews.llvm.org/D107278
  • Loading branch information
jrtc27 committed May 31, 2023
1 parent b9d5351 commit 9b55e5d
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 104 deletions.
45 changes: 28 additions & 17 deletions llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
Expand Up @@ -139,6 +139,9 @@ class RISCVAsmParser : public MCTargetAsmParser {
// Helper to emit pseudo instruction "lla" used in PC-rel addressing.
void emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);

// Helper to emit pseudo instruction "lga" used in GOT-rel addressing.
void emitLoadGlobalAddress(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);

Expand Down Expand Up @@ -3088,29 +3091,34 @@ void RISCVAsmParser::emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc,
RISCV::ADDI, IDLoc, Out);
}

void RISCVAsmParser::emitLoadGlobalAddress(MCInst &Inst, SMLoc IDLoc,
MCStreamer &Out) {
// The load global address pseudo-instruction "lga" is used in GOT-indirect
// addressing of global symbols:
// lga rdest, symbol
// expands to
// 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 = isRV64() ? RISCV::LD : RISCV::LW;
emitAuipcInstPair(DestReg, DestReg, Symbol, RISCVMCExpr::VK_RISCV_GOT_HI,
SecondOpcode, 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)
// is an alias for either (for non-PIC)
// lla rdest, symbol
// 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;
if (ParserOptions.IsPicEnabled) {
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);
// lga rdest, symbol
if (ParserOptions.IsPicEnabled)
emitLoadGlobalAddress(Inst, IDLoc, Out);
else
emitLoadLocalAddress(Inst, IDLoc, Out);
}

void RISCVAsmParser::emitLoadTLSIEAddress(MCInst &Inst, SMLoc IDLoc,
Expand Down Expand Up @@ -3438,6 +3446,9 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
case RISCV::PseudoLLA:
emitLoadLocalAddress(Inst, IDLoc, Out);
return false;
case RISCV::PseudoLGA:
emitLoadGlobalAddress(Inst, IDLoc, Out);
return false;
case RISCV::PseudoLA:
emitLoadAddress(Inst, IDLoc, Out);
return false;
Expand Down
17 changes: 6 additions & 11 deletions llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
Expand Up @@ -371,9 +371,9 @@ class RISCVPreRAExpandPseudo : public MachineFunctionPass {
bool expandLoadLocalAddress(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
MachineBasicBlock::iterator &NextMBBI);
bool expandLoadAddress(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
MachineBasicBlock::iterator &NextMBBI);
bool expandLoadGlobalAddress(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
MachineBasicBlock::iterator &NextMBBI);
bool expandLoadTLSIEAddress(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
MachineBasicBlock::iterator &NextMBBI);
Expand Down Expand Up @@ -431,8 +431,8 @@ bool RISCVPreRAExpandPseudo::expandMI(MachineBasicBlock &MBB,
switch (MBBI->getOpcode()) {
case RISCV::PseudoLLA:
return expandLoadLocalAddress(MBB, MBBI, NextMBBI);
case RISCV::PseudoLA:
return expandLoadAddress(MBB, MBBI, NextMBBI);
case RISCV::PseudoLGA:
return expandLoadGlobalAddress(MBB, MBBI, NextMBBI);
case RISCV::PseudoLA_TLS_IE:
return expandLoadTLSIEAddress(MBB, MBBI, NextMBBI);
case RISCV::PseudoLA_TLS_GD:
Expand Down Expand Up @@ -480,17 +480,12 @@ bool RISCVPreRAExpandPseudo::expandLoadLocalAddress(
RISCV::ADDI);
}

bool RISCVPreRAExpandPseudo::expandLoadAddress(
bool RISCVPreRAExpandPseudo::expandLoadGlobalAddress(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
MachineBasicBlock::iterator &NextMBBI) {
MachineFunction *MF = MBB.getParent();

const auto &STI = MF->getSubtarget<RISCVSubtarget>();
// When HWASAN is used and tagging of global variables is enabled
// they should be accessed via the GOT, since the tagged address of a global
// is incompatible with existing code models. This also applies to non-pic
// mode.
assert(MF->getTarget().isPositionIndependent() || STI.allowTaggedGlobals());
unsigned SecondOpcode = STI.is64Bit() ? RISCV::LD : RISCV::LW;
return expandAuipcInstPair(MBB, MBBI, NextMBBI, RISCVII::MO_GOT_HI,
SecondOpcode);
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/Target/RISCV/RISCVISelLowering.cpp
Expand Up @@ -5278,7 +5278,7 @@ SDValue RISCVTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
return DAG.getNode(RISCVISD::LLA, DL, Ty, Addr);

// Use PC-relative addressing to access the GOT for this symbol, then load
// the address from the GOT. This generates the pattern (PseudoLA sym),
// the address from the GOT. This generates the pattern (PseudoLGA sym),
// which expands to (ld (addi (auipc %got_pcrel_hi(sym)) %pcrel_lo(auipc))).
MachineFunction &MF = DAG.getMachineFunction();
MachineMemOperand *MemOp = MF.getMachineMemOperand(
Expand All @@ -5287,7 +5287,7 @@ SDValue RISCVTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
MachineMemOperand::MOInvariant,
LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8));
SDValue Load =
DAG.getMemIntrinsicNode(RISCVISD::LA, DL, DAG.getVTList(Ty, MVT::Other),
DAG.getMemIntrinsicNode(RISCVISD::LGA, DL, DAG.getVTList(Ty, MVT::Other),
{DAG.getEntryNode(), Addr}, Ty, MemOp);
return Load;
}
Expand Down Expand Up @@ -15279,8 +15279,8 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(ADD_LO)
NODE_NAME_CASE(HI)
NODE_NAME_CASE(LLA)
NODE_NAME_CASE(LGA)
NODE_NAME_CASE(ADD_TPREL)
NODE_NAME_CASE(LA)
NODE_NAME_CASE(LA_TLS_IE)
NODE_NAME_CASE(LA_TLS_GD)
NODE_NAME_CASE(MULHSU)
Expand Down
5 changes: 3 additions & 2 deletions llvm/lib/Target/RISCV/RISCVISelLowering.h
Expand Up @@ -371,8 +371,9 @@ enum NodeType : unsigned {
// have memop! In fact, starting from FIRST_TARGET_MEMORY_OPCODE all
// opcodes will be thought as target memory ops!

// Load address.
LA = ISD::FIRST_TARGET_MEMORY_OPCODE,
// Represents an AUIPC+L[WD] pair. Selected to PseudoLGA.
LGA = ISD::FIRST_TARGET_MEMORY_OPCODE,
// Load initial exec thread-local address.
LA_TLS_IE,

TH_LWD,
Expand Down
13 changes: 9 additions & 4 deletions llvm/lib/Target/RISCV/RISCVInstrInfo.td
Expand Up @@ -84,14 +84,14 @@ def riscv_read_cycle_wide : SDNode<"RISCVISD::READ_CYCLE_WIDE",
def riscv_add_lo : SDNode<"RISCVISD::ADD_LO", SDTIntBinOp>;
def riscv_hi : SDNode<"RISCVISD::HI", SDTIntUnaryOp>;
def riscv_lla : SDNode<"RISCVISD::LLA", SDTIntUnaryOp>;
def riscv_lga : SDNode<"RISCVISD::LGA", SDTLoad,
[SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;
def riscv_add_tprel : SDNode<"RISCVISD::ADD_TPREL",
SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>,
SDTCisSameAs<0, 2>,
SDTCisSameAs<0, 3>,
SDTCisInt<0>]>>;

def riscv_la : SDNode<"RISCVISD::LA", SDTLoad,
[SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;
def riscv_la_tls_ie : SDNode<"RISCVISD::LA_TLS_IE", SDTLoad,
[SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;
def riscv_la_tls_gd : SDNode<"RISCVISD::LA_TLS_GD", SDTIntUnaryOp>;
Expand Down Expand Up @@ -1599,13 +1599,18 @@ def : Pat<(riscv_lla tblockaddress:$in), (PseudoLLA tblockaddress:$in)>;
def : Pat<(riscv_lla tjumptable:$in), (PseudoLLA tjumptable:$in)>;
def : Pat<(riscv_lla tconstpool:$in), (PseudoLLA tconstpool:$in)>;

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

def : Pat<(riscv_lga tglobaladdr:$in), (PseudoLGA tglobaladdr:$in)>;

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

def : Pat<(riscv_la tglobaladdr:$in), (PseudoLA tglobaladdr:$in)>;

let hasSideEffects = 0, mayLoad = 1, mayStore = 0, Size = 8, isCodeGenOnly = 0,
isAsmParserOnly = 1 in
def PseudoLA_TLS_IE : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
Expand Down
10 changes: 10 additions & 0 deletions llvm/test/MC/RISCV/rvi-pseudos-invalid.s
Expand Up @@ -11,6 +11,16 @@ lla x1, %lo(1234) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol na
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

lga x1, 1234 # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
lga x1, %pcrel_hi(1234) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
lga x1, %pcrel_lo(1234) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
lga x1, %pcrel_hi(foo) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
lga x1, %pcrel_lo(foo) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
lga x1, %hi(1234) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
lga x1, %lo(1234) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
lga x1, %hi(foo) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
lga 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
Expand Down

0 comments on commit 9b55e5d

Please sign in to comment.