Index: lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -1219,6 +1219,10 @@ 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: lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -88,19 +88,29 @@ 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 &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 @@ // 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 @@ // 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: lib/Target/RISCV/RISCVInstrInfo.cpp =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.cpp +++ lib/Target/RISCV/RISCVInstrInfo.cpp @@ -436,6 +436,7 @@ case TargetOpcode::KILL: case TargetOpcode::DBG_VALUE: return 0; + case RISCV::PseudoCALLReg: case RISCV::PseudoCALL: case RISCV::PseudoTAIL: case RISCV::PseudoLLA: Index: lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.td +++ lib/Target/RISCV/RISCVInstrInfo.td @@ -870,6 +870,17 @@ 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: test/MC/RISCV/function-call-invalid.s =================================================================== --- test/MC/RISCV/function-call-invalid.s +++ test/MC/RISCV/function-call-invalid.s @@ -9,3 +9,4 @@ 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 \ No newline at end of file Index: test/MC/RISCV/function-call.s =================================================================== --- test/MC/RISCV/function-call.s +++ test/MC/RISCV/function-call.s @@ -51,3 +51,17 @@ # 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