Index: lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -23,6 +23,15 @@ ~RISCVELFObjectWriter() override; + // Return true to preserve the symbols with relocations instead of 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 @@ 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; } } Index: lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h +++ lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -47,6 +47,9 @@ // 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 of an adjacent jalr pair. + fixup_riscv_call, // fixup_riscv_invalid - used as a sentinel and a marker, must be last fixup fixup_riscv_invalid, Index: lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -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 @@ SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const override; + void expandFunctionCall(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &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,39 @@ return new RISCVMCCodeEmitter(Ctx, MCII); } +// Expand PseudoCALL to AUIPC and JALR with relocation types. +void RISCVMCCodeEmitter::expandFunctionCall(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + MCInst TmpInst; + MCOperand Func = MI.getOperand(0); + unsigned Ra = RISCV::X1; + uint32_t Binary; + + assert(Func.isExpr()); + + 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(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(OS).write(Binary); +} + void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { @@ -87,6 +125,12 @@ // 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 +227,9 @@ 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(Expr)->getKind() == MCSymbolRefExpr::VK_None) { Index: lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h +++ lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h @@ -29,6 +29,7 @@ VK_RISCV_HI, VK_RISCV_PCREL_LO, VK_RISCV_PCREL_HI, + VK_RISCV_CALL, VK_RISCV_Invalid }; Index: lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -32,7 +32,8 @@ } 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 @@ 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)) Index: lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.td +++ lib/Target/RISCV/RISCVInstrInfo.td @@ -620,9 +620,20 @@ 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 simm21_lsb0:$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)]>, Index: test/MC/RISCV/function-call.s =================================================================== --- /dev/null +++ test/MC/RISCV/function-call.s @@ -0,0 +1,11 @@ +# 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 + +.long foo + +call foo +# RELOC: R_RISCV_CALL foo 0x0 +# INSTR: auipc ra, 0 +# INSTR: jalr ra