xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
104eeddc0SDimitry Andric //===-- M68kMCCodeEmitter.cpp - Convert M68k code emitter -------*- C++ -*-===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric ///
9fe6060f1SDimitry Andric /// \file
10fe6060f1SDimitry Andric /// This file contains defintions for M68k code emitter.
11fe6060f1SDimitry Andric ///
12fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
13fe6060f1SDimitry Andric 
14fe6060f1SDimitry Andric #include "MCTargetDesc/M68kMCCodeEmitter.h"
15fe6060f1SDimitry Andric #include "MCTargetDesc/M68kBaseInfo.h"
16fe6060f1SDimitry Andric #include "MCTargetDesc/M68kFixupKinds.h"
17fe6060f1SDimitry Andric #include "MCTargetDesc/M68kMCTargetDesc.h"
18fe6060f1SDimitry Andric 
19fe6060f1SDimitry Andric #include "llvm/MC/MCCodeEmitter.h"
20fe6060f1SDimitry Andric #include "llvm/MC/MCContext.h"
21fe6060f1SDimitry Andric #include "llvm/MC/MCExpr.h"
22fe6060f1SDimitry Andric #include "llvm/MC/MCInst.h"
23fe6060f1SDimitry Andric #include "llvm/MC/MCInstrInfo.h"
24fe6060f1SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
25fe6060f1SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
26fe6060f1SDimitry Andric #include "llvm/MC/MCSymbol.h"
27fe6060f1SDimitry Andric #include "llvm/Support/Debug.h"
28fe6060f1SDimitry Andric #include "llvm/Support/EndianStream.h"
29fe6060f1SDimitry Andric #include "llvm/Support/raw_ostream.h"
3081ad6265SDimitry Andric #include <type_traits>
31fe6060f1SDimitry Andric 
32fe6060f1SDimitry Andric using namespace llvm;
33fe6060f1SDimitry Andric 
34fe6060f1SDimitry Andric #define DEBUG_TYPE "m68k-mccodeemitter"
35fe6060f1SDimitry Andric 
36fe6060f1SDimitry Andric namespace {
37fe6060f1SDimitry Andric class M68kMCCodeEmitter : public MCCodeEmitter {
38fe6060f1SDimitry Andric   M68kMCCodeEmitter(const M68kMCCodeEmitter &) = delete;
39fe6060f1SDimitry Andric   void operator=(const M68kMCCodeEmitter &) = delete;
40fe6060f1SDimitry Andric   const MCInstrInfo &MCII;
41fe6060f1SDimitry Andric   MCContext &Ctx;
42fe6060f1SDimitry Andric 
4381ad6265SDimitry Andric   void getBinaryCodeForInstr(const MCInst &MI, SmallVectorImpl<MCFixup> &Fixups,
4481ad6265SDimitry Andric                              APInt &Inst, APInt &Scratch,
4581ad6265SDimitry Andric                              const MCSubtargetInfo &STI) const;
4681ad6265SDimitry Andric 
4781ad6265SDimitry Andric   void getMachineOpValue(const MCInst &MI, const MCOperand &Op,
4881ad6265SDimitry Andric                          unsigned InsertPos, APInt &Value,
4981ad6265SDimitry Andric                          SmallVectorImpl<MCFixup> &Fixups,
5081ad6265SDimitry Andric                          const MCSubtargetInfo &STI) const;
5181ad6265SDimitry Andric 
5281ad6265SDimitry Andric   template <unsigned Size>
5381ad6265SDimitry Andric   void encodeRelocImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,
5481ad6265SDimitry Andric                       APInt &Value, SmallVectorImpl<MCFixup> &Fixups,
5581ad6265SDimitry Andric                       const MCSubtargetInfo &STI) const;
5681ad6265SDimitry Andric 
5781ad6265SDimitry Andric   template <unsigned Size>
5881ad6265SDimitry Andric   void encodePCRelImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,
5981ad6265SDimitry Andric                       APInt &Value, SmallVectorImpl<MCFixup> &Fixups,
6081ad6265SDimitry Andric                       const MCSubtargetInfo &STI) const;
6181ad6265SDimitry Andric 
62fe6060f1SDimitry Andric public:
63fe6060f1SDimitry Andric   M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
64fe6060f1SDimitry Andric       : MCII(mcii), Ctx(ctx) {}
65fe6060f1SDimitry Andric 
66fe6060f1SDimitry Andric   ~M68kMCCodeEmitter() override {}
67fe6060f1SDimitry Andric 
68*06c3fb27SDimitry Andric   void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,
69fe6060f1SDimitry Andric                          SmallVectorImpl<MCFixup> &Fixups,
70fe6060f1SDimitry Andric                          const MCSubtargetInfo &STI) const override;
71fe6060f1SDimitry Andric };
72fe6060f1SDimitry Andric 
73fe6060f1SDimitry Andric } // end anonymous namespace
74fe6060f1SDimitry Andric 
7581ad6265SDimitry Andric #include "M68kGenMCCodeEmitter.inc"
7681ad6265SDimitry Andric 
7781ad6265SDimitry Andric // Select the proper unsigned integer type from a bit size.
7881ad6265SDimitry Andric template <unsigned Size> struct select_uint_t {
7981ad6265SDimitry Andric   using type = typename std::conditional<
8081ad6265SDimitry Andric       Size == 8, uint8_t,
8181ad6265SDimitry Andric       typename std::conditional<
8281ad6265SDimitry Andric           Size == 16, uint16_t,
8381ad6265SDimitry Andric           typename std::conditional<Size == 32, uint32_t,
8481ad6265SDimitry Andric                                     uint64_t>::type>::type>::type;
8581ad6265SDimitry Andric };
8681ad6265SDimitry Andric 
8781ad6265SDimitry Andric // Figure out which byte we're at in big endian mode.
8881ad6265SDimitry Andric template <unsigned Size> static unsigned getBytePosition(unsigned BitPos) {
8981ad6265SDimitry Andric   if (Size % 16) {
9081ad6265SDimitry Andric     return static_cast<unsigned>(BitPos / 8 + ((BitPos & 0b1111) < 8 ? 1 : -1));
9181ad6265SDimitry Andric   } else {
9281ad6265SDimitry Andric     assert(!(BitPos & 0b1111) && "Not aligned to word boundary?");
9381ad6265SDimitry Andric     return BitPos / 8;
9481ad6265SDimitry Andric   }
9581ad6265SDimitry Andric }
9681ad6265SDimitry Andric 
9781ad6265SDimitry Andric // We need special handlings for relocatable & pc-relative operands that are
9881ad6265SDimitry Andric // larger than a word.
9981ad6265SDimitry Andric // A M68k instruction is aligned by word (16 bits). That means, 32-bit
10081ad6265SDimitry Andric // (& 64-bit) immediate values are separated into hi & lo words and placed
10181ad6265SDimitry Andric // at lower & higher addresses, respectively. For immediate values that can
10281ad6265SDimitry Andric // be easily expressed in TG, we explicitly rotate the word ordering like
10381ad6265SDimitry Andric // this:
10481ad6265SDimitry Andric // ```
10581ad6265SDimitry Andric // (ascend (slice "$imm", 31, 16), (slice "$imm", 15, 0))
10681ad6265SDimitry Andric // ```
10781ad6265SDimitry Andric // For operands that call into encoder functions, we need to use the `swapWord`
10881ad6265SDimitry Andric // function to assure the correct word ordering on LE host. Note that
10981ad6265SDimitry Andric // M68kMCCodeEmitter does massage _byte_ ordering of the final encoded
11081ad6265SDimitry Andric // instruction but it assumes everything aligns on word boundaries. So things
11181ad6265SDimitry Andric // will go wrong if we don't take care of the _word_ ordering here.
11281ad6265SDimitry Andric template <unsigned Size>
11381ad6265SDimitry Andric void M68kMCCodeEmitter::encodeRelocImm(const MCInst &MI, unsigned OpIdx,
11481ad6265SDimitry Andric                                        unsigned InsertPos, APInt &Value,
115fe6060f1SDimitry Andric                                        SmallVectorImpl<MCFixup> &Fixups,
116fe6060f1SDimitry Andric                                        const MCSubtargetInfo &STI) const {
11781ad6265SDimitry Andric   using value_t = typename select_uint_t<Size>::type;
11881ad6265SDimitry Andric   const MCOperand &MCO = MI.getOperand(OpIdx);
11981ad6265SDimitry Andric   if (MCO.isImm()) {
120bdd1243dSDimitry Andric     Value |= M68k::swapWord<value_t>(static_cast<value_t>(MCO.getImm()));
12181ad6265SDimitry Andric   } else if (MCO.isExpr()) {
122fe6060f1SDimitry Andric     const MCExpr *Expr = MCO.getExpr();
123fe6060f1SDimitry Andric 
12481ad6265SDimitry Andric     // Absolute address
12581ad6265SDimitry Andric     int64_t Addr;
12681ad6265SDimitry Andric     if (Expr->evaluateAsAbsolute(Addr)) {
127bdd1243dSDimitry Andric       Value |= M68k::swapWord<value_t>(static_cast<value_t>(Addr));
12881ad6265SDimitry Andric       return;
129fe6060f1SDimitry Andric     }
130fe6060f1SDimitry Andric 
13181ad6265SDimitry Andric     // Relocatable address
13281ad6265SDimitry Andric     unsigned InsertByte = getBytePosition<Size>(InsertPos);
13381ad6265SDimitry Andric     Fixups.push_back(MCFixup::create(InsertByte, Expr,
13481ad6265SDimitry Andric                                      getFixupForSize(Size, /*IsPCRel=*/false),
13581ad6265SDimitry Andric                                      MI.getLoc()));
13681ad6265SDimitry Andric   }
137fe6060f1SDimitry Andric }
138fe6060f1SDimitry Andric 
13981ad6265SDimitry Andric template <unsigned Size>
14081ad6265SDimitry Andric void M68kMCCodeEmitter::encodePCRelImm(const MCInst &MI, unsigned OpIdx,
14181ad6265SDimitry Andric                                        unsigned InsertPos, APInt &Value,
14281ad6265SDimitry Andric                                        SmallVectorImpl<MCFixup> &Fixups,
14381ad6265SDimitry Andric                                        const MCSubtargetInfo &STI) const {
14481ad6265SDimitry Andric   const MCOperand &MCO = MI.getOperand(OpIdx);
14581ad6265SDimitry Andric   if (MCO.isImm()) {
14681ad6265SDimitry Andric     using value_t = typename select_uint_t<Size>::type;
147bdd1243dSDimitry Andric     Value |= M68k::swapWord<value_t>(static_cast<value_t>(MCO.getImm()));
14881ad6265SDimitry Andric   } else if (MCO.isExpr()) {
149fe6060f1SDimitry Andric     const MCExpr *Expr = MCO.getExpr();
15081ad6265SDimitry Andric     unsigned InsertByte = getBytePosition<Size>(InsertPos);
151fe6060f1SDimitry Andric 
15281ad6265SDimitry Andric     // Special handlings for sizes smaller than a word.
15381ad6265SDimitry Andric     if (Size < 16) {
15481ad6265SDimitry Andric       int LabelOffset = 0;
15581ad6265SDimitry Andric       if (InsertPos < 16)
15681ad6265SDimitry Andric         // If the patch point is at the first word, PC is pointing at the
15781ad6265SDimitry Andric         // next word.
15881ad6265SDimitry Andric         LabelOffset = InsertByte - 2;
15981ad6265SDimitry Andric       else if (InsertByte % 2)
16081ad6265SDimitry Andric         // Otherwise the PC is pointing at the first byte of this word.
16181ad6265SDimitry Andric         // So we need to consider the offset between PC and the fixup byte.
16281ad6265SDimitry Andric         LabelOffset = 1;
16381ad6265SDimitry Andric 
16481ad6265SDimitry Andric       if (LabelOffset)
165fe6060f1SDimitry Andric         Expr = MCBinaryExpr::createAdd(
16681ad6265SDimitry Andric             Expr, MCConstantExpr::create(LabelOffset, Ctx), Ctx);
167fe6060f1SDimitry Andric     }
168fe6060f1SDimitry Andric 
16981ad6265SDimitry Andric     Fixups.push_back(MCFixup::create(InsertByte, Expr,
17081ad6265SDimitry Andric                                      getFixupForSize(Size, /*IsPCRel=*/true),
17181ad6265SDimitry Andric                                      MI.getLoc()));
172fe6060f1SDimitry Andric   }
173fe6060f1SDimitry Andric }
174fe6060f1SDimitry Andric 
17581ad6265SDimitry Andric void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op,
17681ad6265SDimitry Andric                                           unsigned InsertPos, APInt &Value,
17781ad6265SDimitry Andric                                           SmallVectorImpl<MCFixup> &Fixups,
17881ad6265SDimitry Andric                                           const MCSubtargetInfo &STI) const {
17981ad6265SDimitry Andric   // Register
18081ad6265SDimitry Andric   if (Op.isReg()) {
18181ad6265SDimitry Andric     unsigned RegNum = Op.getReg();
18281ad6265SDimitry Andric     const auto *RI = Ctx.getRegisterInfo();
18381ad6265SDimitry Andric     Value |= RI->getEncodingValue(RegNum);
18481ad6265SDimitry Andric     // Setup the D/A bit
18581ad6265SDimitry Andric     if (M68kII::isAddressRegister(RegNum))
18681ad6265SDimitry Andric       Value |= 0b1000;
18781ad6265SDimitry Andric   } else if (Op.isImm()) {
18881ad6265SDimitry Andric     // Immediate
18981ad6265SDimitry Andric     Value |= static_cast<uint64_t>(Op.getImm());
19081ad6265SDimitry Andric   } else if (Op.isExpr()) {
19181ad6265SDimitry Andric     // Absolute address
19281ad6265SDimitry Andric     int64_t Addr;
19381ad6265SDimitry Andric     if (!Op.getExpr()->evaluateAsAbsolute(Addr))
19481ad6265SDimitry Andric       report_fatal_error("Unsupported asm expression. Only absolute address "
19581ad6265SDimitry Andric                          "can be placed here.");
19681ad6265SDimitry Andric     Value |= static_cast<uint64_t>(Addr);
197fe6060f1SDimitry Andric   } else {
19881ad6265SDimitry Andric     llvm_unreachable("Unsupported operand type");
199fe6060f1SDimitry Andric   }
200fe6060f1SDimitry Andric }
201fe6060f1SDimitry Andric 
202*06c3fb27SDimitry Andric void M68kMCCodeEmitter::encodeInstruction(const MCInst &MI,
203*06c3fb27SDimitry Andric                                           SmallVectorImpl<char> &CB,
204fe6060f1SDimitry Andric                                           SmallVectorImpl<MCFixup> &Fixups,
205fe6060f1SDimitry Andric                                           const MCSubtargetInfo &STI) const {
206fe6060f1SDimitry Andric   unsigned Opcode = MI.getOpcode();
207fe6060f1SDimitry Andric 
208fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "EncodeInstruction: " << MCII.getName(Opcode) << "("
209fe6060f1SDimitry Andric                     << Opcode << ")\n");
210fe6060f1SDimitry Andric 
21181ad6265SDimitry Andric   // Try using the new method first.
21281ad6265SDimitry Andric   APInt EncodedInst(16, 0U);
21381ad6265SDimitry Andric   APInt Scratch(16, 0U);
21481ad6265SDimitry Andric   getBinaryCodeForInstr(MI, Fixups, EncodedInst, Scratch, STI);
215fe6060f1SDimitry Andric 
21681ad6265SDimitry Andric   ArrayRef<uint64_t> Data(EncodedInst.getRawData(), EncodedInst.getNumWords());
21781ad6265SDimitry Andric   int64_t InstSize = EncodedInst.getBitWidth();
21881ad6265SDimitry Andric   for (uint64_t Word : Data) {
21981ad6265SDimitry Andric     for (int i = 0; i < 4 && InstSize > 0; ++i, InstSize -= 16) {
220*06c3fb27SDimitry Andric       support::endian::write<uint16_t>(CB, static_cast<uint16_t>(Word),
22181ad6265SDimitry Andric                                        support::big);
22281ad6265SDimitry Andric       Word >>= 16;
223fe6060f1SDimitry Andric     }
224fe6060f1SDimitry Andric   }
225fe6060f1SDimitry Andric }
226fe6060f1SDimitry Andric 
227fe6060f1SDimitry Andric MCCodeEmitter *llvm::createM68kMCCodeEmitter(const MCInstrInfo &MCII,
228fe6060f1SDimitry Andric                                              MCContext &Ctx) {
229fe6060f1SDimitry Andric   return new M68kMCCodeEmitter(MCII, Ctx);
230fe6060f1SDimitry Andric }
231