diff options
| -rw-r--r-- | llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp | 67 | ||||
| -rw-r--r-- | llvm/lib/Target/RISCV/RISCVInstrInfo.td | 5 | ||||
| -rw-r--r-- | llvm/test/MC/RISCV/lla-invalid.s | 6 | ||||
| -rw-r--r-- | llvm/test/MC/RISCV/rvi-pseudos.s | 28 | 
4 files changed, 103 insertions, 3 deletions
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index 9a455c10548..5a56ddf0656 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -73,6 +73,9 @@ class RISCVAsmParser : public MCTargetAsmParser {    // 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 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 @@ -964,6 +967,26 @@ bool RISCVAsmParser::parseOperand(OperandVector &Operands,    return true;  } +/// Return true if the operand at the OperandIdx for opcode Name should be +/// 'forced' to be parsed as an immediate. This is required for +/// pseudoinstructions such as tail or call, which allow bare symbols to be used +/// that could clash with register names. +static bool shouldForceImediateOperand(StringRef Name, unsigned OperandIdx) { +  // FIXME: This may not scale so perhaps we want to use a data-driven approach +  // instead. +  switch (OperandIdx) { +  case 0: +    // call imm +    // tail imm +    return Name == "tail" || Name == "call"; +  case 1: +    // lla rdest, imm +    return Name == "lla"; +  default: +    return false; +  } +} +  bool RISCVAsmParser::ParseInstruction(ParseInstructionInfo &Info,                                        StringRef Name, SMLoc NameLoc,                                        OperandVector &Operands) { @@ -975,18 +998,20 @@ bool RISCVAsmParser::ParseInstruction(ParseInstructionInfo &Info,      return false;    // Parse first operand -  bool ForceImmediate = (Name == "call" || Name == "tail"); -  if (parseOperand(Operands, ForceImmediate)) +  if (parseOperand(Operands, shouldForceImediateOperand(Name, 0)))      return true;    // Parse until end of statement, consuming commas between operands +  unsigned OperandIdx = 1;    while (getLexer().is(AsmToken::Comma)) {      // Consume comma token      getLexer().Lex();      // Parse next operand -    if (parseOperand(Operands, false)) +    if (parseOperand(Operands, shouldForceImediateOperand(Name, OperandIdx)))        return true; + +    ++OperandIdx;    }    if (getLexer().isNot(AsmToken::EndOfStatement)) { @@ -1184,6 +1209,39 @@ void RISCVAsmParser::emitLoadImm(unsigned DestReg, int64_t Value,                              .addImm(Lo12));  } +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) +  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); + +  MCInst &AUIPC = +      MCInstBuilder(RISCV::AUIPC).addOperand(DestReg).addExpr(Symbol); +  emitToStreamer(Out, AUIPC); + +  const MCExpr *RefToLinkTmpLabel = +      RISCVMCExpr::create(MCSymbolRefExpr::create(TmpLabel, Ctx), +                          RISCVMCExpr::VK_RISCV_PCREL_LO, Ctx); + +  MCInst &ADDI = MCInstBuilder(RISCV::ADDI) +                     .addOperand(DestReg) +                     .addOperand(DestReg) +                     .addExpr(RefToLinkTmpLabel); +  emitToStreamer(Out, ADDI); +} +  bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,                                          MCStreamer &Out) {    Inst.setLoc(IDLoc); @@ -1198,6 +1256,9 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,        Imm = SignExtend64<32>(Imm);      emitLoadImm(Reg, Imm, Out);      return false; +  } else if (Inst.getOpcode() == RISCV::PseudoLLA) { +    emitLoadLocalAddress(Inst, IDLoc, Out); +    return false;    }    emitToStreamer(Out, Inst); diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index dd19e31d7ca..1dc60737a16 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -759,6 +759,11 @@ def : Pat<(Tail (iPTR tglobaladdr:$dst)),  def : Pat<(Tail (iPTR texternalsym:$dst)),            (PseudoTAIL texternalsym:$dst)>; +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 0, +    isAsmParserOnly = 1 in +def PseudoLLA : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [], +                       "lla", "$dst, $src">; +  /// Loads  multiclass LdPat<PatFrag LoadOp, RVInst Inst> { diff --git a/llvm/test/MC/RISCV/lla-invalid.s b/llvm/test/MC/RISCV/lla-invalid.s new file mode 100644 index 00000000000..bd99bfd83ca --- /dev/null +++ b/llvm/test/MC/RISCV/lla-invalid.s @@ -0,0 +1,6 @@ +# 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 +lla a2, %lo(a_symbol) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name +lla a2, %hi(a_symbol) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name diff --git a/llvm/test/MC/RISCV/rvi-pseudos.s b/llvm/test/MC/RISCV/rvi-pseudos.s new file mode 100644 index 00000000000..b93e6f79ef6 --- /dev/null +++ b/llvm/test/MC/RISCV/rvi-pseudos.s @@ -0,0 +1,28 @@ +# RUN: llvm-mc %s -triple=riscv32 | FileCheck %s +# RUN: llvm-mc %s -triple=riscv64 | FileCheck %s + +# CHECK: .Lpcrel_hi0: +# CHECK: auipc a0, %pcrel_hi(a_symbol) +# CHECK: addi  a0, a0, %pcrel_lo(.Lpcrel_hi0) +lla a0, a_symbol + +# CHECK: .Lpcrel_hi1: +# CHECK: auipc a1, %pcrel_hi(another_symbol) +# CHECK: addi  a1, a1, %pcrel_lo(.Lpcrel_hi1) +lla a1, another_symbol + +# Check that we can load the address of symbols that are spelled like a register +# CHECK: .Lpcrel_hi2: +# CHECK: auipc a2, %pcrel_hi(zero) +# CHECK: addi  a2, a2, %pcrel_lo(.Lpcrel_hi2) +lla a2, zero + +# CHECK: .Lpcrel_hi3: +# CHECK: auipc a3, %pcrel_hi(ra) +# CHECK: addi  a3, a3, %pcrel_lo(.Lpcrel_hi3) +lla a3, ra + +# CHECK: .Lpcrel_hi4: +# CHECK: auipc a4, %pcrel_hi(f1) +# CHECK: addi  a4, a4, %pcrel_lo(.Lpcrel_hi4) +lla a4, f1  | 

