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
62*5f757f3fSDimitry Andric void encodeFPSYSSelect(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,
63*5f757f3fSDimitry Andric APInt &Value, SmallVectorImpl<MCFixup> &Fixups,
64*5f757f3fSDimitry Andric const MCSubtargetInfo &STI) const;
65*5f757f3fSDimitry Andric
66fe6060f1SDimitry Andric public:
M68kMCCodeEmitter(const MCInstrInfo & mcii,MCContext & ctx)67fe6060f1SDimitry Andric M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
68fe6060f1SDimitry Andric : MCII(mcii), Ctx(ctx) {}
69fe6060f1SDimitry Andric
~M68kMCCodeEmitter()70fe6060f1SDimitry Andric ~M68kMCCodeEmitter() override {}
71fe6060f1SDimitry Andric
7206c3fb27SDimitry Andric void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,
73fe6060f1SDimitry Andric SmallVectorImpl<MCFixup> &Fixups,
74fe6060f1SDimitry Andric const MCSubtargetInfo &STI) const override;
75fe6060f1SDimitry Andric };
76fe6060f1SDimitry Andric
77fe6060f1SDimitry Andric } // end anonymous namespace
78fe6060f1SDimitry Andric
7981ad6265SDimitry Andric #include "M68kGenMCCodeEmitter.inc"
8081ad6265SDimitry Andric
8181ad6265SDimitry Andric // Select the proper unsigned integer type from a bit size.
8281ad6265SDimitry Andric template <unsigned Size> struct select_uint_t {
8381ad6265SDimitry Andric using type = typename std::conditional<
8481ad6265SDimitry Andric Size == 8, uint8_t,
8581ad6265SDimitry Andric typename std::conditional<
8681ad6265SDimitry Andric Size == 16, uint16_t,
8781ad6265SDimitry Andric typename std::conditional<Size == 32, uint32_t,
8881ad6265SDimitry Andric uint64_t>::type>::type>::type;
8981ad6265SDimitry Andric };
9081ad6265SDimitry Andric
9181ad6265SDimitry Andric // Figure out which byte we're at in big endian mode.
getBytePosition(unsigned BitPos)9281ad6265SDimitry Andric template <unsigned Size> static unsigned getBytePosition(unsigned BitPos) {
9381ad6265SDimitry Andric if (Size % 16) {
9481ad6265SDimitry Andric return static_cast<unsigned>(BitPos / 8 + ((BitPos & 0b1111) < 8 ? 1 : -1));
9581ad6265SDimitry Andric } else {
9681ad6265SDimitry Andric assert(!(BitPos & 0b1111) && "Not aligned to word boundary?");
9781ad6265SDimitry Andric return BitPos / 8;
9881ad6265SDimitry Andric }
9981ad6265SDimitry Andric }
10081ad6265SDimitry Andric
10181ad6265SDimitry Andric // We need special handlings for relocatable & pc-relative operands that are
10281ad6265SDimitry Andric // larger than a word.
10381ad6265SDimitry Andric // A M68k instruction is aligned by word (16 bits). That means, 32-bit
10481ad6265SDimitry Andric // (& 64-bit) immediate values are separated into hi & lo words and placed
10581ad6265SDimitry Andric // at lower & higher addresses, respectively. For immediate values that can
10681ad6265SDimitry Andric // be easily expressed in TG, we explicitly rotate the word ordering like
10781ad6265SDimitry Andric // this:
10881ad6265SDimitry Andric // ```
10981ad6265SDimitry Andric // (ascend (slice "$imm", 31, 16), (slice "$imm", 15, 0))
11081ad6265SDimitry Andric // ```
11181ad6265SDimitry Andric // For operands that call into encoder functions, we need to use the `swapWord`
11281ad6265SDimitry Andric // function to assure the correct word ordering on LE host. Note that
11381ad6265SDimitry Andric // M68kMCCodeEmitter does massage _byte_ ordering of the final encoded
11481ad6265SDimitry Andric // instruction but it assumes everything aligns on word boundaries. So things
11581ad6265SDimitry Andric // will go wrong if we don't take care of the _word_ ordering here.
11681ad6265SDimitry Andric template <unsigned Size>
encodeRelocImm(const MCInst & MI,unsigned OpIdx,unsigned InsertPos,APInt & Value,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const11781ad6265SDimitry Andric void M68kMCCodeEmitter::encodeRelocImm(const MCInst &MI, unsigned OpIdx,
11881ad6265SDimitry Andric unsigned InsertPos, APInt &Value,
119fe6060f1SDimitry Andric SmallVectorImpl<MCFixup> &Fixups,
120fe6060f1SDimitry Andric const MCSubtargetInfo &STI) const {
12181ad6265SDimitry Andric using value_t = typename select_uint_t<Size>::type;
12281ad6265SDimitry Andric const MCOperand &MCO = MI.getOperand(OpIdx);
12381ad6265SDimitry Andric if (MCO.isImm()) {
124bdd1243dSDimitry Andric Value |= M68k::swapWord<value_t>(static_cast<value_t>(MCO.getImm()));
12581ad6265SDimitry Andric } else if (MCO.isExpr()) {
126fe6060f1SDimitry Andric const MCExpr *Expr = MCO.getExpr();
127fe6060f1SDimitry Andric
12881ad6265SDimitry Andric // Absolute address
12981ad6265SDimitry Andric int64_t Addr;
13081ad6265SDimitry Andric if (Expr->evaluateAsAbsolute(Addr)) {
131bdd1243dSDimitry Andric Value |= M68k::swapWord<value_t>(static_cast<value_t>(Addr));
13281ad6265SDimitry Andric return;
133fe6060f1SDimitry Andric }
134fe6060f1SDimitry Andric
13581ad6265SDimitry Andric // Relocatable address
13681ad6265SDimitry Andric unsigned InsertByte = getBytePosition<Size>(InsertPos);
13781ad6265SDimitry Andric Fixups.push_back(MCFixup::create(InsertByte, Expr,
13881ad6265SDimitry Andric getFixupForSize(Size, /*IsPCRel=*/false),
13981ad6265SDimitry Andric MI.getLoc()));
14081ad6265SDimitry Andric }
141fe6060f1SDimitry Andric }
142fe6060f1SDimitry Andric
14381ad6265SDimitry Andric template <unsigned Size>
encodePCRelImm(const MCInst & MI,unsigned OpIdx,unsigned InsertPos,APInt & Value,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const14481ad6265SDimitry Andric void M68kMCCodeEmitter::encodePCRelImm(const MCInst &MI, unsigned OpIdx,
14581ad6265SDimitry Andric unsigned InsertPos, APInt &Value,
14681ad6265SDimitry Andric SmallVectorImpl<MCFixup> &Fixups,
14781ad6265SDimitry Andric const MCSubtargetInfo &STI) const {
14881ad6265SDimitry Andric const MCOperand &MCO = MI.getOperand(OpIdx);
14981ad6265SDimitry Andric if (MCO.isImm()) {
15081ad6265SDimitry Andric using value_t = typename select_uint_t<Size>::type;
151bdd1243dSDimitry Andric Value |= M68k::swapWord<value_t>(static_cast<value_t>(MCO.getImm()));
15281ad6265SDimitry Andric } else if (MCO.isExpr()) {
153fe6060f1SDimitry Andric const MCExpr *Expr = MCO.getExpr();
15481ad6265SDimitry Andric unsigned InsertByte = getBytePosition<Size>(InsertPos);
155fe6060f1SDimitry Andric
15681ad6265SDimitry Andric // Special handlings for sizes smaller than a word.
15781ad6265SDimitry Andric if (Size < 16) {
15881ad6265SDimitry Andric int LabelOffset = 0;
15981ad6265SDimitry Andric if (InsertPos < 16)
16081ad6265SDimitry Andric // If the patch point is at the first word, PC is pointing at the
16181ad6265SDimitry Andric // next word.
16281ad6265SDimitry Andric LabelOffset = InsertByte - 2;
16381ad6265SDimitry Andric else if (InsertByte % 2)
16481ad6265SDimitry Andric // Otherwise the PC is pointing at the first byte of this word.
16581ad6265SDimitry Andric // So we need to consider the offset between PC and the fixup byte.
16681ad6265SDimitry Andric LabelOffset = 1;
16781ad6265SDimitry Andric
16881ad6265SDimitry Andric if (LabelOffset)
169fe6060f1SDimitry Andric Expr = MCBinaryExpr::createAdd(
17081ad6265SDimitry Andric Expr, MCConstantExpr::create(LabelOffset, Ctx), Ctx);
171fe6060f1SDimitry Andric }
172fe6060f1SDimitry Andric
17381ad6265SDimitry Andric Fixups.push_back(MCFixup::create(InsertByte, Expr,
17481ad6265SDimitry Andric getFixupForSize(Size, /*IsPCRel=*/true),
17581ad6265SDimitry Andric MI.getLoc()));
176fe6060f1SDimitry Andric }
177fe6060f1SDimitry Andric }
178fe6060f1SDimitry Andric
encodeFPSYSSelect(const MCInst & MI,unsigned OpIdx,unsigned InsertPos,APInt & Value,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const179*5f757f3fSDimitry Andric void M68kMCCodeEmitter::encodeFPSYSSelect(const MCInst &MI, unsigned OpIdx,
180*5f757f3fSDimitry Andric unsigned InsertPos, APInt &Value,
181*5f757f3fSDimitry Andric SmallVectorImpl<MCFixup> &Fixups,
182*5f757f3fSDimitry Andric const MCSubtargetInfo &STI) const {
183*5f757f3fSDimitry Andric MCRegister FPSysReg = MI.getOperand(OpIdx).getReg();
184*5f757f3fSDimitry Andric switch (FPSysReg) {
185*5f757f3fSDimitry Andric case M68k::FPC:
186*5f757f3fSDimitry Andric Value = 0b100;
187*5f757f3fSDimitry Andric break;
188*5f757f3fSDimitry Andric case M68k::FPS:
189*5f757f3fSDimitry Andric Value = 0b010;
190*5f757f3fSDimitry Andric break;
191*5f757f3fSDimitry Andric case M68k::FPIAR:
192*5f757f3fSDimitry Andric Value = 0b001;
193*5f757f3fSDimitry Andric break;
194*5f757f3fSDimitry Andric default:
195*5f757f3fSDimitry Andric llvm_unreachable("Unrecognized FPSYS register");
196*5f757f3fSDimitry Andric }
197*5f757f3fSDimitry Andric }
198*5f757f3fSDimitry Andric
getMachineOpValue(const MCInst & MI,const MCOperand & Op,unsigned InsertPos,APInt & Value,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const19981ad6265SDimitry Andric void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op,
20081ad6265SDimitry Andric unsigned InsertPos, APInt &Value,
20181ad6265SDimitry Andric SmallVectorImpl<MCFixup> &Fixups,
20281ad6265SDimitry Andric const MCSubtargetInfo &STI) const {
20381ad6265SDimitry Andric // Register
20481ad6265SDimitry Andric if (Op.isReg()) {
20581ad6265SDimitry Andric unsigned RegNum = Op.getReg();
20681ad6265SDimitry Andric const auto *RI = Ctx.getRegisterInfo();
20781ad6265SDimitry Andric Value |= RI->getEncodingValue(RegNum);
20881ad6265SDimitry Andric // Setup the D/A bit
20981ad6265SDimitry Andric if (M68kII::isAddressRegister(RegNum))
21081ad6265SDimitry Andric Value |= 0b1000;
21181ad6265SDimitry Andric } else if (Op.isImm()) {
21281ad6265SDimitry Andric // Immediate
21381ad6265SDimitry Andric Value |= static_cast<uint64_t>(Op.getImm());
21481ad6265SDimitry Andric } else if (Op.isExpr()) {
21581ad6265SDimitry Andric // Absolute address
21681ad6265SDimitry Andric int64_t Addr;
21781ad6265SDimitry Andric if (!Op.getExpr()->evaluateAsAbsolute(Addr))
21881ad6265SDimitry Andric report_fatal_error("Unsupported asm expression. Only absolute address "
21981ad6265SDimitry Andric "can be placed here.");
22081ad6265SDimitry Andric Value |= static_cast<uint64_t>(Addr);
221fe6060f1SDimitry Andric } else {
22281ad6265SDimitry Andric llvm_unreachable("Unsupported operand type");
223fe6060f1SDimitry Andric }
224fe6060f1SDimitry Andric }
225fe6060f1SDimitry Andric
encodeInstruction(const MCInst & MI,SmallVectorImpl<char> & CB,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const22606c3fb27SDimitry Andric void M68kMCCodeEmitter::encodeInstruction(const MCInst &MI,
22706c3fb27SDimitry Andric SmallVectorImpl<char> &CB,
228fe6060f1SDimitry Andric SmallVectorImpl<MCFixup> &Fixups,
229fe6060f1SDimitry Andric const MCSubtargetInfo &STI) const {
230*5f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "EncodeInstruction: " << MCII.getName(MI.getOpcode())
231*5f757f3fSDimitry Andric << "(" << MI.getOpcode() << ")\n");
232*5f757f3fSDimitry Andric (void)MCII;
233fe6060f1SDimitry Andric
23481ad6265SDimitry Andric // Try using the new method first.
23581ad6265SDimitry Andric APInt EncodedInst(16, 0U);
236*5f757f3fSDimitry Andric APInt Scratch(64, 0U); // One APInt word is enough.
23781ad6265SDimitry Andric getBinaryCodeForInstr(MI, Fixups, EncodedInst, Scratch, STI);
238fe6060f1SDimitry Andric
23981ad6265SDimitry Andric ArrayRef<uint64_t> Data(EncodedInst.getRawData(), EncodedInst.getNumWords());
24081ad6265SDimitry Andric int64_t InstSize = EncodedInst.getBitWidth();
24181ad6265SDimitry Andric for (uint64_t Word : Data) {
24281ad6265SDimitry Andric for (int i = 0; i < 4 && InstSize > 0; ++i, InstSize -= 16) {
24306c3fb27SDimitry Andric support::endian::write<uint16_t>(CB, static_cast<uint16_t>(Word),
244*5f757f3fSDimitry Andric llvm::endianness::big);
24581ad6265SDimitry Andric Word >>= 16;
246fe6060f1SDimitry Andric }
247fe6060f1SDimitry Andric }
248fe6060f1SDimitry Andric }
249fe6060f1SDimitry Andric
createM68kMCCodeEmitter(const MCInstrInfo & MCII,MCContext & Ctx)250fe6060f1SDimitry Andric MCCodeEmitter *llvm::createM68kMCCodeEmitter(const MCInstrInfo &MCII,
251fe6060f1SDimitry Andric MCContext &Ctx) {
252fe6060f1SDimitry Andric return new M68kMCCodeEmitter(MCII, Ctx);
253fe6060f1SDimitry Andric }
254