Index: lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -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" @@ -79,9 +80,16 @@ // synthesize the desired immedate value into the destination register. void emitLoadImm(unsigned DestReg, int64_t Value, MCStreamer &Out); + 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 @@ -1415,42 +1423,81 @@ } } -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; + 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: { auto Reg = Inst.getOperand(0).getReg(); int64_t Imm = Inst.getOperand(1).getImm(); // On RV32 the immediate here can either be a signed or an unsigned @@ -1460,9 +1507,13 @@ 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); Index: lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.td +++ lib/Target/RISCV/RISCVInstrInfo.td @@ -817,6 +817,11 @@ 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 { Index: test/MC/RISCV/rvi-pseudos.s =================================================================== --- test/MC/RISCV/rvi-pseudos.s +++ test/MC/RISCV/rvi-pseudos.s @@ -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) @@ -26,3 +30,44 @@ # 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