104eeddc0SDimitry Andric //===-- M68kMCCodeEmitter.cpp - Convert M68k code emitter -------*- C++ -*-===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric /// 9fe6060f1SDimitry Andric /// \file 10fe6060f1SDimitry Andric /// This file contains defintions for M68k code emitter. 11fe6060f1SDimitry Andric /// 12fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 13fe6060f1SDimitry Andric 14fe6060f1SDimitry Andric #include "MCTargetDesc/M68kMCCodeEmitter.h" 15fe6060f1SDimitry Andric #include "MCTargetDesc/M68kBaseInfo.h" 16fe6060f1SDimitry Andric #include "MCTargetDesc/M68kFixupKinds.h" 17fe6060f1SDimitry Andric #include "MCTargetDesc/M68kMCTargetDesc.h" 18fe6060f1SDimitry Andric 19fe6060f1SDimitry Andric #include "llvm/MC/MCCodeEmitter.h" 20fe6060f1SDimitry Andric #include "llvm/MC/MCContext.h" 21fe6060f1SDimitry Andric #include "llvm/MC/MCExpr.h" 22fe6060f1SDimitry Andric #include "llvm/MC/MCInst.h" 23fe6060f1SDimitry Andric #include "llvm/MC/MCInstrInfo.h" 24fe6060f1SDimitry Andric #include "llvm/MC/MCRegisterInfo.h" 25fe6060f1SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h" 26fe6060f1SDimitry Andric #include "llvm/MC/MCSymbol.h" 27fe6060f1SDimitry Andric #include "llvm/Support/Debug.h" 28fe6060f1SDimitry Andric #include "llvm/Support/EndianStream.h" 29fe6060f1SDimitry Andric #include "llvm/Support/raw_ostream.h" 3081ad6265SDimitry Andric #include <type_traits> 31fe6060f1SDimitry Andric 32fe6060f1SDimitry Andric using namespace llvm; 33fe6060f1SDimitry Andric 34fe6060f1SDimitry Andric #define DEBUG_TYPE "m68k-mccodeemitter" 35fe6060f1SDimitry Andric 36fe6060f1SDimitry Andric namespace { 37fe6060f1SDimitry Andric class M68kMCCodeEmitter : public MCCodeEmitter { 38fe6060f1SDimitry Andric M68kMCCodeEmitter(const M68kMCCodeEmitter &) = delete; 39fe6060f1SDimitry Andric void operator=(const M68kMCCodeEmitter &) = delete; 40fe6060f1SDimitry Andric const MCInstrInfo &MCII; 41fe6060f1SDimitry Andric MCContext &Ctx; 42fe6060f1SDimitry Andric 4381ad6265SDimitry Andric void getBinaryCodeForInstr(const MCInst &MI, SmallVectorImpl<MCFixup> &Fixups, 4481ad6265SDimitry Andric APInt &Inst, APInt &Scratch, 4581ad6265SDimitry Andric const MCSubtargetInfo &STI) const; 4681ad6265SDimitry Andric 4781ad6265SDimitry Andric void getMachineOpValue(const MCInst &MI, const MCOperand &Op, 4881ad6265SDimitry Andric unsigned InsertPos, APInt &Value, 4981ad6265SDimitry Andric SmallVectorImpl<MCFixup> &Fixups, 5081ad6265SDimitry Andric const MCSubtargetInfo &STI) const; 5181ad6265SDimitry Andric 5281ad6265SDimitry Andric template <unsigned Size> 5381ad6265SDimitry Andric void encodeRelocImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos, 5481ad6265SDimitry Andric APInt &Value, SmallVectorImpl<MCFixup> &Fixups, 5581ad6265SDimitry Andric const MCSubtargetInfo &STI) const; 5681ad6265SDimitry Andric 5781ad6265SDimitry Andric template <unsigned Size> 5881ad6265SDimitry Andric void encodePCRelImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos, 5981ad6265SDimitry Andric APInt &Value, SmallVectorImpl<MCFixup> &Fixups, 6081ad6265SDimitry Andric const MCSubtargetInfo &STI) const; 6181ad6265SDimitry Andric 62*5f757f3fSDimitry Andric void encodeFPSYSSelect(const MCInst &MI, unsigned OpIdx, unsigned InsertPos, 63*5f757f3fSDimitry Andric APInt &Value, SmallVectorImpl<MCFixup> &Fixups, 64*5f757f3fSDimitry Andric const MCSubtargetInfo &STI) const; 65*5f757f3fSDimitry Andric 66fe6060f1SDimitry Andric public: 67fe6060f1SDimitry Andric M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx) 68fe6060f1SDimitry Andric : MCII(mcii), Ctx(ctx) {} 69fe6060f1SDimitry Andric 70fe6060f1SDimitry Andric ~M68kMCCodeEmitter() override {} 71fe6060f1SDimitry Andric 7206c3fb27SDimitry Andric void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB, 73fe6060f1SDimitry Andric SmallVectorImpl<MCFixup> &Fixups, 74fe6060f1SDimitry Andric const MCSubtargetInfo &STI) const override; 75fe6060f1SDimitry Andric }; 76fe6060f1SDimitry Andric 77fe6060f1SDimitry Andric } // end anonymous namespace 78fe6060f1SDimitry Andric 7981ad6265SDimitry Andric #include "M68kGenMCCodeEmitter.inc" 8081ad6265SDimitry Andric 8181ad6265SDimitry Andric // Select the proper unsigned integer type from a bit size. 8281ad6265SDimitry Andric template <unsigned Size> struct select_uint_t { 8381ad6265SDimitry Andric using type = typename std::conditional< 8481ad6265SDimitry Andric Size == 8, uint8_t, 8581ad6265SDimitry Andric typename std::conditional< 8681ad6265SDimitry Andric Size == 16, uint16_t, 8781ad6265SDimitry Andric typename std::conditional<Size == 32, uint32_t, 8881ad6265SDimitry Andric uint64_t>::type>::type>::type; 8981ad6265SDimitry Andric }; 9081ad6265SDimitry Andric 9181ad6265SDimitry Andric // Figure out which byte we're at in big endian mode. 9281ad6265SDimitry Andric template <unsigned Size> static unsigned getBytePosition(unsigned BitPos) { 9381ad6265SDimitry Andric if (Size % 16) { 9481ad6265SDimitry Andric return static_cast<unsigned>(BitPos / 8 + ((BitPos & 0b1111) < 8 ? 1 : -1)); 9581ad6265SDimitry Andric } else { 9681ad6265SDimitry Andric assert(!(BitPos & 0b1111) && "Not aligned to word boundary?"); 9781ad6265SDimitry Andric return BitPos / 8; 9881ad6265SDimitry Andric } 9981ad6265SDimitry Andric } 10081ad6265SDimitry Andric 10181ad6265SDimitry Andric // We need special handlings for relocatable & pc-relative operands that are 10281ad6265SDimitry Andric // larger than a word. 10381ad6265SDimitry Andric // A M68k instruction is aligned by word (16 bits). That means, 32-bit 10481ad6265SDimitry Andric // (& 64-bit) immediate values are separated into hi & lo words and placed 10581ad6265SDimitry Andric // at lower & higher addresses, respectively. For immediate values that can 10681ad6265SDimitry Andric // be easily expressed in TG, we explicitly rotate the word ordering like 10781ad6265SDimitry Andric // this: 10881ad6265SDimitry Andric // ``` 10981ad6265SDimitry Andric // (ascend (slice "$imm", 31, 16), (slice "$imm", 15, 0)) 11081ad6265SDimitry Andric // ``` 11181ad6265SDimitry Andric // For operands that call into encoder functions, we need to use the `swapWord` 11281ad6265SDimitry Andric // function to assure the correct word ordering on LE host. Note that 11381ad6265SDimitry Andric // M68kMCCodeEmitter does massage _byte_ ordering of the final encoded 11481ad6265SDimitry Andric // instruction but it assumes everything aligns on word boundaries. So things 11581ad6265SDimitry Andric // will go wrong if we don't take care of the _word_ ordering here. 11681ad6265SDimitry Andric template <unsigned Size> 11781ad6265SDimitry Andric void M68kMCCodeEmitter::encodeRelocImm(const MCInst &MI, unsigned OpIdx, 11881ad6265SDimitry Andric unsigned InsertPos, APInt &Value, 119fe6060f1SDimitry Andric SmallVectorImpl<MCFixup> &Fixups, 120fe6060f1SDimitry Andric const MCSubtargetInfo &STI) const { 12181ad6265SDimitry Andric using value_t = typename select_uint_t<Size>::type; 12281ad6265SDimitry Andric const MCOperand &MCO = MI.getOperand(OpIdx); 12381ad6265SDimitry Andric if (MCO.isImm()) { 124bdd1243dSDimitry Andric Value |= M68k::swapWord<value_t>(static_cast<value_t>(MCO.getImm())); 12581ad6265SDimitry Andric } else if (MCO.isExpr()) { 126fe6060f1SDimitry Andric const MCExpr *Expr = MCO.getExpr(); 127fe6060f1SDimitry Andric 12881ad6265SDimitry Andric // Absolute address 12981ad6265SDimitry Andric int64_t Addr; 13081ad6265SDimitry Andric if (Expr->evaluateAsAbsolute(Addr)) { 131bdd1243dSDimitry Andric Value |= M68k::swapWord<value_t>(static_cast<value_t>(Addr)); 13281ad6265SDimitry Andric return; 133fe6060f1SDimitry Andric } 134fe6060f1SDimitry Andric 13581ad6265SDimitry Andric // Relocatable address 13681ad6265SDimitry Andric unsigned InsertByte = getBytePosition<Size>(InsertPos); 13781ad6265SDimitry Andric Fixups.push_back(MCFixup::create(InsertByte, Expr, 13881ad6265SDimitry Andric getFixupForSize(Size, /*IsPCRel=*/false), 13981ad6265SDimitry Andric MI.getLoc())); 14081ad6265SDimitry Andric } 141fe6060f1SDimitry Andric } 142fe6060f1SDimitry Andric 14381ad6265SDimitry Andric template <unsigned Size> 14481ad6265SDimitry Andric void M68kMCCodeEmitter::encodePCRelImm(const MCInst &MI, unsigned OpIdx, 14581ad6265SDimitry Andric unsigned InsertPos, APInt &Value, 14681ad6265SDimitry Andric SmallVectorImpl<MCFixup> &Fixups, 14781ad6265SDimitry Andric const MCSubtargetInfo &STI) const { 14881ad6265SDimitry Andric const MCOperand &MCO = MI.getOperand(OpIdx); 14981ad6265SDimitry Andric if (MCO.isImm()) { 15081ad6265SDimitry Andric using value_t = typename select_uint_t<Size>::type; 151bdd1243dSDimitry Andric Value |= M68k::swapWord<value_t>(static_cast<value_t>(MCO.getImm())); 15281ad6265SDimitry Andric } else if (MCO.isExpr()) { 153fe6060f1SDimitry Andric const MCExpr *Expr = MCO.getExpr(); 15481ad6265SDimitry Andric unsigned InsertByte = getBytePosition<Size>(InsertPos); 155fe6060f1SDimitry Andric 15681ad6265SDimitry Andric // Special handlings for sizes smaller than a word. 15781ad6265SDimitry Andric if (Size < 16) { 15881ad6265SDimitry Andric int LabelOffset = 0; 15981ad6265SDimitry Andric if (InsertPos < 16) 16081ad6265SDimitry Andric // If the patch point is at the first word, PC is pointing at the 16181ad6265SDimitry Andric // next word. 16281ad6265SDimitry Andric LabelOffset = InsertByte - 2; 16381ad6265SDimitry Andric else if (InsertByte % 2) 16481ad6265SDimitry Andric // Otherwise the PC is pointing at the first byte of this word. 16581ad6265SDimitry Andric // So we need to consider the offset between PC and the fixup byte. 16681ad6265SDimitry Andric LabelOffset = 1; 16781ad6265SDimitry Andric 16881ad6265SDimitry Andric if (LabelOffset) 169fe6060f1SDimitry Andric Expr = MCBinaryExpr::createAdd( 17081ad6265SDimitry Andric Expr, MCConstantExpr::create(LabelOffset, Ctx), Ctx); 171fe6060f1SDimitry Andric } 172fe6060f1SDimitry Andric 17381ad6265SDimitry Andric Fixups.push_back(MCFixup::create(InsertByte, Expr, 17481ad6265SDimitry Andric getFixupForSize(Size, /*IsPCRel=*/true), 17581ad6265SDimitry Andric MI.getLoc())); 176fe6060f1SDimitry Andric } 177fe6060f1SDimitry Andric } 178fe6060f1SDimitry Andric 179*5f757f3fSDimitry Andric void M68kMCCodeEmitter::encodeFPSYSSelect(const MCInst &MI, unsigned OpIdx, 180*5f757f3fSDimitry Andric unsigned InsertPos, APInt &Value, 181*5f757f3fSDimitry Andric SmallVectorImpl<MCFixup> &Fixups, 182*5f757f3fSDimitry Andric const MCSubtargetInfo &STI) const { 183*5f757f3fSDimitry Andric MCRegister FPSysReg = MI.getOperand(OpIdx).getReg(); 184*5f757f3fSDimitry Andric switch (FPSysReg) { 185*5f757f3fSDimitry Andric case M68k::FPC: 186*5f757f3fSDimitry Andric Value = 0b100; 187*5f757f3fSDimitry Andric break; 188*5f757f3fSDimitry Andric case M68k::FPS: 189*5f757f3fSDimitry Andric Value = 0b010; 190*5f757f3fSDimitry Andric break; 191*5f757f3fSDimitry Andric case M68k::FPIAR: 192*5f757f3fSDimitry Andric Value = 0b001; 193*5f757f3fSDimitry Andric break; 194*5f757f3fSDimitry Andric default: 195*5f757f3fSDimitry Andric llvm_unreachable("Unrecognized FPSYS register"); 196*5f757f3fSDimitry Andric } 197*5f757f3fSDimitry Andric } 198*5f757f3fSDimitry Andric 19981ad6265SDimitry Andric void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op, 20081ad6265SDimitry Andric unsigned InsertPos, APInt &Value, 20181ad6265SDimitry Andric SmallVectorImpl<MCFixup> &Fixups, 20281ad6265SDimitry Andric const MCSubtargetInfo &STI) const { 20381ad6265SDimitry Andric // Register 20481ad6265SDimitry Andric if (Op.isReg()) { 20581ad6265SDimitry Andric unsigned RegNum = Op.getReg(); 20681ad6265SDimitry Andric const auto *RI = Ctx.getRegisterInfo(); 20781ad6265SDimitry Andric Value |= RI->getEncodingValue(RegNum); 20881ad6265SDimitry Andric // Setup the D/A bit 20981ad6265SDimitry Andric if (M68kII::isAddressRegister(RegNum)) 21081ad6265SDimitry Andric Value |= 0b1000; 21181ad6265SDimitry Andric } else if (Op.isImm()) { 21281ad6265SDimitry Andric // Immediate 21381ad6265SDimitry Andric Value |= static_cast<uint64_t>(Op.getImm()); 21481ad6265SDimitry Andric } else if (Op.isExpr()) { 21581ad6265SDimitry Andric // Absolute address 21681ad6265SDimitry Andric int64_t Addr; 21781ad6265SDimitry Andric if (!Op.getExpr()->evaluateAsAbsolute(Addr)) 21881ad6265SDimitry Andric report_fatal_error("Unsupported asm expression. Only absolute address " 21981ad6265SDimitry Andric "can be placed here."); 22081ad6265SDimitry Andric Value |= static_cast<uint64_t>(Addr); 221fe6060f1SDimitry Andric } else { 22281ad6265SDimitry Andric llvm_unreachable("Unsupported operand type"); 223fe6060f1SDimitry Andric } 224fe6060f1SDimitry Andric } 225fe6060f1SDimitry Andric 22606c3fb27SDimitry Andric void M68kMCCodeEmitter::encodeInstruction(const MCInst &MI, 22706c3fb27SDimitry Andric SmallVectorImpl<char> &CB, 228fe6060f1SDimitry Andric SmallVectorImpl<MCFixup> &Fixups, 229fe6060f1SDimitry Andric const MCSubtargetInfo &STI) const { 230*5f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "EncodeInstruction: " << MCII.getName(MI.getOpcode()) 231*5f757f3fSDimitry Andric << "(" << MI.getOpcode() << ")\n"); 232*5f757f3fSDimitry Andric (void)MCII; 233fe6060f1SDimitry Andric 23481ad6265SDimitry Andric // Try using the new method first. 23581ad6265SDimitry Andric APInt EncodedInst(16, 0U); 236*5f757f3fSDimitry Andric APInt Scratch(64, 0U); // One APInt word is enough. 23781ad6265SDimitry Andric getBinaryCodeForInstr(MI, Fixups, EncodedInst, Scratch, STI); 238fe6060f1SDimitry Andric 23981ad6265SDimitry Andric ArrayRef<uint64_t> Data(EncodedInst.getRawData(), EncodedInst.getNumWords()); 24081ad6265SDimitry Andric int64_t InstSize = EncodedInst.getBitWidth(); 24181ad6265SDimitry Andric for (uint64_t Word : Data) { 24281ad6265SDimitry Andric for (int i = 0; i < 4 && InstSize > 0; ++i, InstSize -= 16) { 24306c3fb27SDimitry Andric support::endian::write<uint16_t>(CB, static_cast<uint16_t>(Word), 244*5f757f3fSDimitry Andric llvm::endianness::big); 24581ad6265SDimitry Andric Word >>= 16; 246fe6060f1SDimitry Andric } 247fe6060f1SDimitry Andric } 248fe6060f1SDimitry Andric } 249fe6060f1SDimitry Andric 250fe6060f1SDimitry Andric MCCodeEmitter *llvm::createM68kMCCodeEmitter(const MCInstrInfo &MCII, 251fe6060f1SDimitry Andric MCContext &Ctx) { 252fe6060f1SDimitry Andric return new M68kMCCodeEmitter(MCII, Ctx); 253fe6060f1SDimitry Andric } 254