xref: /freebsd/contrib/llvm-project/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp (revision 924226fba12cc9a228c73b956e1b7fa24c60b055)
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:
43   M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
44       : MCII(mcii), Ctx(ctx) {}
45 
46   ~M68kMCCodeEmitter() override {}
47 
48   // TableGen'erated function
49   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 
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;
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 
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;
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 
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 
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;
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 
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);
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 
383 MCCodeEmitter *llvm::createM68kMCCodeEmitter(const MCInstrInfo &MCII,
384                                              const MCRegisterInfo &MRI,
385                                              MCContext &Ctx) {
386   return new M68kMCCodeEmitter(MCII, Ctx);
387 }
388