Index: llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -91,6 +91,10 @@ // 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 @@ 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(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 @@ 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 @@ 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); Index: llvm/trunk/lib/Target/RISCV/RISCVInstrFormats.td =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVInstrFormats.td +++ llvm/trunk/lib/Target/RISCV/RISCVInstrFormats.td @@ -108,6 +108,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: llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td +++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td @@ -10,8 +10,6 @@ // //===----------------------------------------------------------------------===// -include "RISCVInstrFormats.td" - //===----------------------------------------------------------------------===// // RISC-V specific DAG Nodes. //===----------------------------------------------------------------------===// @@ -241,6 +239,12 @@ }]>; //===----------------------------------------------------------------------===// +// Instruction Formats +//===----------------------------------------------------------------------===// + +include "RISCVInstrFormats.td" + +//===----------------------------------------------------------------------===// // Instruction Class Templates //===----------------------------------------------------------------------===// @@ -497,11 +501,6 @@ // 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 @@ 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: llvm/trunk/lib/Target/RISCV/RISCVInstrInfoD.td =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVInstrInfoD.td +++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfoD.td @@ -178,9 +178,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)>; @@ -191,6 +188,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: llvm/trunk/lib/Target/RISCV/RISCVInstrInfoF.td =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVInstrInfoF.td +++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfoF.td @@ -206,9 +206,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)>; @@ -244,6 +241,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: llvm/trunk/test/MC/RISCV/rv32d-invalid.s =================================================================== --- llvm/trunk/test/MC/RISCV/rv32d-invalid.s +++ llvm/trunk/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: llvm/trunk/test/MC/RISCV/rv32f-invalid.s =================================================================== --- llvm/trunk/test/MC/RISCV/rv32f-invalid.s +++ llvm/trunk/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: llvm/trunk/test/MC/RISCV/rv32i-invalid.s =================================================================== --- llvm/trunk/test/MC/RISCV/rv32i-invalid.s +++ llvm/trunk/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: llvm/trunk/test/MC/RISCV/rv64i-pseudos.s =================================================================== --- llvm/trunk/test/MC/RISCV/rv64i-pseudos.s +++ llvm/trunk/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: llvm/trunk/test/MC/RISCV/rvd-pseudos.s =================================================================== --- llvm/trunk/test/MC/RISCV/rvd-pseudos.s +++ llvm/trunk/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: llvm/trunk/test/MC/RISCV/rvf-pseudos.s =================================================================== --- llvm/trunk/test/MC/RISCV/rvf-pseudos.s +++ llvm/trunk/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: llvm/trunk/test/MC/RISCV/rvi-pseudos-invalid.s =================================================================== --- llvm/trunk/test/MC/RISCV/rvi-pseudos-invalid.s +++ llvm/trunk/test/MC/RISCV/rvi-pseudos-invalid.s @@ -20,3 +20,10 @@ 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 Index: llvm/trunk/test/MC/RISCV/rvi-pseudos.s =================================================================== --- llvm/trunk/test/MC/RISCV/rvi-pseudos.s +++ llvm/trunk/test/MC/RISCV/rvi-pseudos.s @@ -71,3 +71,49 @@ # 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