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