Index: lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -79,8 +79,10 @@ // synthesize the desired immedate value into the destination register. void emitLoadImm(unsigned DestReg, int64_t Value, 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 "lla" and load/store + // load/store with symbol. + void emitAuipcInstPair(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + unsigned Opcode, bool HasTmpRegOperand); /// Helper for processing MC instructions that have been successfully matched /// by MatchAndEmitInstruction. Modifications to the emitted instructions, @@ -1408,42 +1410,59 @@ } } -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(MCInst &Inst, SMLoc IDLoc, + MCStreamer &Out, unsigned Opcode, + bool HasTmpRegOperand) { + // The store pseudo-instruction does a pc-relative store with + // a symbol. + // + // The expansion looks like this + // + // TmpLabel: AUIPC tmp, %pcrel_hi(symbol) + // Opcode rd, %pcrel_lo(TmpLabel)(tmp) + MCOperand DestReg = Inst.getOperand(0); + MCOperand TmpReg; + const MCExpr *Symbol; MCContext &Ctx = getContext(); + if (HasTmpRegOperand) { + TmpReg = Inst.getOperand(1); + Symbol = Inst.getOperand(2).getExpr(); + } else { + TmpReg = Inst.getOperand(0); + Symbol = Inst.getOperand(1).getExpr(); + } + 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 *SymbolExpr = RISCVMCExpr::create( + Symbol, RISCVMCExpr::VK_RISCV_PCREL_HI, Ctx); + emitToStreamer( - Out, MCInstBuilder(RISCV::AUIPC).addOperand(DestReg).addExpr(Symbol)); + Out, MCInstBuilder(RISCV::AUIPC).addOperand(TmpReg).addExpr(SymbolExpr)); 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(Opcode) .addOperand(DestReg) + .addOperand(TmpReg) .addExpr(RefToLinkTmpLabel)); + } 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()) { @@ -1463,8 +1482,54 @@ Imm = SignExtend64<32>(Imm); emitLoadImm(Reg, Imm, Out); return false; - } else if (Inst.getOpcode() == RISCV::PseudoLLA) { - emitLoadLocalAddress(Inst, IDLoc, Out); + } + case RISCV::PseudoLLA: + emitAuipcInstPair(Inst, IDLoc, Out, RISCV::ADDI, false); + return false; + case RISCV::PseudoLB: + emitAuipcInstPair(Inst, IDLoc, Out, RISCV::LB, false); + return false; + case RISCV::PseudoLBU: + emitAuipcInstPair(Inst, IDLoc, Out, RISCV::LBU, false); + return false; + case RISCV::PseudoLH: + emitAuipcInstPair(Inst, IDLoc, Out, RISCV::LH, false); + return false; + case RISCV::PseudoLHU: + emitAuipcInstPair(Inst, IDLoc, Out, RISCV::LHU, false); + return false; + case RISCV::PseudoLW: + emitAuipcInstPair(Inst, IDLoc, Out, RISCV::LW, false); + return false; + case RISCV::PseudoLWU: + emitAuipcInstPair(Inst, IDLoc, Out, RISCV::LWU, false); + return false; + case RISCV::PseudoLD: + emitAuipcInstPair(Inst, IDLoc, Out, RISCV::LD, false); + return false; + case RISCV::PseudoFLW: + emitAuipcInstPair(Inst, IDLoc, Out, RISCV::FLW, true); + return false; + case RISCV::PseudoFLD: + emitAuipcInstPair(Inst, IDLoc, Out, RISCV::FLD, true); + return false; + case RISCV::PseudoSB: + emitAuipcInstPair(Inst, IDLoc, Out, RISCV::SB, true); + return false; + case RISCV::PseudoSH: + emitAuipcInstPair(Inst, IDLoc, Out, RISCV::SH, true); + return false; + case RISCV::PseudoSW: + emitAuipcInstPair(Inst, IDLoc, Out, RISCV::SW, true); + return false; + case RISCV::PseudoSD: + emitAuipcInstPair(Inst, IDLoc, Out, RISCV::SD, true); + return false; + case RISCV::PseudoFSW: + emitAuipcInstPair(Inst, IDLoc, Out, RISCV::FSW, true); + return false; + case RISCV::PseudoFSD: + emitAuipcInstPair(Inst, IDLoc, Out, RISCV::FSD, true); return false; } Index: lib/Target/RISCV/RISCVInstrFormats.td =================================================================== --- lib/Target/RISCV/RISCVInstrFormats.td +++ lib/Target/RISCV/RISCVInstrFormats.td @@ -109,6 +109,35 @@ let isCodeGenOnly = 1; } +// Pseudo load instructions. +class PseudoLoad + : 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 + : 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 + : 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. Index: lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.td +++ lib/Target/RISCV/RISCVInstrInfo.td @@ -11,8 +11,6 @@ // //===----------------------------------------------------------------------===// -include "RISCVInstrFormats.td" - //===----------------------------------------------------------------------===// // RISC-V specific DAG Nodes. //===----------------------------------------------------------------------===// @@ -234,6 +232,12 @@ }]>; //===----------------------------------------------------------------------===// +// Instruction Formats +//===----------------------------------------------------------------------===// + +include "RISCVInstrFormats.td" + +//===----------------------------------------------------------------------===// // Instruction Class Templates //===----------------------------------------------------------------------===// @@ -486,10 +490,6 @@ //===----------------------------------------------------------------------===// // TODO la -// TODO lb lh lw -// TODO RV64I: ld -// TODO sb sh sw -// TODO RV64I: sd def : InstAlias<"nop", (ADDI X0, X0, 0)>; @@ -502,6 +502,22 @@ 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)>; Index: lib/Target/RISCV/RISCVInstrInfoD.td =================================================================== --- lib/Target/RISCV/RISCVInstrInfoD.td +++ lib/Target/RISCV/RISCVInstrInfoD.td @@ -179,9 +179,6 @@ //===----------------------------------------------------------------------===// 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)>; @@ -192,6 +189,9 @@ (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] //===----------------------------------------------------------------------===// Index: lib/Target/RISCV/RISCVInstrInfoF.td =================================================================== --- lib/Target/RISCV/RISCVInstrInfoF.td +++ lib/Target/RISCV/RISCVInstrInfoF.td @@ -193,9 +193,6 @@ //===----------------------------------------------------------------------===// 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)>; @@ -231,6 +228,9 @@ // 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] //===----------------------------------------------------------------------===// Index: test/MC/RISCV/rv32d-invalid.s =================================================================== --- test/MC/RISCV/rv32d-invalid.s +++ test/MC/RISCV/rv32d-invalid.s @@ -6,8 +6,8 @@ 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 Index: test/MC/RISCV/rv32f-invalid.s =================================================================== --- test/MC/RISCV/rv32f-invalid.s +++ test/MC/RISCV/rv32f-invalid.s @@ -6,8 +6,8 @@ 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 Index: test/MC/RISCV/rv32i-invalid.s =================================================================== --- test/MC/RISCV/rv32i-invalid.s +++ test/MC/RISCV/rv32i-invalid.s @@ -158,7 +158,7 @@ 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 Index: test/MC/RISCV/rv64i-pseudos.s =================================================================== --- /dev/null +++ test/MC/RISCV/rv64i-pseudos.s @@ -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 Index: test/MC/RISCV/rvd-pseudos.s =================================================================== --- /dev/null +++ test/MC/RISCV/rvd-pseudos.s @@ -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 Index: test/MC/RISCV/rvf-pseudos.s =================================================================== --- /dev/null +++ test/MC/RISCV/rvf-pseudos.s @@ -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 Index: test/MC/RISCV/rvi-pseudos-invalid.s =================================================================== --- /dev/null +++ test/MC/RISCV/rvi-pseudos-invalid.s @@ -0,0 +1,10 @@ +# RUN: not llvm-mc -triple=riscv32 < %s 2>&1 | FileCheck %s +# RUN: not llvm-mc -triple=riscv64 < %s 2>&1 | FileCheck %s + +# Non bare symbols must be rejected +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 fwe operands must be rejected +sw a2, a_symbol # CHECK: :[[@LINE]]:1: error: too few operands for instruction Index: test/MC/RISCV/rvi-pseudos.s =================================================================== --- test/MC/RISCV/rvi-pseudos.s +++ test/MC/RISCV/rvi-pseudos.s @@ -26,3 +26,49 @@ # CHECK: auipc a4, %pcrel_hi(f1) # CHECK: addi a4, a4, %pcrel_lo(.Lpcrel_hi4) lla a4, f1 + +# CHECK: .Lpcrel_hi5: +# CHECK: auipc a0, %pcrel_hi(a_symbol) +# CHECK: lb a0, %pcrel_lo(.Lpcrel_hi5)(a0) +lb a0, a_symbol + +# CHECK: .Lpcrel_hi6: +# CHECK: auipc a1, %pcrel_hi(a_symbol) +# CHECK: lh a1, %pcrel_lo(.Lpcrel_hi6)(a1) +lh a1, a_symbol + +# CHECK: .Lpcrel_hi7: +# CHECK: auipc a2, %pcrel_hi(a_symbol) +# CHECK: lhu a2, %pcrel_lo(.Lpcrel_hi7)(a2) +lhu a2, a_symbol + +# CHECK: .Lpcrel_hi8: +# CHECK: auipc a3, %pcrel_hi(a_symbol) +# CHECK: lw a3, %pcrel_lo(.Lpcrel_hi8)(a3) +lw a3, a_symbol + +# CHECK: .Lpcrel_hi9: +# CHECK: auipc a4, %pcrel_hi(a_symbol) +# CHECK: sb a3, %pcrel_lo(.Lpcrel_hi9)(a4) +sb a3, a_symbol, a4 + +# CHECK: .Lpcrel_hi10: +# CHECK: auipc a4, %pcrel_hi(a_symbol) +# CHECK: sh a3, %pcrel_lo(.Lpcrel_hi10)(a4) +sh a3, a_symbol, a4 + +# CHECK: .Lpcrel_hi11: +# CHECK: auipc a4, %pcrel_hi(a_symbol) +# CHECK: sw a3, %pcrel_lo(.Lpcrel_hi11)(a4) +sw a3, a_symbol, a4 + +# Check that we can load the address of symbols that are spelled like a register +# CHECK: .Lpcrel_hi12: +# CHECK: auipc a2, %pcrel_hi(zero) +# CHECK: lw a2, %pcrel_lo(.Lpcrel_hi12)(a2) +lw a2, zero + +# CHECK: .Lpcrel_hi13: +# CHECK: auipc a4, %pcrel_hi(zero) +# CHECK: sw a3, %pcrel_lo(.Lpcrel_hi13)(a4) +sw a3, zero, a4