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