|  | //===-- SparcMCCodeEmitter.cpp - Convert Sparc code to machine code -------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file implements the SparcMCCodeEmitter class. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "MCTargetDesc/SparcFixupKinds.h" | 
|  | #include "SparcMCExpr.h" | 
|  | #include "SparcMCTargetDesc.h" | 
|  | #include "llvm/ADT/SmallVector.h" | 
|  | #include "llvm/ADT/Statistic.h" | 
|  | #include "llvm/MC/MCAsmInfo.h" | 
|  | #include "llvm/MC/MCCodeEmitter.h" | 
|  | #include "llvm/MC/MCContext.h" | 
|  | #include "llvm/MC/MCExpr.h" | 
|  | #include "llvm/MC/MCFixup.h" | 
|  | #include "llvm/MC/MCInst.h" | 
|  | #include "llvm/MC/MCInstrInfo.h" | 
|  | #include "llvm/MC/MCRegisterInfo.h" | 
|  | #include "llvm/MC/MCSubtargetInfo.h" | 
|  | #include "llvm/MC/MCSymbol.h" | 
|  | #include "llvm/MC/SubtargetFeature.h" | 
|  | #include "llvm/Support/Casting.h" | 
|  | #include "llvm/Support/Endian.h" | 
|  | #include "llvm/Support/EndianStream.h" | 
|  | #include "llvm/Support/ErrorHandling.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  | #include <cassert> | 
|  | #include <cstdint> | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | #define DEBUG_TYPE "mccodeemitter" | 
|  |  | 
|  | STATISTIC(MCNumEmitted, "Number of MC instructions emitted"); | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class SparcMCCodeEmitter : public MCCodeEmitter { | 
|  | const MCInstrInfo &MCII; | 
|  | MCContext &Ctx; | 
|  |  | 
|  | public: | 
|  | SparcMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx) | 
|  | : MCII(mcii), Ctx(ctx) {} | 
|  | SparcMCCodeEmitter(const SparcMCCodeEmitter &) = delete; | 
|  | SparcMCCodeEmitter &operator=(const SparcMCCodeEmitter &) = delete; | 
|  | ~SparcMCCodeEmitter() override = default; | 
|  |  | 
|  | void encodeInstruction(const MCInst &MI, raw_ostream &OS, | 
|  | SmallVectorImpl<MCFixup> &Fixups, | 
|  | const MCSubtargetInfo &STI) const override; | 
|  |  | 
|  | // getBinaryCodeForInstr - TableGen'erated function for getting the | 
|  | // binary encoding for an instruction. | 
|  | uint64_t getBinaryCodeForInstr(const MCInst &MI, | 
|  | SmallVectorImpl<MCFixup> &Fixups, | 
|  | const MCSubtargetInfo &STI) const; | 
|  |  | 
|  | /// getMachineOpValue - Return binary encoding of operand. If the machine | 
|  | /// operand requires relocation, record the relocation and return zero. | 
|  | unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO, | 
|  | SmallVectorImpl<MCFixup> &Fixups, | 
|  | const MCSubtargetInfo &STI) const; | 
|  |  | 
|  | unsigned getCallTargetOpValue(const MCInst &MI, unsigned OpNo, | 
|  | SmallVectorImpl<MCFixup> &Fixups, | 
|  | const MCSubtargetInfo &STI) const; | 
|  | unsigned getBranchTargetOpValue(const MCInst &MI, unsigned OpNo, | 
|  | SmallVectorImpl<MCFixup> &Fixups, | 
|  | const MCSubtargetInfo &STI) const; | 
|  | unsigned getBranchPredTargetOpValue(const MCInst &MI, unsigned OpNo, | 
|  | SmallVectorImpl<MCFixup> &Fixups, | 
|  | const MCSubtargetInfo &STI) const; | 
|  | unsigned getBranchOnRegTargetOpValue(const MCInst &MI, unsigned OpNo, | 
|  | SmallVectorImpl<MCFixup> &Fixups, | 
|  | const MCSubtargetInfo &STI) const; | 
|  |  | 
|  | private: | 
|  | FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) const; | 
|  | void | 
|  | verifyInstructionPredicates(const MCInst &MI, | 
|  | const FeatureBitset &AvailableFeatures) const; | 
|  | }; | 
|  |  | 
|  | } // end anonymous namespace | 
|  |  | 
|  | void SparcMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, | 
|  | SmallVectorImpl<MCFixup> &Fixups, | 
|  | const MCSubtargetInfo &STI) const { | 
|  | verifyInstructionPredicates(MI, | 
|  | computeAvailableFeatures(STI.getFeatureBits())); | 
|  |  | 
|  | unsigned Bits = getBinaryCodeForInstr(MI, Fixups, STI); | 
|  | support::endian::write(OS, Bits, | 
|  | Ctx.getAsmInfo()->isLittleEndian() ? support::little | 
|  | : support::big); | 
|  | unsigned tlsOpNo = 0; | 
|  | switch (MI.getOpcode()) { | 
|  | default: break; | 
|  | case SP::TLS_CALL:   tlsOpNo = 1; break; | 
|  | case SP::TLS_ADDrr: | 
|  | case SP::TLS_ADDXrr: | 
|  | case SP::TLS_LDrr: | 
|  | case SP::TLS_LDXrr:  tlsOpNo = 3; break; | 
|  | } | 
|  | if (tlsOpNo != 0) { | 
|  | const MCOperand &MO = MI.getOperand(tlsOpNo); | 
|  | uint64_t op = getMachineOpValue(MI, MO, Fixups, STI); | 
|  | assert(op == 0 && "Unexpected operand value!"); | 
|  | (void)op; // suppress warning. | 
|  | } | 
|  |  | 
|  | ++MCNumEmitted;  // Keep track of the # of mi's emitted. | 
|  | } | 
|  |  | 
|  | unsigned SparcMCCodeEmitter:: | 
|  | getMachineOpValue(const MCInst &MI, const MCOperand &MO, | 
|  | SmallVectorImpl<MCFixup> &Fixups, | 
|  | const MCSubtargetInfo &STI) const { | 
|  | if (MO.isReg()) | 
|  | return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg()); | 
|  |  | 
|  | if (MO.isImm()) | 
|  | return MO.getImm(); | 
|  |  | 
|  | assert(MO.isExpr()); | 
|  | const MCExpr *Expr = MO.getExpr(); | 
|  | if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(Expr)) { | 
|  | MCFixupKind Kind = (MCFixupKind)SExpr->getFixupKind(); | 
|  | Fixups.push_back(MCFixup::create(0, Expr, Kind)); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int64_t Res; | 
|  | if (Expr->evaluateAsAbsolute(Res)) | 
|  | return Res; | 
|  |  | 
|  | llvm_unreachable("Unhandled expression!"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | unsigned SparcMCCodeEmitter:: | 
|  | getCallTargetOpValue(const MCInst &MI, unsigned OpNo, | 
|  | SmallVectorImpl<MCFixup> &Fixups, | 
|  | const MCSubtargetInfo &STI) const { | 
|  | const MCOperand &MO = MI.getOperand(OpNo); | 
|  | if (MO.isReg() || MO.isImm()) | 
|  | return getMachineOpValue(MI, MO, Fixups, STI); | 
|  |  | 
|  | if (MI.getOpcode() == SP::TLS_CALL) { | 
|  | // No fixups for __tls_get_addr. Will emit for fixups for tls_symbol in | 
|  | // encodeInstruction. | 
|  | #ifndef NDEBUG | 
|  | // Verify that the callee is actually __tls_get_addr. | 
|  | const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(MO.getExpr()); | 
|  | assert(SExpr && SExpr->getSubExpr()->getKind() == MCExpr::SymbolRef && | 
|  | "Unexpected expression in TLS_CALL"); | 
|  | const MCSymbolRefExpr *SymExpr = cast<MCSymbolRefExpr>(SExpr->getSubExpr()); | 
|  | assert(SymExpr->getSymbol().getName() == "__tls_get_addr" && | 
|  | "Unexpected function for TLS_CALL"); | 
|  | #endif | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | MCFixupKind fixupKind = (MCFixupKind)Sparc::fixup_sparc_call30; | 
|  |  | 
|  | if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(MO.getExpr())) { | 
|  | if (SExpr->getKind() == SparcMCExpr::VK_Sparc_WPLT30) | 
|  | fixupKind = (MCFixupKind)Sparc::fixup_sparc_wplt30; | 
|  | } | 
|  |  | 
|  | Fixups.push_back(MCFixup::create(0, MO.getExpr(), fixupKind)); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | unsigned SparcMCCodeEmitter:: | 
|  | getBranchTargetOpValue(const MCInst &MI, unsigned OpNo, | 
|  | SmallVectorImpl<MCFixup> &Fixups, | 
|  | const MCSubtargetInfo &STI) const { | 
|  | const MCOperand &MO = MI.getOperand(OpNo); | 
|  | if (MO.isReg() || MO.isImm()) | 
|  | return getMachineOpValue(MI, MO, Fixups, STI); | 
|  |  | 
|  | Fixups.push_back(MCFixup::create(0, MO.getExpr(), | 
|  | (MCFixupKind)Sparc::fixup_sparc_br22)); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | unsigned SparcMCCodeEmitter:: | 
|  | getBranchPredTargetOpValue(const MCInst &MI, unsigned OpNo, | 
|  | SmallVectorImpl<MCFixup> &Fixups, | 
|  | const MCSubtargetInfo &STI) const { | 
|  | const MCOperand &MO = MI.getOperand(OpNo); | 
|  | if (MO.isReg() || MO.isImm()) | 
|  | return getMachineOpValue(MI, MO, Fixups, STI); | 
|  |  | 
|  | Fixups.push_back(MCFixup::create(0, MO.getExpr(), | 
|  | (MCFixupKind)Sparc::fixup_sparc_br19)); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | unsigned SparcMCCodeEmitter:: | 
|  | getBranchOnRegTargetOpValue(const MCInst &MI, unsigned OpNo, | 
|  | SmallVectorImpl<MCFixup> &Fixups, | 
|  | const MCSubtargetInfo &STI) const { | 
|  | const MCOperand &MO = MI.getOperand(OpNo); | 
|  | if (MO.isReg() || MO.isImm()) | 
|  | return getMachineOpValue(MI, MO, Fixups, STI); | 
|  |  | 
|  | Fixups.push_back(MCFixup::create(0, MO.getExpr(), | 
|  | (MCFixupKind)Sparc::fixup_sparc_br16_2)); | 
|  | Fixups.push_back(MCFixup::create(0, MO.getExpr(), | 
|  | (MCFixupKind)Sparc::fixup_sparc_br16_14)); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #define ENABLE_INSTR_PREDICATE_VERIFIER | 
|  | #include "SparcGenMCCodeEmitter.inc" | 
|  |  | 
|  | MCCodeEmitter *llvm::createSparcMCCodeEmitter(const MCInstrInfo &MCII, | 
|  | const MCRegisterInfo &MRI, | 
|  | MCContext &Ctx) { | 
|  | return new SparcMCCodeEmitter(MCII, Ctx); | 
|  | } |