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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// 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 32 using namespace llvm; 33 34 #define DEBUG_TYPE "m68k-mccodeemitter" 35 36 namespace { 37 class 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 public: 67 M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx) 68 : MCII(mcii), Ctx(ctx) {} 69 70 ~M68kMCCodeEmitter() override {} 71 72 void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB, 73 SmallVectorImpl<MCFixup> &Fixups, 74 const MCSubtargetInfo &STI) const override; 75 }; 76 77 } // end anonymous namespace 78 79 #include "M68kGenMCCodeEmitter.inc" 80 81 // Select the proper unsigned integer type from a bit size. 82 template <unsigned Size> struct select_uint_t { 83 using type = typename std::conditional< 84 Size == 8, uint8_t, 85 typename std::conditional< 86 Size == 16, uint16_t, 87 typename std::conditional<Size == 32, uint32_t, 88 uint64_t>::type>::type>::type; 89 }; 90 91 // Figure out which byte we're at in big endian mode. 92 template <unsigned Size> static unsigned getBytePosition(unsigned BitPos) { 93 if (Size % 16) { 94 return static_cast<unsigned>(BitPos / 8 + ((BitPos & 0b1111) < 8 ? 1 : -1)); 95 } else { 96 assert(!(BitPos & 0b1111) && "Not aligned to word boundary?"); 97 return BitPos / 8; 98 } 99 } 100 101 // We need special handlings for relocatable & pc-relative operands that are 102 // larger than a word. 103 // A M68k instruction is aligned by word (16 bits). That means, 32-bit 104 // (& 64-bit) immediate values are separated into hi & lo words and placed 105 // at lower & higher addresses, respectively. For immediate values that can 106 // be easily expressed in TG, we explicitly rotate the word ordering like 107 // this: 108 // ``` 109 // (ascend (slice "$imm", 31, 16), (slice "$imm", 15, 0)) 110 // ``` 111 // For operands that call into encoder functions, we need to use the `swapWord` 112 // function to assure the correct word ordering on LE host. Note that 113 // M68kMCCodeEmitter does massage _byte_ ordering of the final encoded 114 // instruction but it assumes everything aligns on word boundaries. So things 115 // will go wrong if we don't take care of the _word_ ordering here. 116 template <unsigned Size> 117 void M68kMCCodeEmitter::encodeRelocImm(const MCInst &MI, unsigned OpIdx, 118 unsigned InsertPos, APInt &Value, 119 SmallVectorImpl<MCFixup> &Fixups, 120 const MCSubtargetInfo &STI) const { 121 using value_t = typename select_uint_t<Size>::type; 122 const MCOperand &MCO = MI.getOperand(OpIdx); 123 if (MCO.isImm()) { 124 Value |= M68k::swapWord<value_t>(static_cast<value_t>(MCO.getImm())); 125 } else if (MCO.isExpr()) { 126 const MCExpr *Expr = MCO.getExpr(); 127 128 // Absolute address 129 int64_t Addr; 130 if (Expr->evaluateAsAbsolute(Addr)) { 131 Value |= M68k::swapWord<value_t>(static_cast<value_t>(Addr)); 132 return; 133 } 134 135 // Relocatable address 136 unsigned InsertByte = getBytePosition<Size>(InsertPos); 137 Fixups.push_back(MCFixup::create(InsertByte, Expr, 138 getFixupForSize(Size, /*IsPCRel=*/false), 139 MI.getLoc())); 140 } 141 } 142 143 template <unsigned Size> 144 void M68kMCCodeEmitter::encodePCRelImm(const MCInst &MI, unsigned OpIdx, 145 unsigned InsertPos, APInt &Value, 146 SmallVectorImpl<MCFixup> &Fixups, 147 const MCSubtargetInfo &STI) const { 148 const MCOperand &MCO = MI.getOperand(OpIdx); 149 if (MCO.isImm()) { 150 using value_t = typename select_uint_t<Size>::type; 151 Value |= M68k::swapWord<value_t>(static_cast<value_t>(MCO.getImm())); 152 } else if (MCO.isExpr()) { 153 const MCExpr *Expr = MCO.getExpr(); 154 unsigned InsertByte = getBytePosition<Size>(InsertPos); 155 156 // Special handlings for sizes smaller than a word. 157 if (Size < 16) { 158 int LabelOffset = 0; 159 if (InsertPos < 16) 160 // If the patch point is at the first word, PC is pointing at the 161 // next word. 162 LabelOffset = InsertByte - 2; 163 else if (InsertByte % 2) 164 // Otherwise the PC is pointing at the first byte of this word. 165 // So we need to consider the offset between PC and the fixup byte. 166 LabelOffset = 1; 167 168 if (LabelOffset) 169 Expr = MCBinaryExpr::createAdd( 170 Expr, MCConstantExpr::create(LabelOffset, Ctx), Ctx); 171 } 172 173 Fixups.push_back(MCFixup::create(InsertByte, Expr, 174 getFixupForSize(Size, /*IsPCRel=*/true), 175 MI.getLoc())); 176 } 177 } 178 179 void M68kMCCodeEmitter::encodeFPSYSSelect(const MCInst &MI, unsigned OpIdx, 180 unsigned InsertPos, APInt &Value, 181 SmallVectorImpl<MCFixup> &Fixups, 182 const MCSubtargetInfo &STI) const { 183 MCRegister FPSysReg = MI.getOperand(OpIdx).getReg(); 184 switch (FPSysReg) { 185 case M68k::FPC: 186 Value = 0b100; 187 break; 188 case M68k::FPS: 189 Value = 0b010; 190 break; 191 case M68k::FPIAR: 192 Value = 0b001; 193 break; 194 default: 195 llvm_unreachable("Unrecognized FPSYS register"); 196 } 197 } 198 199 void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op, 200 unsigned InsertPos, APInt &Value, 201 SmallVectorImpl<MCFixup> &Fixups, 202 const MCSubtargetInfo &STI) const { 203 // Register 204 if (Op.isReg()) { 205 unsigned RegNum = Op.getReg(); 206 const auto *RI = Ctx.getRegisterInfo(); 207 Value |= RI->getEncodingValue(RegNum); 208 // Setup the D/A bit 209 if (M68kII::isAddressRegister(RegNum)) 210 Value |= 0b1000; 211 } else if (Op.isImm()) { 212 // Immediate 213 Value |= static_cast<uint64_t>(Op.getImm()); 214 } else if (Op.isExpr()) { 215 // Absolute address 216 int64_t Addr; 217 if (!Op.getExpr()->evaluateAsAbsolute(Addr)) 218 report_fatal_error("Unsupported asm expression. Only absolute address " 219 "can be placed here."); 220 Value |= static_cast<uint64_t>(Addr); 221 } else { 222 llvm_unreachable("Unsupported operand type"); 223 } 224 } 225 226 void M68kMCCodeEmitter::encodeInstruction(const MCInst &MI, 227 SmallVectorImpl<char> &CB, 228 SmallVectorImpl<MCFixup> &Fixups, 229 const MCSubtargetInfo &STI) const { 230 LLVM_DEBUG(dbgs() << "EncodeInstruction: " << MCII.getName(MI.getOpcode()) 231 << "(" << MI.getOpcode() << ")\n"); 232 (void)MCII; 233 234 // Try using the new method first. 235 APInt EncodedInst(16, 0U); 236 APInt Scratch(64, 0U); // One APInt word is enough. 237 getBinaryCodeForInstr(MI, Fixups, EncodedInst, Scratch, STI); 238 239 ArrayRef<uint64_t> Data(EncodedInst.getRawData(), EncodedInst.getNumWords()); 240 int64_t InstSize = EncodedInst.getBitWidth(); 241 for (uint64_t Word : Data) { 242 for (int i = 0; i < 4 && InstSize > 0; ++i, InstSize -= 16) { 243 support::endian::write<uint16_t>(CB, static_cast<uint16_t>(Word), 244 llvm::endianness::big); 245 Word >>= 16; 246 } 247 } 248 } 249 250 MCCodeEmitter *llvm::createM68kMCCodeEmitter(const MCInstrInfo &MCII, 251 MCContext &Ctx) { 252 return new M68kMCCodeEmitter(MCII, Ctx); 253 } 254