Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp
35294 views
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
void encodeFPSYSSelect(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,
63
APInt &Value, SmallVectorImpl<MCFixup> &Fixups,
64
const MCSubtargetInfo &STI) const;
65
66
public:
67
M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
68
: MCII(mcii), Ctx(ctx) {}
69
70
~M68kMCCodeEmitter() override {}
71
72
void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,
73
SmallVectorImpl<MCFixup> &Fixups,
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.
82
template <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,
88
uint64_t>::type>::type>::type;
89
};
90
91
// Figure out which byte we're at in big endian mode.
92
template <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.
116
template <unsigned Size>
117
void M68kMCCodeEmitter::encodeRelocImm(const MCInst &MI, unsigned OpIdx,
118
unsigned InsertPos, APInt &Value,
119
SmallVectorImpl<MCFixup> &Fixups,
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
143
template <unsigned Size>
144
void M68kMCCodeEmitter::encodePCRelImm(const MCInst &MI, unsigned OpIdx,
145
unsigned InsertPos, APInt &Value,
146
SmallVectorImpl<MCFixup> &Fixups,
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)
169
Expr = MCBinaryExpr::createAdd(
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
179
void M68kMCCodeEmitter::encodeFPSYSSelect(const MCInst &MI, unsigned OpIdx,
180
unsigned InsertPos, APInt &Value,
181
SmallVectorImpl<MCFixup> &Fixups,
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
199
void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op,
200
unsigned InsertPos, APInt &Value,
201
SmallVectorImpl<MCFixup> &Fixups,
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
226
void M68kMCCodeEmitter::encodeInstruction(const MCInst &MI,
227
SmallVectorImpl<char> &CB,
228
SmallVectorImpl<MCFixup> &Fixups,
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
ArrayRef<uint64_t> Data(EncodedInst.getRawData(), EncodedInst.getNumWords());
240
int64_t InstSize = EncodedInst.getBitWidth();
241
for (uint64_t Word : Data) {
242
for (int i = 0; i < 4 && InstSize > 0; ++i, InstSize -= 16) {
243
support::endian::write<uint16_t>(CB, static_cast<uint16_t>(Word),
244
llvm::endianness::big);
245
Word >>= 16;
246
}
247
}
248
}
249
250
MCCodeEmitter *llvm::createM68kMCCodeEmitter(const MCInstrInfo &MCII,
251
MCContext &Ctx) {
252
return new M68kMCCodeEmitter(MCII, Ctx);
253
}
254
255