[ORC] Add std::tuple support to SimplePackedSerialization.
[llvm-project.git] / llvm / lib / Target / M68k / MCTargetDesc / M68kMCCodeEmitter.cpp
blob9708abaadf981ef6418b317ed34e8c7eeaaf144b
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 //===----------------------------------------------------------------------===//
14 #include "MCTargetDesc/M68kMCCodeEmitter.h"
15 #include "MCTargetDesc/M68kBaseInfo.h"
16 #include "MCTargetDesc/M68kFixupKinds.h"
17 #include "MCTargetDesc/M68kMCTargetDesc.h"
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"
31 using namespace llvm;
33 #define DEBUG_TYPE "m68k-mccodeemitter"
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;
42 public:
43 M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
44 : MCII(mcii), Ctx(ctx) {}
46 ~M68kMCCodeEmitter() override {}
48 // TableGen'erated function
49 const uint8_t *getGenInstrBeads(const MCInst &MI) const {
50 return M68k::getMCInstrBeads(MI.getOpcode());
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;
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;
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;
68 void encodeInstruction(const MCInst &MI, raw_ostream &OS,
69 SmallVectorImpl<MCFixup> &Fixups,
70 const MCSubtargetInfo &STI) const override;
73 } // end anonymous namespace
75 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;
96 unsigned char Val = (Bead & 0xF0) >> 4;
98 LLVM_DEBUG(dbgs() << "\tEncodeBits"
99 << " Num: " << Num << " Val: 0x");
100 LLVM_DEBUG(dbgs().write_hex(Val) << "\n");
102 Buffer |= (Val << Offset);
104 return Num;
107 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;
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");
137 auto MIOpIdx = M68k::getLogicalOperandIdx(MI.getOpcode(), Op);
138 bool IsPCRel = Desc.OpInfo[MIOpIdx].OperandType == MCOI::OPERAND_PCREL;
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));
149 } else {
150 assert(!Alt && "You cannot use Alt register with a simple operand");
151 MCO = MI.getOperand(MIOpIdx);
154 unsigned RegNum = MCO.getReg();
155 auto RI = Ctx.getRegisterInfo();
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;
165 if (DA) {
166 Buffer |= (uint64_t)M68kII::isAddressRegister(RegNum) << Offset;
167 Written++;
170 return Written;
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");
177 // Writing Value in host's endianness
178 Buffer |= (Val & ((1ULL << Size) - 1)) << Offset;
179 return Size + Pad;
182 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;
194 unsigned Type = Bead & 0xF;
195 unsigned Op = (Bead & 0x70) >> 4;
196 bool Alt = (Bead & 0x80);
198 auto MIOpIdx = M68k::getLogicalOperandIdx(MI.getOpcode(), Op);
199 bool IsPCRel = Desc.OpInfo[MIOpIdx].OperandType == MCOI::OPERAND_PCREL;
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;
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;
238 LLVM_DEBUG(dbgs() << "\tEncodeImm"
239 << " Op: " << Op << ", Size: " << Size << ", Alt: " << Alt
240 << "\n");
242 MCOperand MCO;
243 if (M68kII::hasMultiMIOperands(MI.getOpcode(), Op)) {
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));
252 if (MCO.isExpr()) {
253 assert(!NoExpr && "Cannot use expression here");
254 const MCExpr *Expr = MCO.getExpr();
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);
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);
273 } else {
274 MCO = MI.getOperand(MIOpIdx);
275 if (MCO.isExpr()) {
276 assert(!NoExpr && "Cannot use expression here");
277 const MCExpr *Expr = MCO.getExpr();
279 if (Addendum != 0) {
280 Expr = MCBinaryExpr::createAdd(
281 Expr, MCConstantExpr::create(Addendum, Ctx), Ctx);
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);
291 int64_t I = MCO.getImm();
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));
301 uint64_t Imm = I;
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;
310 return EmitConstant(Imm & ((1ULL << Size) - 1), Size, Pad, Buffer, Offset);
313 #include "M68kGenMCCodeBeads.inc"
315 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);
321 LLVM_DEBUG(dbgs() << "EncodeInstruction: " << MCII.getName(Opcode) << "("
322 << Opcode << ")\n");
324 const uint8_t *Beads = getGenInstrBeads(MI);
325 if (!Beads || !*Beads) {
326 llvm_unreachable("*** Instruction does not have Beads defined");
329 uint64_t Buffer = 0;
330 unsigned Offset = 0;
331 unsigned ThisByte = 0;
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;
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;
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;
379 assert(Offset == 0 && "M68k Instructions are % 2 bytes");
380 assert((ThisByte && !(ThisByte % 2)) && "M68k Instructions are % 2 bytes");
383 MCCodeEmitter *llvm::createM68kMCCodeEmitter(const MCInstrInfo &MCII,
384 const MCRegisterInfo &MRI,
385 MCContext &Ctx) {
386 return new M68kMCCodeEmitter(MCII, Ctx);