diff options
Diffstat (limited to 'lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp')
-rw-r--r-- | lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp | 87 |
1 files changed, 82 insertions, 5 deletions
diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp index 641997e67e06..8a796a014b33 100644 --- a/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ b/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 @@ 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,46 @@ 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. +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; + 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::write(OS, Binary, support::little); + + if (MI.getOpcode() == RISCV::PseudoTAIL) + // Emit JALR X0, X6, 0 + TmpInst = MCInstBuilder(RISCV::JALR).addReg(RISCV::X0).addReg(Ra).addImm(0); + else + // Emit JALR X1, X1, 0 + TmpInst = MCInstBuilder(RISCV::JALR).addReg(Ra).addReg(Ra).addImm(0); + Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI); + support::endian::write(OS, Binary, support::little); +} + void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { @@ -87,17 +132,24 @@ void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, // Get byte count of instruction. unsigned Size = Desc.getSize(); + if (MI.getOpcode() == RISCV::PseudoCALL || + MI.getOpcode() == RISCV::PseudoTAIL) { + expandFunctionCall(MI, OS, Fixups, STI); + MCNumEmitted += 2; + return; + } + switch (Size) { default: llvm_unreachable("Unhandled encodeInstruction length!"); case 2: { uint16_t Bits = getBinaryCodeForInstr(MI, Fixups, STI); - support::endian::Writer<support::little>(OS).write<uint16_t>(Bits); + support::endian::write<uint16_t>(OS, Bits, support::little); break; } case 4: { uint32_t Bits = getBinaryCodeForInstr(MI, Fixups, STI); - support::endian::Writer<support::little>(OS).write(Bits); + support::endian::write(OS, Bits, support::little); break; } } @@ -138,7 +190,7 @@ RISCVMCCodeEmitter::getImmOpValueAsr1(const MCInst &MI, unsigned OpNo, unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { - + bool EnableRelax = STI.getFeatureBits()[RISCV::FeatureRelax]; const MCOperand &MO = MI.getOperand(OpNo); MCInstrDesc const &Desc = MCII.get(MI.getOpcode()); @@ -161,15 +213,31 @@ unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo, case RISCVMCExpr::VK_RISCV_Invalid: llvm_unreachable("Unhandled fixup kind!"); case RISCVMCExpr::VK_RISCV_LO: - FixupKind = MIFrm == RISCVII::InstFormatI ? RISCV::fixup_riscv_lo12_i - : RISCV::fixup_riscv_lo12_s; + if (MIFrm == RISCVII::InstFormatI) + FixupKind = RISCV::fixup_riscv_lo12_i; + else if (MIFrm == RISCVII::InstFormatS) + FixupKind = RISCV::fixup_riscv_lo12_s; + else + llvm_unreachable("VK_RISCV_LO used with unexpected instruction format"); break; case RISCVMCExpr::VK_RISCV_HI: FixupKind = RISCV::fixup_riscv_hi20; break; + case RISCVMCExpr::VK_RISCV_PCREL_LO: + if (MIFrm == RISCVII::InstFormatI) + FixupKind = RISCV::fixup_riscv_pcrel_lo12_i; + else if (MIFrm == RISCVII::InstFormatS) + FixupKind = RISCV::fixup_riscv_pcrel_lo12_s; + else + llvm_unreachable( + "VK_RISCV_PCREL_LO used with unexpected instruction format"); + break; 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) { @@ -190,6 +258,15 @@ unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo, MCFixup::create(0, Expr, MCFixupKind(FixupKind), MI.getLoc())); ++MCNumFixups; + if (EnableRelax) { + if (FixupKind == RISCV::fixup_riscv_call) { + Fixups.push_back( + MCFixup::create(0, Expr, MCFixupKind(RISCV::fixup_riscv_relax), + MI.getLoc())); + ++MCNumFixups; + } + } + return 0; } |