1*d415bd75Srobert //===-- M68kMCCodeEmitter.cpp - Convert M68k code emitter -------*- C++ -*-===//
273471bf0Spatrick //
373471bf0Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
473471bf0Spatrick // See https://llvm.org/LICENSE.txt for license information.
573471bf0Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
673471bf0Spatrick //
773471bf0Spatrick //===----------------------------------------------------------------------===//
873471bf0Spatrick ///
973471bf0Spatrick /// \file
1073471bf0Spatrick /// This file contains defintions for M68k code emitter.
1173471bf0Spatrick ///
1273471bf0Spatrick //===----------------------------------------------------------------------===//
1373471bf0Spatrick 
1473471bf0Spatrick #include "MCTargetDesc/M68kMCCodeEmitter.h"
1573471bf0Spatrick #include "MCTargetDesc/M68kBaseInfo.h"
1673471bf0Spatrick #include "MCTargetDesc/M68kFixupKinds.h"
1773471bf0Spatrick #include "MCTargetDesc/M68kMCTargetDesc.h"
1873471bf0Spatrick 
1973471bf0Spatrick #include "llvm/MC/MCCodeEmitter.h"
2073471bf0Spatrick #include "llvm/MC/MCContext.h"
2173471bf0Spatrick #include "llvm/MC/MCExpr.h"
2273471bf0Spatrick #include "llvm/MC/MCInst.h"
2373471bf0Spatrick #include "llvm/MC/MCInstrInfo.h"
2473471bf0Spatrick #include "llvm/MC/MCRegisterInfo.h"
2573471bf0Spatrick #include "llvm/MC/MCSubtargetInfo.h"
2673471bf0Spatrick #include "llvm/MC/MCSymbol.h"
2773471bf0Spatrick #include "llvm/Support/Debug.h"
2873471bf0Spatrick #include "llvm/Support/EndianStream.h"
2973471bf0Spatrick #include "llvm/Support/raw_ostream.h"
30*d415bd75Srobert #include <type_traits>
3173471bf0Spatrick 
3273471bf0Spatrick using namespace llvm;
3373471bf0Spatrick 
3473471bf0Spatrick #define DEBUG_TYPE "m68k-mccodeemitter"
3573471bf0Spatrick 
3673471bf0Spatrick namespace {
3773471bf0Spatrick class M68kMCCodeEmitter : public MCCodeEmitter {
3873471bf0Spatrick   M68kMCCodeEmitter(const M68kMCCodeEmitter &) = delete;
3973471bf0Spatrick   void operator=(const M68kMCCodeEmitter &) = delete;
4073471bf0Spatrick   const MCInstrInfo &MCII;
4173471bf0Spatrick   MCContext &Ctx;
4273471bf0Spatrick 
43*d415bd75Srobert   void getBinaryCodeForInstr(const MCInst &MI, SmallVectorImpl<MCFixup> &Fixups,
44*d415bd75Srobert                              APInt &Inst, APInt &Scratch,
45*d415bd75Srobert                              const MCSubtargetInfo &STI) const;
46*d415bd75Srobert 
47*d415bd75Srobert   void getMachineOpValue(const MCInst &MI, const MCOperand &Op,
48*d415bd75Srobert                          unsigned InsertPos, APInt &Value,
49*d415bd75Srobert                          SmallVectorImpl<MCFixup> &Fixups,
50*d415bd75Srobert                          const MCSubtargetInfo &STI) const;
51*d415bd75Srobert 
52*d415bd75Srobert   template <unsigned Size>
53*d415bd75Srobert   void encodeRelocImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,
54*d415bd75Srobert                       APInt &Value, SmallVectorImpl<MCFixup> &Fixups,
55*d415bd75Srobert                       const MCSubtargetInfo &STI) const;
56*d415bd75Srobert 
57*d415bd75Srobert   template <unsigned Size>
58*d415bd75Srobert   void encodePCRelImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,
59*d415bd75Srobert                       APInt &Value, SmallVectorImpl<MCFixup> &Fixups,
60*d415bd75Srobert                       const MCSubtargetInfo &STI) const;
61*d415bd75Srobert 
6273471bf0Spatrick public:
M68kMCCodeEmitter(const MCInstrInfo & mcii,MCContext & ctx)6373471bf0Spatrick   M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
6473471bf0Spatrick       : MCII(mcii), Ctx(ctx) {}
6573471bf0Spatrick 
~M68kMCCodeEmitter()6673471bf0Spatrick   ~M68kMCCodeEmitter() override {}
6773471bf0Spatrick 
6873471bf0Spatrick   void encodeInstruction(const MCInst &MI, raw_ostream &OS,
6973471bf0Spatrick                          SmallVectorImpl<MCFixup> &Fixups,
7073471bf0Spatrick                          const MCSubtargetInfo &STI) const override;
7173471bf0Spatrick };
7273471bf0Spatrick 
7373471bf0Spatrick } // end anonymous namespace
7473471bf0Spatrick 
75*d415bd75Srobert #include "M68kGenMCCodeEmitter.inc"
76*d415bd75Srobert 
77*d415bd75Srobert // Select the proper unsigned integer type from a bit size.
78*d415bd75Srobert template <unsigned Size> struct select_uint_t {
79*d415bd75Srobert   using type = typename std::conditional<
80*d415bd75Srobert       Size == 8, uint8_t,
81*d415bd75Srobert       typename std::conditional<
82*d415bd75Srobert           Size == 16, uint16_t,
83*d415bd75Srobert           typename std::conditional<Size == 32, uint32_t,
84*d415bd75Srobert                                     uint64_t>::type>::type>::type;
85*d415bd75Srobert };
86*d415bd75Srobert 
87*d415bd75Srobert // Figure out which byte we're at in big endian mode.
getBytePosition(unsigned BitPos)88*d415bd75Srobert template <unsigned Size> static unsigned getBytePosition(unsigned BitPos) {
89*d415bd75Srobert   if (Size % 16) {
90*d415bd75Srobert     return static_cast<unsigned>(BitPos / 8 + ((BitPos & 0b1111) < 8 ? 1 : -1));
91*d415bd75Srobert   } else {
92*d415bd75Srobert     assert(!(BitPos & 0b1111) && "Not aligned to word boundary?");
93*d415bd75Srobert     return BitPos / 8;
94*d415bd75Srobert   }
95*d415bd75Srobert }
96*d415bd75Srobert 
97*d415bd75Srobert // We need special handlings for relocatable & pc-relative operands that are
98*d415bd75Srobert // larger than a word.
99*d415bd75Srobert // A M68k instruction is aligned by word (16 bits). That means, 32-bit
100*d415bd75Srobert // (& 64-bit) immediate values are separated into hi & lo words and placed
101*d415bd75Srobert // at lower & higher addresses, respectively. For immediate values that can
102*d415bd75Srobert // be easily expressed in TG, we explicitly rotate the word ordering like
103*d415bd75Srobert // this:
104*d415bd75Srobert // ```
105*d415bd75Srobert // (ascend (slice "$imm", 31, 16), (slice "$imm", 15, 0))
106*d415bd75Srobert // ```
107*d415bd75Srobert // For operands that call into encoder functions, we need to use the `swapWord`
108*d415bd75Srobert // function to assure the correct word ordering on LE host. Note that
109*d415bd75Srobert // M68kMCCodeEmitter does massage _byte_ ordering of the final encoded
110*d415bd75Srobert // instruction but it assumes everything aligns on word boundaries. So things
111*d415bd75Srobert // will go wrong if we don't take care of the _word_ ordering here.
112*d415bd75Srobert template <unsigned Size>
encodeRelocImm(const MCInst & MI,unsigned OpIdx,unsigned InsertPos,APInt & Value,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const113*d415bd75Srobert void M68kMCCodeEmitter::encodeRelocImm(const MCInst &MI, unsigned OpIdx,
114*d415bd75Srobert                                        unsigned InsertPos, APInt &Value,
11573471bf0Spatrick                                        SmallVectorImpl<MCFixup> &Fixups,
11673471bf0Spatrick                                        const MCSubtargetInfo &STI) const {
117*d415bd75Srobert   using value_t = typename select_uint_t<Size>::type;
118*d415bd75Srobert   const MCOperand &MCO = MI.getOperand(OpIdx);
119*d415bd75Srobert   if (MCO.isImm()) {
120*d415bd75Srobert     Value |= M68k::swapWord<value_t>(static_cast<value_t>(MCO.getImm()));
121*d415bd75Srobert   } else if (MCO.isExpr()) {
12273471bf0Spatrick     const MCExpr *Expr = MCO.getExpr();
12373471bf0Spatrick 
124*d415bd75Srobert     // Absolute address
125*d415bd75Srobert     int64_t Addr;
126*d415bd75Srobert     if (Expr->evaluateAsAbsolute(Addr)) {
127*d415bd75Srobert       Value |= M68k::swapWord<value_t>(static_cast<value_t>(Addr));
128*d415bd75Srobert       return;
12973471bf0Spatrick     }
13073471bf0Spatrick 
131*d415bd75Srobert     // Relocatable address
132*d415bd75Srobert     unsigned InsertByte = getBytePosition<Size>(InsertPos);
133*d415bd75Srobert     Fixups.push_back(MCFixup::create(InsertByte, Expr,
134*d415bd75Srobert                                      getFixupForSize(Size, /*IsPCRel=*/false),
135*d415bd75Srobert                                      MI.getLoc()));
136*d415bd75Srobert   }
13773471bf0Spatrick }
13873471bf0Spatrick 
139*d415bd75Srobert template <unsigned Size>
encodePCRelImm(const MCInst & MI,unsigned OpIdx,unsigned InsertPos,APInt & Value,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const140*d415bd75Srobert void M68kMCCodeEmitter::encodePCRelImm(const MCInst &MI, unsigned OpIdx,
141*d415bd75Srobert                                        unsigned InsertPos, APInt &Value,
142*d415bd75Srobert                                        SmallVectorImpl<MCFixup> &Fixups,
143*d415bd75Srobert                                        const MCSubtargetInfo &STI) const {
144*d415bd75Srobert   const MCOperand &MCO = MI.getOperand(OpIdx);
145*d415bd75Srobert   if (MCO.isImm()) {
146*d415bd75Srobert     using value_t = typename select_uint_t<Size>::type;
147*d415bd75Srobert     Value |= M68k::swapWord<value_t>(static_cast<value_t>(MCO.getImm()));
148*d415bd75Srobert   } else if (MCO.isExpr()) {
14973471bf0Spatrick     const MCExpr *Expr = MCO.getExpr();
150*d415bd75Srobert     unsigned InsertByte = getBytePosition<Size>(InsertPos);
15173471bf0Spatrick 
152*d415bd75Srobert     // Special handlings for sizes smaller than a word.
153*d415bd75Srobert     if (Size < 16) {
154*d415bd75Srobert       int LabelOffset = 0;
155*d415bd75Srobert       if (InsertPos < 16)
156*d415bd75Srobert         // If the patch point is at the first word, PC is pointing at the
157*d415bd75Srobert         // next word.
158*d415bd75Srobert         LabelOffset = InsertByte - 2;
159*d415bd75Srobert       else if (InsertByte % 2)
160*d415bd75Srobert         // Otherwise the PC is pointing at the first byte of this word.
161*d415bd75Srobert         // So we need to consider the offset between PC and the fixup byte.
162*d415bd75Srobert         LabelOffset = 1;
163*d415bd75Srobert 
164*d415bd75Srobert       if (LabelOffset)
16573471bf0Spatrick         Expr = MCBinaryExpr::createAdd(
166*d415bd75Srobert             Expr, MCConstantExpr::create(LabelOffset, Ctx), Ctx);
16773471bf0Spatrick     }
16873471bf0Spatrick 
169*d415bd75Srobert     Fixups.push_back(MCFixup::create(InsertByte, Expr,
170*d415bd75Srobert                                      getFixupForSize(Size, /*IsPCRel=*/true),
171*d415bd75Srobert                                      MI.getLoc()));
17273471bf0Spatrick   }
17373471bf0Spatrick }
17473471bf0Spatrick 
getMachineOpValue(const MCInst & MI,const MCOperand & Op,unsigned InsertPos,APInt & Value,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const175*d415bd75Srobert void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op,
176*d415bd75Srobert                                           unsigned InsertPos, APInt &Value,
177*d415bd75Srobert                                           SmallVectorImpl<MCFixup> &Fixups,
178*d415bd75Srobert                                           const MCSubtargetInfo &STI) const {
179*d415bd75Srobert   // Register
180*d415bd75Srobert   if (Op.isReg()) {
181*d415bd75Srobert     unsigned RegNum = Op.getReg();
182*d415bd75Srobert     const auto *RI = Ctx.getRegisterInfo();
183*d415bd75Srobert     Value |= RI->getEncodingValue(RegNum);
184*d415bd75Srobert     // Setup the D/A bit
185*d415bd75Srobert     if (M68kII::isAddressRegister(RegNum))
186*d415bd75Srobert       Value |= 0b1000;
187*d415bd75Srobert   } else if (Op.isImm()) {
188*d415bd75Srobert     // Immediate
189*d415bd75Srobert     Value |= static_cast<uint64_t>(Op.getImm());
190*d415bd75Srobert   } else if (Op.isExpr()) {
191*d415bd75Srobert     // Absolute address
192*d415bd75Srobert     int64_t Addr;
193*d415bd75Srobert     if (!Op.getExpr()->evaluateAsAbsolute(Addr))
194*d415bd75Srobert       report_fatal_error("Unsupported asm expression. Only absolute address "
195*d415bd75Srobert                          "can be placed here.");
196*d415bd75Srobert     Value |= static_cast<uint64_t>(Addr);
19773471bf0Spatrick   } else {
198*d415bd75Srobert     llvm_unreachable("Unsupported operand type");
19973471bf0Spatrick   }
20073471bf0Spatrick }
20173471bf0Spatrick 
encodeInstruction(const MCInst & MI,raw_ostream & OS,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const20273471bf0Spatrick void M68kMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
20373471bf0Spatrick                                           SmallVectorImpl<MCFixup> &Fixups,
20473471bf0Spatrick                                           const MCSubtargetInfo &STI) const {
20573471bf0Spatrick   unsigned Opcode = MI.getOpcode();
20673471bf0Spatrick 
20773471bf0Spatrick   LLVM_DEBUG(dbgs() << "EncodeInstruction: " << MCII.getName(Opcode) << "("
20873471bf0Spatrick                     << Opcode << ")\n");
20973471bf0Spatrick 
210*d415bd75Srobert   // Try using the new method first.
211*d415bd75Srobert   APInt EncodedInst(16, 0U);
212*d415bd75Srobert   APInt Scratch(16, 0U);
213*d415bd75Srobert   getBinaryCodeForInstr(MI, Fixups, EncodedInst, Scratch, STI);
21473471bf0Spatrick 
215*d415bd75Srobert   ArrayRef<uint64_t> Data(EncodedInst.getRawData(), EncodedInst.getNumWords());
216*d415bd75Srobert   int64_t InstSize = EncodedInst.getBitWidth();
217*d415bd75Srobert   for (uint64_t Word : Data) {
218*d415bd75Srobert     for (int i = 0; i < 4 && InstSize > 0; ++i, InstSize -= 16) {
219*d415bd75Srobert       support::endian::write<uint16_t>(OS, static_cast<uint16_t>(Word),
220*d415bd75Srobert                                        support::big);
221*d415bd75Srobert       Word >>= 16;
22273471bf0Spatrick     }
22373471bf0Spatrick   }
22473471bf0Spatrick }
22573471bf0Spatrick 
createM68kMCCodeEmitter(const MCInstrInfo & MCII,MCContext & Ctx)22673471bf0Spatrick MCCodeEmitter *llvm::createM68kMCCodeEmitter(const MCInstrInfo &MCII,
22773471bf0Spatrick                                              MCContext &Ctx) {
22873471bf0Spatrick   return new M68kMCCodeEmitter(MCII, Ctx);
22973471bf0Spatrick }
230