]> granicus.if.org Git - llvm/commitdiff
[RISCV] Add pseudo instruction for calls with explicit register
authorLewis Revill <lewis.revill@embecosm.com>
Wed, 26 Jun 2019 10:35:58 +0000 (10:35 +0000)
committerLewis Revill <lewis.revill@embecosm.com>
Wed, 26 Jun 2019 10:35:58 +0000 (10:35 +0000)
This patch adds the PseudoCALLReg instruction which allows using an
explicit register operand as the destination for the return address.

GCC can successfully parse this form of the call instruction, which
would be used for calls to functions which do not use ra as the return
address register, such as the __riscv_save libcalls. This patch forms
the first part of an implementation of -msave-restore for RISC-V.

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@364403 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
lib/Target/RISCV/RISCVInstrInfo.cpp
lib/Target/RISCV/RISCVInstrInfo.td
test/MC/RISCV/function-call-invalid.s
test/MC/RISCV/function-call.s

index f79cbd7fb6bad3ec253a65359e812d26269062ba..b4d206db54c2d01ecedf462fbe1fdccf74888f56 100644 (file)
@@ -1219,6 +1219,10 @@ OperandMatchResultTy RISCVAsmParser::parseCallSymbol(OperandVector &Operands) {
   if (getLexer().getKind() != AsmToken::Identifier)
     return MatchOperand_NoMatch;
 
+  // Avoid parsing the register in `call rd, foo` as a call symbol.
+  if (getLexer().peekTok().getKind() != AsmToken::EndOfStatement)
+    return MatchOperand_NoMatch;
+
   StringRef Identifier;
   if (getParser().parseIdentifier(Identifier))
     return MatchOperand_ParseFail;
index 32e9f4e3a6c7b6bada2b54ee16f444a6325f04ab..0fc775f63ed45c28e2fc0149c715f93cb7bffe74 100644 (file)
@@ -88,19 +88,29 @@ MCCodeEmitter *llvm::createRISCVMCCodeEmitter(const MCInstrInfo &MCII,
   return new RISCVMCCodeEmitter(Ctx, MCII);
 }
 
-// Expand PseudoCALL and PseudoTAIL to AUIPC and JALR with relocation types.
-// We expand PseudoCALL and PseudoTAIL 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.
+// Expand PseudoCALL(Reg) and PseudoTAIL to AUIPC and JALR with relocation
+// types. We expand PseudoCALL(Reg) and PseudoTAIL 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 = (MI.getOpcode() == RISCV::PseudoTAIL) ? RISCV::X6 : RISCV::X1;
+  MCOperand Func;
+  unsigned Ra;
+  if (MI.getOpcode() == RISCV::PseudoTAIL) {
+    Func = MI.getOperand(0);
+    Ra = RISCV::X6;
+  } else if (MI.getOpcode() == RISCV::PseudoCALLReg) {
+    Func = MI.getOperand(1);
+    Ra = MI.getOperand(0).getReg();
+  } else {
+    Func = MI.getOperand(0);
+    Ra = RISCV::X1;
+  }
   uint32_t Binary;
 
   assert(Func.isExpr() && "Expected expression");
@@ -118,7 +128,7 @@ void RISCVMCCodeEmitter::expandFunctionCall(const MCInst &MI, raw_ostream &OS,
     // Emit JALR X0, X6, 0
     TmpInst = MCInstBuilder(RISCV::JALR).addReg(RISCV::X0).addReg(Ra).addImm(0);
   else
-    // Emit JALR X1, X1, 0
+    // Emit JALR Ra, Ra, 0
     TmpInst = MCInstBuilder(RISCV::JALR).addReg(Ra).addReg(Ra).addImm(0);
   Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);
   support::endian::write(OS, Binary, support::little);
@@ -169,7 +179,8 @@ void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
   // Get byte count of instruction.
   unsigned Size = Desc.getSize();
 
-  if (MI.getOpcode() == RISCV::PseudoCALL ||
+  if (MI.getOpcode() == RISCV::PseudoCALLReg ||
+      MI.getOpcode() == RISCV::PseudoCALL ||
       MI.getOpcode() == RISCV::PseudoTAIL) {
     expandFunctionCall(MI, OS, Fixups, STI);
     MCNumEmitted += 2;
index 9d1361b4df71d02a2f9ef61ed30f0340c19e37fd..2608906bb4308775c7c6d2ff249af85fdf273e0c 100644 (file)
@@ -436,6 +436,7 @@ unsigned RISCVInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
   case TargetOpcode::KILL:
   case TargetOpcode::DBG_VALUE:
     return 0;
+  case RISCV::PseudoCALLReg:
   case RISCV::PseudoCALL:
   case RISCV::PseudoTAIL:
   case RISCV::PseudoLLA:
index d7bcc21f3b49d2e23765df11cca1f005bbf53c6a..c181f3a3d05ff9d5a32e3e277a0b823fd28eff3d 100644 (file)
@@ -870,6 +870,17 @@ def : Pat<(brind GPR:$rs1), (PseudoBRIND GPR:$rs1, 0)>;
 def : Pat<(brind (add GPR:$rs1, simm12:$imm12)),
           (PseudoBRIND GPR:$rs1, simm12:$imm12)>;
 
+// PsuedoCALLReg is a generic pseudo instruction for calls which will eventually
+// expand to auipc and jalr while encoding, with any given register used as the
+// destination.
+// Define AsmString to print "call" when compile with -S flag.
+// Define isCodeGenOnly = 0 to support parsing assembly "call" instruction.
+let isCall = 1, isBarrier = 1, isCodeGenOnly = 0, hasSideEffects = 0,
+    mayStore = 0, mayLoad = 0 in
+def PseudoCALLReg : Pseudo<(outs GPR:$rd), (ins call_symbol:$func), []> {
+  let AsmString = "call\t$rd, $func";
+}
+
 // PseudoCALL is a pseudo instruction which will eventually expand to auipc
 // and jalr while encoding. This is desirable, as an auipc+jalr pair with
 // R_RISCV_CALL and R_RISCV_RELAX relocations can be be relaxed by the linker
index 14532495e3f8c685d86df8c6b3cb7f0af58708a5..2b7a85245880d7f5a087ab0ef1071b842d90cc0a 100644 (file)
@@ -9,3 +9,4 @@ 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
+call foo, bar # CHECK: :[[@LINE]]:6: error: operand must be a bare symbol name
index 6ee77b017465b1cc1f6b97a2403ceece030a0776..d63db714b41d5b915973e79b750a441d0e4689c0 100644 (file)
@@ -51,3 +51,17 @@ call foo@plt
 # INSTR: auipc ra, 0
 # INSTR: jalr  ra
 # FIXUP: fixup A - offset: 0, value: foo@plt, kind: fixup_riscv_call_plt
+
+# Ensure that an explicit register operand can be parsed.
+
+call a0, foo
+# RELOC: R_RISCV_CALL foo 0x0
+# INSTR: auipc a0, 0
+# INSTR: jalr  a0
+# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_call
+
+call a0, foo@plt
+# RELOC: R_RISCV_CALL_PLT foo 0x0
+# INSTR: auipc a0, 0
+# INSTR: jalr  a0
+# FIXUP: fixup A - offset: 0, value: foo@plt, kind: fixup_riscv_call_plt