264 lines · cpp
1//===-- M68kMCCodeEmitter.cpp - Convert M68k code emitter -------*- C++ -*-===//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/// \file10/// This file contains defintions for M68k code emitter.11///12//===----------------------------------------------------------------------===//13 14#include "MCTargetDesc/M68kMCCodeEmitter.h"15#include "MCTargetDesc/M68kBaseInfo.h"16#include "MCTargetDesc/M68kFixupKinds.h"17#include "MCTargetDesc/M68kMCTargetDesc.h"18 19#include "llvm/MC/MCCodeEmitter.h"20#include "llvm/MC/MCContext.h"21#include "llvm/MC/MCExpr.h"22#include "llvm/MC/MCInst.h"23#include "llvm/MC/MCInstrInfo.h"24#include "llvm/MC/MCRegisterInfo.h"25#include "llvm/MC/MCSubtargetInfo.h"26#include "llvm/MC/MCSymbol.h"27#include "llvm/Support/Debug.h"28#include "llvm/Support/EndianStream.h"29#include "llvm/Support/raw_ostream.h"30#include <type_traits>31 32using namespace llvm;33 34#define DEBUG_TYPE "m68k-mccodeemitter"35 36namespace {37class M68kMCCodeEmitter : public MCCodeEmitter {38 M68kMCCodeEmitter(const M68kMCCodeEmitter &) = delete;39 void operator=(const M68kMCCodeEmitter &) = delete;40 const MCInstrInfo &MCII;41 MCContext &Ctx;42 43 void getBinaryCodeForInstr(const MCInst &MI, SmallVectorImpl<MCFixup> &Fixups,44 APInt &Inst, APInt &Scratch,45 const MCSubtargetInfo &STI) const;46 47 void getMachineOpValue(const MCInst &MI, const MCOperand &Op,48 unsigned InsertPos, APInt &Value,49 SmallVectorImpl<MCFixup> &Fixups,50 const MCSubtargetInfo &STI) const;51 52 template <unsigned Size>53 void encodeRelocImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,54 APInt &Value, SmallVectorImpl<MCFixup> &Fixups,55 const MCSubtargetInfo &STI) const;56 57 template <unsigned Size>58 void encodePCRelImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,59 APInt &Value, SmallVectorImpl<MCFixup> &Fixups,60 const MCSubtargetInfo &STI) const;61 62 void encodeFPSYSSelect(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,63 APInt &Value, SmallVectorImpl<MCFixup> &Fixups,64 const MCSubtargetInfo &STI) const;65 66 void encodeInverseMoveMask(const MCInst &MI, unsigned OpIdx,67 unsigned InsertPos, APInt &Value,68 SmallVectorImpl<MCFixup> &Fixups,69 const MCSubtargetInfo &STI) const;70 71public:72 M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)73 : MCII(mcii), Ctx(ctx) {}74 75 ~M68kMCCodeEmitter() override {}76 77 void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,78 SmallVectorImpl<MCFixup> &Fixups,79 const MCSubtargetInfo &STI) const override;80};81 82} // end anonymous namespace83 84#include "M68kGenMCCodeEmitter.inc"85 86// Select the proper unsigned integer type from a bit size.87template <unsigned Size> struct select_uint_t {88 using type = typename std::conditional<89 Size == 8, uint8_t,90 typename std::conditional<91 Size == 16, uint16_t,92 typename std::conditional<Size == 32, uint32_t,93 uint64_t>::type>::type>::type;94};95 96// Figure out which byte we're at in big endian mode.97template <unsigned Size> static unsigned getBytePosition(unsigned BitPos) {98 if (Size % 16) {99 return static_cast<unsigned>(BitPos / 8 + ((BitPos & 0b1111) < 8 ? 1 : -1));100 } else {101 assert(!(BitPos & 0b1111) && "Not aligned to word boundary?");102 return BitPos / 8;103 }104}105 106static void addFixup(SmallVectorImpl<MCFixup> &Fixups, uint32_t Offset,107 const MCExpr *Value, uint16_t Kind, bool PCRel = false) {108 Fixups.push_back(MCFixup::create(Offset, Value, Kind, PCRel));109}110 111// We need special handlings for relocatable & pc-relative operands that are112// larger than a word.113// A M68k instruction is aligned by word (16 bits). That means, 32-bit114// (& 64-bit) immediate values are separated into hi & lo words and placed115// at lower & higher addresses, respectively. For immediate values that can116// be easily expressed in TG, we explicitly rotate the word ordering like117// this:118// ```119// (ascend (slice "$imm", 31, 16), (slice "$imm", 15, 0))120// ```121// For operands that call into encoder functions, we need to use the `swapWord`122// function to assure the correct word ordering on LE host. Note that123// M68kMCCodeEmitter does massage _byte_ ordering of the final encoded124// instruction but it assumes everything aligns on word boundaries. So things125// will go wrong if we don't take care of the _word_ ordering here.126template <unsigned Size>127void M68kMCCodeEmitter::encodeRelocImm(const MCInst &MI, unsigned OpIdx,128 unsigned InsertPos, APInt &Value,129 SmallVectorImpl<MCFixup> &Fixups,130 const MCSubtargetInfo &STI) const {131 using value_t = typename select_uint_t<Size>::type;132 const MCOperand &MCO = MI.getOperand(OpIdx);133 if (MCO.isImm()) {134 Value |= M68k::swapWord<value_t>(static_cast<value_t>(MCO.getImm()));135 } else if (MCO.isExpr()) {136 const MCExpr *Expr = MCO.getExpr();137 138 // Absolute address139 int64_t Addr;140 if (Expr->evaluateAsAbsolute(Addr)) {141 Value |= M68k::swapWord<value_t>(static_cast<value_t>(Addr));142 return;143 }144 145 // Relocatable address146 unsigned InsertByte = getBytePosition<Size>(InsertPos);147 addFixup(Fixups, InsertByte, Expr, MCFixup::getDataKindForSize(Size / 8));148 }149}150 151template <unsigned Size>152void M68kMCCodeEmitter::encodePCRelImm(const MCInst &MI, unsigned OpIdx,153 unsigned InsertPos, APInt &Value,154 SmallVectorImpl<MCFixup> &Fixups,155 const MCSubtargetInfo &STI) const {156 const MCOperand &MCO = MI.getOperand(OpIdx);157 if (MCO.isImm()) {158 using value_t = typename select_uint_t<Size>::type;159 Value |= M68k::swapWord<value_t>(static_cast<value_t>(MCO.getImm()));160 } else if (MCO.isExpr()) {161 const MCExpr *Expr = MCO.getExpr();162 unsigned InsertByte = getBytePosition<Size>(InsertPos);163 164 // Special handlings for sizes smaller than a word.165 if (Size < 16) {166 int LabelOffset = 0;167 if (InsertPos < 16)168 // If the patch point is at the first word, PC is pointing at the169 // next word.170 LabelOffset = InsertByte - 2;171 else if (InsertByte % 2)172 // Otherwise the PC is pointing at the first byte of this word.173 // So we need to consider the offset between PC and the fixup byte.174 LabelOffset = 1;175 176 if (LabelOffset)177 Expr = MCBinaryExpr::createAdd(178 Expr, MCConstantExpr::create(LabelOffset, Ctx), Ctx);179 }180 181 addFixup(Fixups, InsertByte, Expr, MCFixup::getDataKindForSize(Size / 8),182 true);183 }184}185 186void M68kMCCodeEmitter::encodeFPSYSSelect(const MCInst &MI, unsigned OpIdx,187 unsigned InsertPos, APInt &Value,188 SmallVectorImpl<MCFixup> &Fixups,189 const MCSubtargetInfo &STI) const {190 MCRegister FPSysReg = MI.getOperand(OpIdx).getReg();191 switch (FPSysReg) {192 case M68k::FPC:193 Value = 0b100;194 break;195 case M68k::FPS:196 Value = 0b010;197 break;198 case M68k::FPIAR:199 Value = 0b001;200 break;201 default:202 llvm_unreachable("Unrecognized FPSYS register");203 }204}205 206void M68kMCCodeEmitter::encodeInverseMoveMask(207 const MCInst &MI, unsigned OpIdx, unsigned InsertPos, APInt &Value,208 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {209 const MCOperand &Op = MI.getOperand(OpIdx);210 Value = llvm::reverseBits<uint16_t>((uint16_t)Op.getImm());211}212 213void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op,214 unsigned InsertPos, APInt &Value,215 SmallVectorImpl<MCFixup> &Fixups,216 const MCSubtargetInfo &STI) const {217 // Register218 if (Op.isReg()) {219 unsigned RegNum = Op.getReg();220 const auto *RI = Ctx.getRegisterInfo();221 Value |= RI->getEncodingValue(RegNum);222 // Setup the D/A bit223 if (M68kII::isAddressRegister(RegNum))224 Value |= 0b1000;225 } else if (Op.isImm()) {226 // Immediate227 Value |= static_cast<uint64_t>(Op.getImm());228 } else if (Op.isExpr()) {229 // Absolute address230 int64_t Addr;231 if (!Op.getExpr()->evaluateAsAbsolute(Addr))232 report_fatal_error("Unsupported asm expression. Only absolute address "233 "can be placed here.");234 Value |= static_cast<uint64_t>(Addr);235 } else {236 llvm_unreachable("Unsupported operand type");237 }238}239 240void M68kMCCodeEmitter::encodeInstruction(const MCInst &MI,241 SmallVectorImpl<char> &CB,242 SmallVectorImpl<MCFixup> &Fixups,243 const MCSubtargetInfo &STI) const {244 LLVM_DEBUG(dbgs() << "EncodeInstruction: " << MCII.getName(MI.getOpcode())245 << "(" << MI.getOpcode() << ")\n");246 (void)MCII;247 248 // Try using the new method first.249 APInt EncodedInst(16, 0U);250 APInt Scratch(64, 0U); // One APInt word is enough.251 getBinaryCodeForInstr(MI, Fixups, EncodedInst, Scratch, STI);252 253 unsigned InstSize = EncodedInst.getBitWidth();254 for (unsigned i = 0; i != InstSize; i += 16)255 support::endian::write<uint16_t>(256 CB, static_cast<uint16_t>(EncodedInst.extractBitsAsZExtValue(16, i)),257 llvm::endianness::big);258}259 260MCCodeEmitter *llvm::createM68kMCCodeEmitter(const MCInstrInfo &MCII,261 MCContext &Ctx) {262 return new M68kMCCodeEmitter(MCII, Ctx);263}264