LLVM 20.0.0git
M68kMCCodeEmitter.cpp
Go to the documentation of this file.
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
18
20#include "llvm/MC/MCContext.h"
21#include "llvm/MC/MCExpr.h"
22#include "llvm/MC/MCInst.h"
23#include "llvm/MC/MCInstrInfo.h"
26#include "llvm/MC/MCSymbol.h"
27#include "llvm/Support/Debug.h"
30#include <type_traits>
31
32using namespace llvm;
33
34#define DEBUG_TYPE "m68k-mccodeemitter"
35
36namespace {
37class 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,
50 const MCSubtargetInfo &STI) const;
51
52 template <unsigned Size>
53 void encodeRelocImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,
55 const MCSubtargetInfo &STI) const;
56
57 template <unsigned Size>
58 void encodePCRelImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,
60 const MCSubtargetInfo &STI) const;
61
62 void encodeFPSYSSelect(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,
64 const MCSubtargetInfo &STI) const;
65
66public:
67 M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
68 : MCII(mcii), Ctx(ctx) {}
69
70 ~M68kMCCodeEmitter() override {}
71
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.
82template <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,
89};
90
91// Figure out which byte we're at in big endian mode.
92template <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.
116template <unsigned Size>
117void M68kMCCodeEmitter::encodeRelocImm(const MCInst &MI, unsigned OpIdx,
118 unsigned InsertPos, APInt &Value,
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
143template <unsigned Size>
144void M68kMCCodeEmitter::encodePCRelImm(const MCInst &MI, unsigned OpIdx,
145 unsigned InsertPos, APInt &Value,
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)
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
179void M68kMCCodeEmitter::encodeFPSYSSelect(const MCInst &MI, unsigned OpIdx,
180 unsigned InsertPos, APInt &Value,
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
199void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op,
200 unsigned InsertPos, APInt &Value,
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
226void M68kMCCodeEmitter::encodeInstruction(const MCInst &MI,
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 unsigned InstSize = EncodedInst.getBitWidth();
240 for (unsigned i = 0; i != InstSize; i += 16)
241 support::endian::write<uint16_t>(
242 CB, static_cast<uint16_t>(EncodedInst.extractBitsAsZExtValue(16, i)),
244}
245
247 MCContext &Ctx) {
248 return new M68kMCCodeEmitter(MCII, Ctx);
249}
#define LLVM_DEBUG(...)
Definition: Debug.h:106
uint64_t Addr
uint64_t Size
IRTranslator LLVM IR MI
This file contains small standalone helper functions and enum definitions for the M68k target useful ...
This file contains M68k specific fixup entries.
static unsigned getBytePosition(unsigned BitPos)
This file contains the declarations for the code emitter which are useful outside of the emitter itse...
This file provides M68k specific target descriptions.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Class for arbitrary precision integers.
Definition: APInt.h:78
This class represents an Operation in the Expression.
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition: MCExpr.h:537
MCCodeEmitter - Generic instruction encoding interface.
Definition: MCCodeEmitter.h:21
virtual void encodeInstruction(const MCInst &Inst, SmallVectorImpl< char > &CB, SmallVectorImpl< MCFixup > &Fixups, const MCSubtargetInfo &STI) const =0
Encode the given Inst to bytes and append to CB.
MCCodeEmitter & operator=(const MCCodeEmitter &)=delete
static const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition: MCExpr.cpp:222
Context object for machine code objects.
Definition: MCContext.h:83
Base class for the full range of assembler expressions which are needed for parsing.
Definition: MCExpr.h:34
static MCFixup create(uint32_t Offset, const MCExpr *Value, MCFixupKind Kind, SMLoc Loc=SMLoc())
Definition: MCFixup.h:87
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:185
Interface to description of machine instruction set.
Definition: MCInstrInfo.h:26
Instances of this class represent operands of the MCInst class.
Definition: MCInst.h:37
int64_t getImm() const
Definition: MCInst.h:81
bool isImm() const
Definition: MCInst.h:63
const MCExpr * getExpr() const
Definition: MCInst.h:115
bool isExpr() const
Definition: MCInst.h:66
Wrapper class representing physical registers. Should be passed by value.
Definition: MCRegister.h:33
Generic base class for all target subtargets.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:573
LLVM Value Representation.
Definition: Value.h:74
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static bool isAddressRegister(unsigned RegNo)
Definition: M68kBaseInfo.h:252
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
static MCFixupKind getFixupForSize(unsigned Size, bool isPCRel)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:167
MCCodeEmitter * createM68kMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx)
typename std::conditional< Size==8, uint8_t, typename std::conditional< Size==16, uint16_t, typename std::conditional< Size==32, uint32_t, uint64_t >::type >::type >::type type