Path: blob/main/contrib/llvm-project/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp
35294 views
//===-- M68kMCCodeEmitter.cpp - Convert M68k code emitter -------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// This file contains defintions for M68k code emitter.10///11//===----------------------------------------------------------------------===//1213#include "MCTargetDesc/M68kMCCodeEmitter.h"14#include "MCTargetDesc/M68kBaseInfo.h"15#include "MCTargetDesc/M68kFixupKinds.h"16#include "MCTargetDesc/M68kMCTargetDesc.h"1718#include "llvm/MC/MCCodeEmitter.h"19#include "llvm/MC/MCContext.h"20#include "llvm/MC/MCExpr.h"21#include "llvm/MC/MCInst.h"22#include "llvm/MC/MCInstrInfo.h"23#include "llvm/MC/MCRegisterInfo.h"24#include "llvm/MC/MCSubtargetInfo.h"25#include "llvm/MC/MCSymbol.h"26#include "llvm/Support/Debug.h"27#include "llvm/Support/EndianStream.h"28#include "llvm/Support/raw_ostream.h"29#include <type_traits>3031using namespace llvm;3233#define DEBUG_TYPE "m68k-mccodeemitter"3435namespace {36class M68kMCCodeEmitter : public MCCodeEmitter {37M68kMCCodeEmitter(const M68kMCCodeEmitter &) = delete;38void operator=(const M68kMCCodeEmitter &) = delete;39const MCInstrInfo &MCII;40MCContext &Ctx;4142void getBinaryCodeForInstr(const MCInst &MI, SmallVectorImpl<MCFixup> &Fixups,43APInt &Inst, APInt &Scratch,44const MCSubtargetInfo &STI) const;4546void getMachineOpValue(const MCInst &MI, const MCOperand &Op,47unsigned InsertPos, APInt &Value,48SmallVectorImpl<MCFixup> &Fixups,49const MCSubtargetInfo &STI) const;5051template <unsigned Size>52void encodeRelocImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,53APInt &Value, SmallVectorImpl<MCFixup> &Fixups,54const MCSubtargetInfo &STI) const;5556template <unsigned Size>57void encodePCRelImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,58APInt &Value, SmallVectorImpl<MCFixup> &Fixups,59const MCSubtargetInfo &STI) const;6061void encodeFPSYSSelect(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,62APInt &Value, SmallVectorImpl<MCFixup> &Fixups,63const MCSubtargetInfo &STI) const;6465public:66M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)67: MCII(mcii), Ctx(ctx) {}6869~M68kMCCodeEmitter() override {}7071void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,72SmallVectorImpl<MCFixup> &Fixups,73const MCSubtargetInfo &STI) const override;74};7576} // end anonymous namespace7778#include "M68kGenMCCodeEmitter.inc"7980// Select the proper unsigned integer type from a bit size.81template <unsigned Size> struct select_uint_t {82using type = typename std::conditional<83Size == 8, uint8_t,84typename std::conditional<85Size == 16, uint16_t,86typename std::conditional<Size == 32, uint32_t,87uint64_t>::type>::type>::type;88};8990// Figure out which byte we're at in big endian mode.91template <unsigned Size> static unsigned getBytePosition(unsigned BitPos) {92if (Size % 16) {93return static_cast<unsigned>(BitPos / 8 + ((BitPos & 0b1111) < 8 ? 1 : -1));94} else {95assert(!(BitPos & 0b1111) && "Not aligned to word boundary?");96return BitPos / 8;97}98}99100// We need special handlings for relocatable & pc-relative operands that are101// larger than a word.102// A M68k instruction is aligned by word (16 bits). That means, 32-bit103// (& 64-bit) immediate values are separated into hi & lo words and placed104// at lower & higher addresses, respectively. For immediate values that can105// be easily expressed in TG, we explicitly rotate the word ordering like106// this:107// ```108// (ascend (slice "$imm", 31, 16), (slice "$imm", 15, 0))109// ```110// For operands that call into encoder functions, we need to use the `swapWord`111// function to assure the correct word ordering on LE host. Note that112// M68kMCCodeEmitter does massage _byte_ ordering of the final encoded113// instruction but it assumes everything aligns on word boundaries. So things114// will go wrong if we don't take care of the _word_ ordering here.115template <unsigned Size>116void M68kMCCodeEmitter::encodeRelocImm(const MCInst &MI, unsigned OpIdx,117unsigned InsertPos, APInt &Value,118SmallVectorImpl<MCFixup> &Fixups,119const MCSubtargetInfo &STI) const {120using value_t = typename select_uint_t<Size>::type;121const MCOperand &MCO = MI.getOperand(OpIdx);122if (MCO.isImm()) {123Value |= M68k::swapWord<value_t>(static_cast<value_t>(MCO.getImm()));124} else if (MCO.isExpr()) {125const MCExpr *Expr = MCO.getExpr();126127// Absolute address128int64_t Addr;129if (Expr->evaluateAsAbsolute(Addr)) {130Value |= M68k::swapWord<value_t>(static_cast<value_t>(Addr));131return;132}133134// Relocatable address135unsigned InsertByte = getBytePosition<Size>(InsertPos);136Fixups.push_back(MCFixup::create(InsertByte, Expr,137getFixupForSize(Size, /*IsPCRel=*/false),138MI.getLoc()));139}140}141142template <unsigned Size>143void M68kMCCodeEmitter::encodePCRelImm(const MCInst &MI, unsigned OpIdx,144unsigned InsertPos, APInt &Value,145SmallVectorImpl<MCFixup> &Fixups,146const MCSubtargetInfo &STI) const {147const MCOperand &MCO = MI.getOperand(OpIdx);148if (MCO.isImm()) {149using value_t = typename select_uint_t<Size>::type;150Value |= M68k::swapWord<value_t>(static_cast<value_t>(MCO.getImm()));151} else if (MCO.isExpr()) {152const MCExpr *Expr = MCO.getExpr();153unsigned InsertByte = getBytePosition<Size>(InsertPos);154155// Special handlings for sizes smaller than a word.156if (Size < 16) {157int LabelOffset = 0;158if (InsertPos < 16)159// If the patch point is at the first word, PC is pointing at the160// next word.161LabelOffset = InsertByte - 2;162else if (InsertByte % 2)163// Otherwise the PC is pointing at the first byte of this word.164// So we need to consider the offset between PC and the fixup byte.165LabelOffset = 1;166167if (LabelOffset)168Expr = MCBinaryExpr::createAdd(169Expr, MCConstantExpr::create(LabelOffset, Ctx), Ctx);170}171172Fixups.push_back(MCFixup::create(InsertByte, Expr,173getFixupForSize(Size, /*IsPCRel=*/true),174MI.getLoc()));175}176}177178void M68kMCCodeEmitter::encodeFPSYSSelect(const MCInst &MI, unsigned OpIdx,179unsigned InsertPos, APInt &Value,180SmallVectorImpl<MCFixup> &Fixups,181const MCSubtargetInfo &STI) const {182MCRegister FPSysReg = MI.getOperand(OpIdx).getReg();183switch (FPSysReg) {184case M68k::FPC:185Value = 0b100;186break;187case M68k::FPS:188Value = 0b010;189break;190case M68k::FPIAR:191Value = 0b001;192break;193default:194llvm_unreachable("Unrecognized FPSYS register");195}196}197198void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op,199unsigned InsertPos, APInt &Value,200SmallVectorImpl<MCFixup> &Fixups,201const MCSubtargetInfo &STI) const {202// Register203if (Op.isReg()) {204unsigned RegNum = Op.getReg();205const auto *RI = Ctx.getRegisterInfo();206Value |= RI->getEncodingValue(RegNum);207// Setup the D/A bit208if (M68kII::isAddressRegister(RegNum))209Value |= 0b1000;210} else if (Op.isImm()) {211// Immediate212Value |= static_cast<uint64_t>(Op.getImm());213} else if (Op.isExpr()) {214// Absolute address215int64_t Addr;216if (!Op.getExpr()->evaluateAsAbsolute(Addr))217report_fatal_error("Unsupported asm expression. Only absolute address "218"can be placed here.");219Value |= static_cast<uint64_t>(Addr);220} else {221llvm_unreachable("Unsupported operand type");222}223}224225void M68kMCCodeEmitter::encodeInstruction(const MCInst &MI,226SmallVectorImpl<char> &CB,227SmallVectorImpl<MCFixup> &Fixups,228const MCSubtargetInfo &STI) const {229LLVM_DEBUG(dbgs() << "EncodeInstruction: " << MCII.getName(MI.getOpcode())230<< "(" << MI.getOpcode() << ")\n");231(void)MCII;232233// Try using the new method first.234APInt EncodedInst(16, 0U);235APInt Scratch(64, 0U); // One APInt word is enough.236getBinaryCodeForInstr(MI, Fixups, EncodedInst, Scratch, STI);237238ArrayRef<uint64_t> Data(EncodedInst.getRawData(), EncodedInst.getNumWords());239int64_t InstSize = EncodedInst.getBitWidth();240for (uint64_t Word : Data) {241for (int i = 0; i < 4 && InstSize > 0; ++i, InstSize -= 16) {242support::endian::write<uint16_t>(CB, static_cast<uint16_t>(Word),243llvm::endianness::big);244Word >>= 16;245}246}247}248249MCCodeEmitter *llvm::createM68kMCCodeEmitter(const MCInstrInfo &MCII,250MCContext &Ctx) {251return new M68kMCCodeEmitter(MCII, Ctx);252}253254255