[llvm] r330826 - [RISCV] Support "call" pseudoinstruction in the MC layer

Shiva Chen via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 25 07:18:56 PDT 2018


Author: shiva
Date: Wed Apr 25 07:18:55 2018
New Revision: 330826

URL: http://llvm.org/viewvc/llvm-project?rev=330826&view=rev
Log:
[RISCV] Support "call" pseudoinstruction in the MC layer

To do this:
1. Add PseudoCALLIndirct to match indirect function call.

2. Add PseudoCALL to support parsing and print pseudo `call` in assembly

3. Expand PseudoCALL to the following form with R_RISCV_CALL relocation type
   while encoding:
        auipc ra, func
        jalr ra, ra, 0

If we expand PseudoCALL before emitting assembly, we will see auipc and jalr
pair when compile with -S. It's hard for assembly parser to parsing this
pair and identify it's semantic is function call and then insert R_RISCV_CALL
relocation type. Although we could insert R_RISCV_PCREL_HI20 and
R_RISCV_PCREL_LO12_I relocation types instead of R_RISCV_CALL.
Due to RISCV relocation design, auipc and jalr pair only can relax to jal with
R_RISCV_CALL + R_RISCV_RELAX relocation types.

We expand PseudoCALL as late as encoding(RISCVMCCodeEmitter) instead of before
emitting assembly(RISCVAsmPrinter) because we want to preserve call
pseudoinstruction in assembly code. It's more readable and assembly parser
could identify call assembly and insert R_RISCV_CALL relocation type.

Differential Revision: https://reviews.llvm.org/D45859

Added:
    llvm/trunk/test/MC/RISCV/function-call-invalid.s
    llvm/trunk/test/MC/RISCV/function-call.s
Modified:
    llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
    llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
    llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
    llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
    llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
    llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
    llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td

Modified: llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp?rev=330826&r1=330825&r2=330826&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp Wed Apr 25 07:18:55 2018
@@ -171,6 +171,16 @@ public:
 
   // Predicate methods for AsmOperands defined in RISCVInstrInfo.td
 
+  bool isBareSymbol() const {
+    int64_t Imm;
+    RISCVMCExpr::VariantKind VK;
+    // Must be of 'immediate' type but not a constant.
+    if (!isImm() || evaluateConstantImm(Imm, VK))
+      return false;
+    return RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm) &&
+           VK == RISCVMCExpr::VK_RISCV_None;
+  }
+
   /// Return true if the operand is a valid for the fence instruction e.g.
   /// ('iorw').
   bool isFenceArg() const {
@@ -703,6 +713,10 @@ bool RISCVAsmParser::MatchAndEmitInstruc
         ErrorLoc,
         "operand must be a valid floating point rounding mode mnemonic");
   }
+  case Match_InvalidBareSymbol: {
+    SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
+    return Error(ErrorLoc, "operand must be a bare symbol name");
+  }
   }
 
   llvm_unreachable("Unknown match type detected!");

Modified: llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp?rev=330826&r1=330825&r2=330826&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp Wed Apr 25 07:18:55 2018
@@ -23,6 +23,15 @@ public:
 
   ~RISCVELFObjectWriter() override;
 
+  // Return true if the given relocation must be with a symbol rather than
+  // section plus offset.
+  bool needsRelocateWithSymbol(const MCSymbol &Sym,
+                               unsigned Type) const override {
+    // TODO: this is very conservative, update once RISC-V psABI requirements
+    //       are clarified.
+    return true;
+  }
+
 protected:
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
@@ -67,6 +76,8 @@ unsigned RISCVELFObjectWriter::getRelocT
     return ELF::R_RISCV_RVC_JUMP;
   case RISCV::fixup_riscv_rvc_branch:
     return ELF::R_RISCV_RVC_BRANCH;
+  case RISCV::fixup_riscv_call:
+    return ELF::R_RISCV_CALL;
   }
 }
 

Modified: llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h?rev=330826&r1=330825&r2=330826&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h (original)
+++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h Wed Apr 25 07:18:55 2018
@@ -47,6 +47,9 @@ enum Fixups {
   // fixup_riscv_rvc_branch - 8-bit fixup for symbol references in the
   // compressed branch instruction
   fixup_riscv_rvc_branch,
+  // fixup_riscv_call - A fixup representing a call attached to the auipc
+  // instruction in a pair composed of adjacent auipc+jalr instructions.
+  fixup_riscv_call,
 
   // fixup_riscv_invalid - used as a sentinel and a marker, must be last fixup
   fixup_riscv_invalid,

Modified: llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp?rev=330826&r1=330825&r2=330826&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp Wed Apr 25 07:18:55 2018
@@ -21,6 +21,7 @@
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstBuilder.h"
 #include "llvm/MC/MCInstrInfo.h"
 #include "llvm/MC/MCRegisterInfo.h"
 #include "llvm/MC/MCSymbol.h"
@@ -52,6 +53,10 @@ public:
                          SmallVectorImpl<MCFixup> &Fixups,
                          const MCSubtargetInfo &STI) const override;
 
+  void expandFunctionCall(const MCInst &MI, raw_ostream &OS,
+                          SmallVectorImpl<MCFixup> &Fixups,
+                          const MCSubtargetInfo &STI) const;
+
   /// TableGen'erated function for getting the binary encoding for an
   /// instruction.
   uint64_t getBinaryCodeForInstr(const MCInst &MI,
@@ -80,6 +85,42 @@ MCCodeEmitter *llvm::createRISCVMCCodeEm
   return new RISCVMCCodeEmitter(Ctx, MCII);
 }
 
+// Expand PseudoCALL to AUIPC and JALR with relocation types.
+// We expand PseudoCALL while encoding, meaning AUIPC and JALR won't go through
+// RISCV MC to MC compressed instruction transformation. This is acceptable
+// because AUIPC has no 16-bit form and C_JALR have no immediate operand field.
+// We let linker relaxation deal with it. When linker relaxation enabled,
+// AUIPC and JALR have chance relax to JAL. If C extension is enabled,
+// JAL has chance relax to C_JAL.
+void RISCVMCCodeEmitter::expandFunctionCall(const MCInst &MI, raw_ostream &OS,
+                                            SmallVectorImpl<MCFixup> &Fixups,
+                                            const MCSubtargetInfo &STI) const {
+  MCInst TmpInst;
+  MCOperand Func = MI.getOperand(0);
+  unsigned Ra = RISCV::X1;
+  uint32_t Binary;
+
+  assert(Func.isExpr() && "Expected expression");
+
+  const MCExpr *Expr = Func.getExpr();
+
+  // Create function call expression CallExpr for AUIPC.
+  const MCExpr *CallExpr =
+      RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_CALL, Ctx);
+
+  // Emit AUIPC Ra, Func with R_RISCV_CALL relocation type.
+  TmpInst = MCInstBuilder(RISCV::AUIPC)
+                .addReg(Ra)
+                .addOperand(MCOperand::createExpr(CallExpr));
+  Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);
+  support::endian::Writer<support::little>(OS).write(Binary);
+
+  // Emit JALR Ra, Ra, 0
+  TmpInst = MCInstBuilder(RISCV::JALR).addReg(Ra).addReg(Ra).addImm(0);
+  Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);
+  support::endian::Writer<support::little>(OS).write(Binary);
+}
+
 void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
                                            SmallVectorImpl<MCFixup> &Fixups,
                                            const MCSubtargetInfo &STI) const {
@@ -87,6 +128,12 @@ void RISCVMCCodeEmitter::encodeInstructi
   // Get byte count of instruction.
   unsigned Size = Desc.getSize();
 
+  if (MI.getOpcode() == RISCV::PseudoCALL) {
+    expandFunctionCall(MI, OS, Fixups, STI);
+    MCNumEmitted += 2;
+    return;
+  }
+
   switch (Size) {
   default:
     llvm_unreachable("Unhandled encodeInstruction length!");
@@ -183,6 +230,9 @@ unsigned RISCVMCCodeEmitter::getImmOpVal
     case RISCVMCExpr::VK_RISCV_PCREL_HI:
       FixupKind = RISCV::fixup_riscv_pcrel_hi20;
       break;
+    case RISCVMCExpr::VK_RISCV_CALL:
+      FixupKind = RISCV::fixup_riscv_call;
+      break;
     }
   } else if (Kind == MCExpr::SymbolRef &&
              cast<MCSymbolRefExpr>(Expr)->getKind() == MCSymbolRefExpr::VK_None) {

Modified: llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp?rev=330826&r1=330825&r2=330826&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp Wed Apr 25 07:18:55 2018
@@ -32,7 +32,8 @@ const RISCVMCExpr *RISCVMCExpr::create(c
 }
 
 void RISCVMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
-  bool HasVariant = getKind() != VK_RISCV_None;
+  bool HasVariant =
+      ((getKind() != VK_RISCV_None) && (getKind() != VK_RISCV_CALL));
   if (HasVariant)
     OS << '%' << getVariantKindName(getKind()) << '(';
   Expr->print(OS, MAI);
@@ -77,7 +78,8 @@ StringRef RISCVMCExpr::getVariantKindNam
 bool RISCVMCExpr::evaluateAsConstant(int64_t &Res) const {
   MCValue Value;
 
-  if (Kind == VK_RISCV_PCREL_HI || Kind == VK_RISCV_PCREL_LO)
+  if (Kind == VK_RISCV_PCREL_HI || Kind == VK_RISCV_PCREL_LO ||
+      Kind == VK_RISCV_CALL)
     return false;
 
   if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr))

Modified: llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h?rev=330826&r1=330825&r2=330826&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h (original)
+++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h Wed Apr 25 07:18:55 2018
@@ -29,6 +29,7 @@ public:
     VK_RISCV_HI,
     VK_RISCV_PCREL_LO,
     VK_RISCV_PCREL_HI,
+    VK_RISCV_CALL,
     VK_RISCV_Invalid
   };
 

Modified: llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td?rev=330826&r1=330825&r2=330826&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td Wed Apr 25 07:18:55 2018
@@ -153,6 +153,20 @@ def simm21_lsb0 : Operand<OtherVT> {
   }];
 }
 
+def BareSymbol : AsmOperandClass {
+  let Name = "BareSymbol";
+  let RenderMethod = "addImmOperands";
+  let DiagnosticType = "InvalidBareSymbol";
+}
+
+// A bare symbol.
+def bare_symbol : Operand<XLenVT> {
+  let ParserMatchClass = BareSymbol;
+  let MCOperandPredicate = [{
+     return MCOp.isBareSymbolRef();
+  }];
+}
+
 // A parameterized register class alternative to i32imm/i64imm from Target.td.
 def ixlenimm : Operand<XLenVT>;
 
@@ -621,9 +635,20 @@ def : Pat<(brind GPR:$rs1), (PseudoBRIND
 def : Pat<(brind (add GPR:$rs1, simm12:$imm12)),
           (PseudoBRIND GPR:$rs1, simm12:$imm12)>;
 
+// PseudoCALL is a pseudo instruction which will eventually expand to auipc
+// and jalr. Define AsmString because we want assembler could print "call"
+// when compile with -S. Define isCodeGenOnly = 0 because we want parser
+// could parsing assembly "call" instruction.
+let isCall = 1, Defs = [X1], isCodeGenOnly = 0,
+    hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
+def PseudoCALL : Pseudo<(outs), (ins bare_symbol:$func),
+                        []> {
+  let AsmString = "call\t$func";
+}
+
 let isCall = 1, Defs = [X1] in
-def PseudoCALL : Pseudo<(outs), (ins GPR:$rs1), [(Call GPR:$rs1)]>,
-                 PseudoInstExpansion<(JALR X1, GPR:$rs1, 0)>;
+def PseudoCALLIndirect : Pseudo<(outs), (ins GPR:$rs1), [(Call GPR:$rs1)]>,
+                         PseudoInstExpansion<(JALR X1, GPR:$rs1, 0)>;
 
 let isBarrier = 1, isReturn = 1, isTerminator = 1 in
 def PseudoRET : Pseudo<(outs), (ins), [(RetFlag)]>,

Added: llvm/trunk/test/MC/RISCV/function-call-invalid.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/function-call-invalid.s?rev=330826&view=auto
==============================================================================
--- llvm/trunk/test/MC/RISCV/function-call-invalid.s (added)
+++ llvm/trunk/test/MC/RISCV/function-call-invalid.s Wed Apr 25 07:18:55 2018
@@ -0,0 +1,11 @@
+# RUN: not llvm-mc -triple riscv32 < %s 2>&1 | FileCheck %s
+
+call 1234 # CHECK: :[[@LINE]]:6: error: operand must be a bare symbol name
+call %pcrel_hi(1234) # CHECK: :[[@LINE]]:6: error: operand must be a bare symbol name
+call %pcrel_lo(1234) # CHECK: :[[@LINE]]:6: error: operand must be a bare symbol name
+call %pcrel_hi(foo) # CHECK: :[[@LINE]]:6: error: operand must be a bare symbol name
+call %pcrel_lo(foo) # CHECK: :[[@LINE]]:6: error: operand must be a bare symbol name
+call %hi(1234) # CHECK: :[[@LINE]]:6: error: operand must be a bare symbol name
+call %lo(1234) # CHECK: :[[@LINE]]:6: error: operand must be a bare symbol name
+call %hi(foo) # CHECK: :[[@LINE]]:6: error: operand must be a bare symbol name
+call %lo(foo) # CHECK: :[[@LINE]]:6: error: operand must be a bare symbol name

Added: llvm/trunk/test/MC/RISCV/function-call.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/function-call.s?rev=330826&view=auto
==============================================================================
--- llvm/trunk/test/MC/RISCV/function-call.s (added)
+++ llvm/trunk/test/MC/RISCV/function-call.s Wed Apr 25 07:18:55 2018
@@ -0,0 +1,19 @@
+# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \
+# RUN:     | llvm-objdump -d - | FileCheck -check-prefix=INSTR %s
+# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \
+# RUN:     | llvm-readobj -r | FileCheck -check-prefix=RELOC %s
+# RUN: llvm-mc -triple riscv32 < %s -show-encoding \
+# RUN:     | FileCheck -check-prefix=FIXUP %s
+
+.long foo
+
+call foo
+# RELOC: R_RISCV_CALL foo 0x0
+# INSTR: auipc ra, 0
+# INSTR: jalr  ra
+# FIXUP: fixup A - offset: 0, value: foo, kind:
+call bar
+# RELOC: R_RISCV_CALL bar 0x0
+# INSTR: auipc ra, 0
+# INSTR: jalr  ra
+# FIXUP: fixup A - offset: 0, value: bar, kind:




More information about the llvm-commits mailing list