281 lines · cpp
1//===-- SparcMCCodeEmitter.cpp - Convert Sparc code to machine code -------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the SparcMCCodeEmitter class.10//11//===----------------------------------------------------------------------===//12 13#include "MCTargetDesc/SparcFixupKinds.h"14#include "SparcMCTargetDesc.h"15#include "llvm/ADT/SmallVector.h"16#include "llvm/ADT/Statistic.h"17#include "llvm/BinaryFormat/ELF.h"18#include "llvm/MC/MCAsmInfo.h"19#include "llvm/MC/MCCodeEmitter.h"20#include "llvm/MC/MCContext.h"21#include "llvm/MC/MCExpr.h"22#include "llvm/MC/MCFixup.h"23#include "llvm/MC/MCInst.h"24#include "llvm/MC/MCInstrInfo.h"25#include "llvm/MC/MCObjectFileInfo.h"26#include "llvm/MC/MCRegisterInfo.h"27#include "llvm/MC/MCSubtargetInfo.h"28#include "llvm/MC/MCSymbol.h"29#include "llvm/Support/Casting.h"30#include "llvm/Support/EndianStream.h"31#include <cassert>32#include <cstdint>33 34using namespace llvm;35 36#define DEBUG_TYPE "mccodeemitter"37 38STATISTIC(MCNumEmitted, "Number of MC instructions emitted");39 40namespace {41 42class SparcMCCodeEmitter : public MCCodeEmitter {43 MCContext &Ctx;44 45public:46 SparcMCCodeEmitter(const MCInstrInfo &, MCContext &ctx)47 : Ctx(ctx) {}48 SparcMCCodeEmitter(const SparcMCCodeEmitter &) = delete;49 SparcMCCodeEmitter &operator=(const SparcMCCodeEmitter &) = delete;50 ~SparcMCCodeEmitter() override = default;51 52 void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,53 SmallVectorImpl<MCFixup> &Fixups,54 const MCSubtargetInfo &STI) const override;55 56 // getBinaryCodeForInstr - TableGen'erated function for getting the57 // binary encoding for an instruction.58 uint64_t getBinaryCodeForInstr(const MCInst &MI,59 SmallVectorImpl<MCFixup> &Fixups,60 const MCSubtargetInfo &STI) const;61 62 /// getMachineOpValue - Return binary encoding of operand. If the machine63 /// operand requires relocation, record the relocation and return zero.64 unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,65 SmallVectorImpl<MCFixup> &Fixups,66 const MCSubtargetInfo &STI) const;67 unsigned getCallTargetOpValue(const MCInst &MI, unsigned OpNo,68 SmallVectorImpl<MCFixup> &Fixups,69 const MCSubtargetInfo &STI) const;70 unsigned getBranchTargetOpValue(const MCInst &MI, unsigned OpNo,71 SmallVectorImpl<MCFixup> &Fixups,72 const MCSubtargetInfo &STI) const;73 unsigned getSImm5OpValue(const MCInst &MI, unsigned OpNo,74 SmallVectorImpl<MCFixup> &Fixups,75 const MCSubtargetInfo &STI) const;76 unsigned getSImm13OpValue(const MCInst &MI, unsigned OpNo,77 SmallVectorImpl<MCFixup> &Fixups,78 const MCSubtargetInfo &STI) const;79 unsigned getBranchPredTargetOpValue(const MCInst &MI, unsigned OpNo,80 SmallVectorImpl<MCFixup> &Fixups,81 const MCSubtargetInfo &STI) const;82 unsigned getBranchOnRegTargetOpValue(const MCInst &MI, unsigned OpNo,83 SmallVectorImpl<MCFixup> &Fixups,84 const MCSubtargetInfo &STI) const;85 unsigned getCompareAndBranchTargetOpValue(const MCInst &MI, unsigned OpNo,86 SmallVectorImpl<MCFixup> &Fixups,87 const MCSubtargetInfo &STI) const;88};89 90} // end anonymous namespace91 92static void addFixup(SmallVectorImpl<MCFixup> &Fixups, uint32_t Offset,93 const MCExpr *Value, uint16_t Kind) {94 bool PCRel = false;95 switch (Kind) {96 case ELF::R_SPARC_PC10:97 case ELF::R_SPARC_PC22:98 case ELF::R_SPARC_WDISP10:99 case ELF::R_SPARC_WDISP16:100 case ELF::R_SPARC_WDISP19:101 case ELF::R_SPARC_WDISP22:102 case Sparc::fixup_sparc_call30:103 PCRel = true;104 }105 Fixups.push_back(MCFixup::create(Offset, Value, Kind, PCRel));106}107 108void SparcMCCodeEmitter::encodeInstruction(const MCInst &MI,109 SmallVectorImpl<char> &CB,110 SmallVectorImpl<MCFixup> &Fixups,111 const MCSubtargetInfo &STI) const {112 unsigned Bits = getBinaryCodeForInstr(MI, Fixups, STI);113 support::endian::write(CB, Bits,114 Ctx.getAsmInfo()->isLittleEndian()115 ? llvm::endianness::little116 : llvm::endianness::big);117 118 // Some instructions have phantom operands that only contribute a fixup entry.119 unsigned SymOpNo = 0;120 switch (MI.getOpcode()) {121 default: break;122 case SP::TLS_CALL: SymOpNo = 1; break;123 case SP::GDOP_LDrr:124 case SP::GDOP_LDXrr:125 case SP::TLS_ADDrr:126 case SP::TLS_LDrr:127 case SP::TLS_LDXrr: SymOpNo = 3; break;128 }129 if (SymOpNo != 0) {130 const MCOperand &MO = MI.getOperand(SymOpNo);131 uint64_t op = getMachineOpValue(MI, MO, Fixups, STI);132 assert(op == 0 && "Unexpected operand value!");133 (void)op; // suppress warning.134 }135 136 ++MCNumEmitted; // Keep track of the # of mi's emitted.137}138 139unsigned SparcMCCodeEmitter::140getMachineOpValue(const MCInst &MI, const MCOperand &MO,141 SmallVectorImpl<MCFixup> &Fixups,142 const MCSubtargetInfo &STI) const {143 if (MO.isReg())144 return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());145 146 if (MO.isImm())147 return MO.getImm();148 149 assert(MO.isExpr());150 const MCExpr *Expr = MO.getExpr();151 if (auto *SExpr = dyn_cast<MCSpecifierExpr>(Expr)) {152 addFixup(Fixups, 0, Expr, SExpr->getSpecifier());153 return 0;154 }155 156 int64_t Res;157 if (Expr->evaluateAsAbsolute(Res))158 return Res;159 160 llvm_unreachable("Unhandled expression!");161 return 0;162}163 164unsigned SparcMCCodeEmitter::getSImm5OpValue(const MCInst &MI, unsigned OpNo,165 SmallVectorImpl<MCFixup> &Fixups,166 const MCSubtargetInfo &STI) const {167 const MCOperand &MO = MI.getOperand(OpNo);168 169 if (MO.isImm())170 return MO.getImm();171 172 assert(MO.isExpr() &&173 "getSImm5OpValue expects only expressions or an immediate");174 175 const MCExpr *Expr = MO.getExpr();176 177 // Constant value, no fixup is needed178 if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))179 return CE->getValue();180 181 if (auto *SExpr = dyn_cast<MCSpecifierExpr>(Expr)) {182 addFixup(Fixups, 0, Expr, SExpr->getSpecifier());183 return 0;184 }185 addFixup(Fixups, 0, Expr, ELF::R_SPARC_5);186 return 0;187}188 189unsigned190SparcMCCodeEmitter::getSImm13OpValue(const MCInst &MI, unsigned OpNo,191 SmallVectorImpl<MCFixup> &Fixups,192 const MCSubtargetInfo &STI) const {193 const MCOperand &MO = MI.getOperand(OpNo);194 195 if (MO.isImm())196 return MO.getImm();197 198 assert(MO.isExpr() &&199 "getSImm13OpValue expects only expressions or an immediate");200 201 const MCExpr *Expr = MO.getExpr();202 203 // Constant value, no fixup is needed204 if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))205 return CE->getValue();206 207 if (auto *SExpr = dyn_cast<MCSpecifierExpr>(Expr)) {208 addFixup(Fixups, 0, Expr, SExpr->getSpecifier());209 return 0;210 }211 addFixup(Fixups, 0, Expr, Sparc::fixup_sparc_13);212 return 0;213}214 215unsigned SparcMCCodeEmitter::216getCallTargetOpValue(const MCInst &MI, unsigned OpNo,217 SmallVectorImpl<MCFixup> &Fixups,218 const MCSubtargetInfo &STI) const {219 if (MI.getOpcode() == SP::TLS_CALL) {220 // No fixups for __tls_get_addr. Will emit for fixups for tls_symbol in221 // encodeInstruction.222 return 0;223 }224 225 const MCOperand &MO = MI.getOperand(OpNo);226 addFixup(Fixups, 0, MO.getExpr(), Sparc::fixup_sparc_call30);227 return 0;228}229 230unsigned SparcMCCodeEmitter::231getBranchTargetOpValue(const MCInst &MI, unsigned OpNo,232 SmallVectorImpl<MCFixup> &Fixups,233 const MCSubtargetInfo &STI) const {234 const MCOperand &MO = MI.getOperand(OpNo);235 if (MO.isReg() || MO.isImm())236 return getMachineOpValue(MI, MO, Fixups, STI);237 238 addFixup(Fixups, 0, MO.getExpr(), ELF::R_SPARC_WDISP22);239 return 0;240}241 242unsigned SparcMCCodeEmitter::getBranchPredTargetOpValue(243 const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups,244 const MCSubtargetInfo &STI) const {245 const MCOperand &MO = MI.getOperand(OpNo);246 if (MO.isReg() || MO.isImm())247 return getMachineOpValue(MI, MO, Fixups, STI);248 249 addFixup(Fixups, 0, MO.getExpr(), ELF::R_SPARC_WDISP19);250 return 0;251}252 253unsigned SparcMCCodeEmitter::getBranchOnRegTargetOpValue(254 const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups,255 const MCSubtargetInfo &STI) const {256 const MCOperand &MO = MI.getOperand(OpNo);257 if (MO.isReg() || MO.isImm())258 return getMachineOpValue(MI, MO, Fixups, STI);259 260 addFixup(Fixups, 0, MO.getExpr(), ELF::R_SPARC_WDISP16);261 return 0;262}263 264unsigned SparcMCCodeEmitter::getCompareAndBranchTargetOpValue(265 const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups,266 const MCSubtargetInfo &STI) const {267 const MCOperand &MO = MI.getOperand(OpNo);268 if (MO.isImm())269 return getMachineOpValue(MI, MO, Fixups, STI);270 271 addFixup(Fixups, 0, MO.getExpr(), ELF::R_SPARC_WDISP10);272 return 0;273}274 275#include "SparcGenMCCodeEmitter.inc"276 277MCCodeEmitter *llvm::createSparcMCCodeEmitter(const MCInstrInfo &MCII,278 MCContext &Ctx) {279 return new SparcMCCodeEmitter(MCII, Ctx);280}281