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
31 using namespace llvm;
32
33 #define DEBUG_TYPE "m68k-mccodeemitter"
34
35 namespace {
36 class M68kMCCodeEmitter : public MCCodeEmitter {
37 M68kMCCodeEmitter(const M68kMCCodeEmitter &) = delete;
38 void operator=(const M68kMCCodeEmitter &) = delete;
39 const MCInstrInfo &MCII;
40 MCContext &Ctx;
41
42 public:
M68kMCCodeEmitter(const MCInstrInfo & mcii,MCContext & ctx)43 M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
44 : MCII(mcii), Ctx(ctx) {}
45
~M68kMCCodeEmitter()46 ~M68kMCCodeEmitter() override {}
47
48 // TableGen'erated function
getGenInstrBeads(const MCInst & MI) const49 const uint8_t *getGenInstrBeads(const MCInst &MI) const {
50 return M68k::getMCInstrBeads(MI.getOpcode());
51 }
52
53 unsigned encodeBits(unsigned ThisByte, uint8_t Bead, const MCInst &MI,
54 const MCInstrDesc &Desc, uint64_t &Buffer,
55 unsigned Offset, SmallVectorImpl<MCFixup> &Fixups,
56 const MCSubtargetInfo &STI) const;
57
58 unsigned encodeReg(unsigned ThisByte, uint8_t Bead, const MCInst &MI,
59 const MCInstrDesc &Desc, uint64_t &Buffer, unsigned Offset,
60 SmallVectorImpl<MCFixup> &Fixups,
61 const MCSubtargetInfo &STI) const;
62
63 unsigned encodeImm(unsigned ThisByte, uint8_t Bead, const MCInst &MI,
64 const MCInstrDesc &Desc, uint64_t &Buffer, unsigned Offset,
65 SmallVectorImpl<MCFixup> &Fixups,
66 const MCSubtargetInfo &STI) const;
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
encodeBits(unsigned ThisByte,uint8_t Bead,const MCInst & MI,const MCInstrDesc & Desc,uint64_t & Buffer,unsigned Offset,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const75 unsigned M68kMCCodeEmitter::encodeBits(unsigned ThisByte, uint8_t Bead,
76 const MCInst &MI,
77 const MCInstrDesc &Desc,
78 uint64_t &Buffer, unsigned Offset,
79 SmallVectorImpl<MCFixup> &Fixups,
80 const MCSubtargetInfo &STI) const {
81 unsigned Num = 0;
82 switch (Bead & 0xF) {
83 case M68kBeads::Bits1:
84 Num = 1;
85 break;
86 case M68kBeads::Bits2:
87 Num = 2;
88 break;
89 case M68kBeads::Bits3:
90 Num = 3;
91 break;
92 case M68kBeads::Bits4:
93 Num = 4;
94 break;
95 }
96 unsigned char Val = (Bead & 0xF0) >> 4;
97
98 LLVM_DEBUG(dbgs() << "\tEncodeBits"
99 << " Num: " << Num << " Val: 0x");
100 LLVM_DEBUG(dbgs().write_hex(Val) << "\n");
101
102 Buffer |= (Val << Offset);
103
104 return Num;
105 }
106
encodeReg(unsigned ThisByte,uint8_t Bead,const MCInst & MI,const MCInstrDesc & Desc,uint64_t & Buffer,unsigned Offset,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const107 unsigned M68kMCCodeEmitter::encodeReg(unsigned ThisByte, uint8_t Bead,
108 const MCInst &MI, const MCInstrDesc &Desc,
109 uint64_t &Buffer, unsigned Offset,
110 SmallVectorImpl<MCFixup> &Fixups,
111 const MCSubtargetInfo &STI) const {
112 bool DA, Reg;
113 switch (Bead & 0xF) {
114 default:
115 llvm_unreachable("Unrecognized Bead code for register type");
116 case M68kBeads::DAReg:
117 Reg = true;
118 DA = true;
119 break;
120 case M68kBeads::DA:
121 Reg = false;
122 DA = true;
123 break;
124 case M68kBeads::DReg:
125 case M68kBeads::Reg:
126 Reg = true;
127 DA = false;
128 break;
129 }
130
131 unsigned Op = (Bead & 0x70) >> 4;
132 bool Alt = (Bead & 0x80);
133 LLVM_DEBUG(dbgs() << "\tEncodeReg"
134 << " Op: " << Op << ", DA: " << DA << ", Reg: " << Reg
135 << ", Alt: " << Alt << "\n");
136
137 auto MIOpIdx = M68k::getLogicalOperandIdx(MI.getOpcode(), Op);
138 bool IsPCRel = Desc.OpInfo[MIOpIdx].OperandType == MCOI::OPERAND_PCREL;
139
140 MCOperand MCO;
141 if (M68kII::hasMultiMIOperands(MI.getOpcode(), Op)) {
142 if (IsPCRel) {
143 assert(Alt &&
144 "PCRel addresses use Alt bead register encoding by default");
145 MCO = MI.getOperand(MIOpIdx + M68k::PCRelIndex);
146 } else {
147 MCO = MI.getOperand(MIOpIdx + (Alt ? M68k::MemIndex : M68k::MemBase));
148 }
149 } else {
150 assert(!Alt && "You cannot use Alt register with a simple operand");
151 MCO = MI.getOperand(MIOpIdx);
152 }
153
154 unsigned RegNum = MCO.getReg();
155 auto RI = Ctx.getRegisterInfo();
156
157 unsigned Written = 0;
158 if (Reg) {
159 uint32_t Val = RI->getEncodingValue(RegNum);
160 Buffer |= (Val & 7) << Offset;
161 Offset += 3;
162 Written += 3;
163 }
164
165 if (DA) {
166 Buffer |= (uint64_t)M68kII::isAddressRegister(RegNum) << Offset;
167 Written++;
168 }
169
170 return Written;
171 }
172
EmitConstant(uint64_t Val,unsigned Size,unsigned Pad,uint64_t & Buffer,unsigned Offset)173 static unsigned EmitConstant(uint64_t Val, unsigned Size, unsigned Pad,
174 uint64_t &Buffer, unsigned Offset) {
175 assert(Size + Offset <= 64 && isUIntN(Size, Val) && "Value does not fit");
176
177 // Writing Value in host's endianness
178 Buffer |= (Val & ((1ULL << Size) - 1)) << Offset;
179 return Size + Pad;
180 }
181
encodeImm(unsigned ThisByte,uint8_t Bead,const MCInst & MI,const MCInstrDesc & Desc,uint64_t & Buffer,unsigned Offset,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const182 unsigned M68kMCCodeEmitter::encodeImm(unsigned ThisByte, uint8_t Bead,
183 const MCInst &MI, const MCInstrDesc &Desc,
184 uint64_t &Buffer, unsigned Offset,
185 SmallVectorImpl<MCFixup> &Fixups,
186 const MCSubtargetInfo &STI) const {
187 unsigned ThisWord = ThisByte / 2;
188 unsigned Size = 0;
189 unsigned Pad = 0;
190 unsigned FixOffset = 0;
191 int64_t Addendum = 0;
192 bool NoExpr = false;
193
194 unsigned Type = Bead & 0xF;
195 unsigned Op = (Bead & 0x70) >> 4;
196 bool Alt = (Bead & 0x80);
197
198 auto MIOpIdx = M68k::getLogicalOperandIdx(MI.getOpcode(), Op);
199 bool IsPCRel = Desc.OpInfo[MIOpIdx].OperandType == MCOI::OPERAND_PCREL;
200
201 // The PC value upon instruction reading of a short jump will point to the
202 // next instruction, thus we need to compensate 2 bytes, which is the diff
203 // between the patch point and the PC.
204 if (IsPCRel && ThisWord == 0)
205 Addendum -= 2;
206
207 switch (Type) {
208 // ??? what happens if it is not byte aligned
209 // ??? is it even possible
210 case M68kBeads::Disp8:
211 Size = 8;
212 Pad = 0;
213 FixOffset = ThisByte + 1;
214 Addendum += 1;
215 break;
216 case M68kBeads::Imm8:
217 Size = 8;
218 Pad = 8;
219 FixOffset = ThisByte;
220 break;
221 case M68kBeads::Imm16:
222 Size = 16;
223 Pad = 0;
224 FixOffset = ThisByte;
225 break;
226 case M68kBeads::Imm32:
227 Size = 32;
228 Pad = 0;
229 FixOffset = ThisByte;
230 break;
231 case M68kBeads::Imm3:
232 Size = 3;
233 Pad = 0;
234 NoExpr = true;
235 break;
236 }
237
238 LLVM_DEBUG(dbgs() << "\tEncodeImm"
239 << " Op: " << Op << ", Size: " << Size << ", Alt: " << Alt
240 << "\n");
241
242 MCOperand MCO;
243 if (M68kII::hasMultiMIOperands(MI.getOpcode(), Op)) {
244
245 if (IsPCRel) {
246 assert(!Alt && "You cannot use ALT operand with PCRel");
247 MCO = MI.getOperand(MIOpIdx + M68k::PCRelDisp);
248 } else {
249 MCO = MI.getOperand(MIOpIdx + (Alt ? M68k::MemOuter : M68k::MemDisp));
250 }
251
252 if (MCO.isExpr()) {
253 assert(!NoExpr && "Cannot use expression here");
254 const MCExpr *Expr = MCO.getExpr();
255
256 // This only makes sense for PCRel instructions since PC points to the
257 // extension word and Disp8 for example is right justified and requires
258 // correction. E.g. R_68K_PC32 is calculated as S + A - P, P for Disp8
259 // will be EXTENSION_WORD + 1 thus we need to have A equal to 1 to
260 // compensate.
261 // TODO count extension words
262 if (IsPCRel && Addendum != 0) {
263 Expr = MCBinaryExpr::createAdd(
264 Expr, MCConstantExpr::create(Addendum, Ctx), Ctx);
265 }
266
267 Fixups.push_back(MCFixup::create(
268 FixOffset, Expr, getFixupForSize(Size, IsPCRel), MI.getLoc()));
269 // Write zeros
270 return EmitConstant(0, Size, Pad, Buffer, Offset);
271 }
272
273 } else {
274 MCO = MI.getOperand(MIOpIdx);
275 if (MCO.isExpr()) {
276 assert(!NoExpr && "Cannot use expression here");
277 const MCExpr *Expr = MCO.getExpr();
278
279 if (Addendum != 0) {
280 Expr = MCBinaryExpr::createAdd(
281 Expr, MCConstantExpr::create(Addendum, Ctx), Ctx);
282 }
283
284 Fixups.push_back(MCFixup::create(
285 FixOffset, Expr, getFixupForSize(Size, IsPCRel), MI.getLoc()));
286 // Write zeros
287 return EmitConstant(0, Size, Pad, Buffer, Offset);
288 }
289 }
290
291 int64_t I = MCO.getImm();
292
293 // Store 8 as 0, thus making range 1-8
294 if (Type == M68kBeads::Imm3 && Alt) {
295 assert(I && "Cannot encode Alt Imm3 zero value");
296 I %= 8;
297 } else {
298 assert(isIntN(Size, I));
299 }
300
301 uint64_t Imm = I;
302
303 // 32 bit Imm requires HI16 first then LO16
304 if (Size == 32) {
305 Offset += EmitConstant((Imm >> 16) & 0xFFFF, 16, Pad, Buffer, Offset);
306 EmitConstant(Imm & 0xFFFF, 16, Pad, Buffer, Offset);
307 return Size;
308 }
309
310 return EmitConstant(Imm & ((1ULL << Size) - 1), Size, Pad, Buffer, Offset);
311 }
312
313 #include "M68kGenMCCodeBeads.inc"
314
encodeInstruction(const MCInst & MI,raw_ostream & OS,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const315 void M68kMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
316 SmallVectorImpl<MCFixup> &Fixups,
317 const MCSubtargetInfo &STI) const {
318 unsigned Opcode = MI.getOpcode();
319 const MCInstrDesc &Desc = MCII.get(Opcode);
320
321 LLVM_DEBUG(dbgs() << "EncodeInstruction: " << MCII.getName(Opcode) << "("
322 << Opcode << ")\n");
323
324 const uint8_t *Beads = getGenInstrBeads(MI);
325 if (!Beads || !*Beads) {
326 llvm_unreachable("*** Instruction does not have Beads defined");
327 }
328
329 uint64_t Buffer = 0;
330 unsigned Offset = 0;
331 unsigned ThisByte = 0;
332
333 for (uint8_t Bead = *Beads; Bead; Bead = *++Beads) {
334 // Check for control beads
335 if (!(Bead & 0xF)) {
336 switch (Bead >> 4) {
337 case M68kBeads::Ignore:
338 continue;
339 }
340 }
341
342 switch (Bead & 0xF) {
343 default:
344 llvm_unreachable("Unknown Bead code");
345 break;
346 case M68kBeads::Bits1:
347 case M68kBeads::Bits2:
348 case M68kBeads::Bits3:
349 case M68kBeads::Bits4:
350 Offset +=
351 encodeBits(ThisByte, Bead, MI, Desc, Buffer, Offset, Fixups, STI);
352 break;
353 case M68kBeads::DAReg:
354 case M68kBeads::DA:
355 case M68kBeads::DReg:
356 case M68kBeads::Reg:
357 Offset +=
358 encodeReg(ThisByte, Bead, MI, Desc, Buffer, Offset, Fixups, STI);
359 break;
360 case M68kBeads::Disp8:
361 case M68kBeads::Imm8:
362 case M68kBeads::Imm16:
363 case M68kBeads::Imm32:
364 case M68kBeads::Imm3:
365 Offset +=
366 encodeImm(ThisByte, Bead, MI, Desc, Buffer, Offset, Fixups, STI);
367 break;
368 }
369
370 // Since M68k is Big Endian we need to rotate each instruction word
371 while (Offset / 16) {
372 support::endian::write<uint16_t>(OS, Buffer, support::big);
373 Buffer >>= 16;
374 Offset -= 16;
375 ThisByte += 2;
376 }
377 }
378
379 assert(Offset == 0 && "M68k Instructions are % 2 bytes");
380 assert((ThisByte && !(ThisByte % 2)) && "M68k Instructions are % 2 bytes");
381 }
382
createM68kMCCodeEmitter(const MCInstrInfo & MCII,const MCRegisterInfo & MRI,MCContext & Ctx)383 MCCodeEmitter *llvm::createM68kMCCodeEmitter(const MCInstrInfo &MCII,
384 const MCRegisterInfo &MRI,
385 MCContext &Ctx) {
386 return new M68kMCCodeEmitter(MCII, Ctx);
387 }
388