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");
// 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);
// 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;
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
# 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