xref: /freebsd/contrib/llvm-project/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp (revision 9f44a47fd07924afc035991af15d84e6585dea4f)
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