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