1 //===-- M68kMCCodeEmitter.cpp - Convert M68k code emitter ---*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
10 /// This file contains defintions for M68k code emitter.
12 //===----------------------------------------------------------------------===//
14 #include "MCTargetDesc/M68kMCCodeEmitter.h"
15 #include "MCTargetDesc/M68kBaseInfo.h"
16 #include "MCTargetDesc/M68kFixupKinds.h"
17 #include "MCTargetDesc/M68kMCTargetDesc.h"
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"
33 #define DEBUG_TYPE "m68k-mccodeemitter"
36 class M68kMCCodeEmitter
: public MCCodeEmitter
{
37 M68kMCCodeEmitter(const M68kMCCodeEmitter
&) = delete;
38 void operator=(const M68kMCCodeEmitter
&) = delete;
39 const MCInstrInfo
&MCII
;
43 M68kMCCodeEmitter(const MCInstrInfo
&mcii
, MCContext
&ctx
)
44 : MCII(mcii
), Ctx(ctx
) {}
46 ~M68kMCCodeEmitter() override
{}
48 // TableGen'erated function
49 const uint8_t *getGenInstrBeads(const MCInst
&MI
) const {
50 return M68k::getMCInstrBeads(MI
.getOpcode());
53 unsigned encodeBits(unsigned ThisByte
, uint8_t Bead
, const MCInst
&MI
,
54 const MCInstrDesc
&Desc
, uint64_t &Buffer
,
55 unsigned Offset
, SmallVectorImpl
<MCFixup
> &Fixups
,
56 const MCSubtargetInfo
&STI
) const;
58 unsigned encodeReg(unsigned ThisByte
, uint8_t Bead
, const MCInst
&MI
,
59 const MCInstrDesc
&Desc
, uint64_t &Buffer
, unsigned Offset
,
60 SmallVectorImpl
<MCFixup
> &Fixups
,
61 const MCSubtargetInfo
&STI
) const;
63 unsigned encodeImm(unsigned ThisByte
, uint8_t Bead
, const MCInst
&MI
,
64 const MCInstrDesc
&Desc
, uint64_t &Buffer
, unsigned Offset
,
65 SmallVectorImpl
<MCFixup
> &Fixups
,
66 const MCSubtargetInfo
&STI
) const;
68 void encodeInstruction(const MCInst
&MI
, raw_ostream
&OS
,
69 SmallVectorImpl
<MCFixup
> &Fixups
,
70 const MCSubtargetInfo
&STI
) const override
;
73 } // end anonymous namespace
75 unsigned M68kMCCodeEmitter::encodeBits(unsigned ThisByte
, uint8_t Bead
,
77 const MCInstrDesc
&Desc
,
78 uint64_t &Buffer
, unsigned Offset
,
79 SmallVectorImpl
<MCFixup
> &Fixups
,
80 const MCSubtargetInfo
&STI
) const {
83 case M68kBeads::Bits1
:
86 case M68kBeads::Bits2
:
89 case M68kBeads::Bits3
:
92 case M68kBeads::Bits4
:
96 unsigned char Val
= (Bead
& 0xF0) >> 4;
98 LLVM_DEBUG(dbgs() << "\tEncodeBits"
99 << " Num: " << Num
<< " Val: 0x");
100 LLVM_DEBUG(dbgs().write_hex(Val
) << "\n");
102 Buffer
|= (Val
<< Offset
);
107 unsigned M68kMCCodeEmitter::encodeReg(unsigned ThisByte
, uint8_t Bead
,
108 const MCInst
&MI
, const MCInstrDesc
&Desc
,
109 uint64_t &Buffer
, unsigned Offset
,
110 SmallVectorImpl
<MCFixup
> &Fixups
,
111 const MCSubtargetInfo
&STI
) const {
113 switch (Bead
& 0xF) {
115 llvm_unreachable("Unrecognized Bead code for register type");
116 case M68kBeads::DAReg
:
124 case M68kBeads::DReg
:
131 unsigned Op
= (Bead
& 0x70) >> 4;
132 bool Alt
= (Bead
& 0x80);
133 LLVM_DEBUG(dbgs() << "\tEncodeReg"
134 << " Op: " << Op
<< ", DA: " << DA
<< ", Reg: " << Reg
135 << ", Alt: " << Alt
<< "\n");
137 auto MIOpIdx
= M68k::getLogicalOperandIdx(MI
.getOpcode(), Op
);
138 bool IsPCRel
= Desc
.OpInfo
[MIOpIdx
].OperandType
== MCOI::OPERAND_PCREL
;
141 if (M68kII::hasMultiMIOperands(MI
.getOpcode(), Op
)) {
144 "PCRel addresses use Alt bead register encoding by default");
145 MCO
= MI
.getOperand(MIOpIdx
+ M68k::PCRelIndex
);
147 MCO
= MI
.getOperand(MIOpIdx
+ (Alt
? M68k::MemIndex
: M68k::MemBase
));
150 assert(!Alt
&& "You cannot use Alt register with a simple operand");
151 MCO
= MI
.getOperand(MIOpIdx
);
154 unsigned RegNum
= MCO
.getReg();
155 auto RI
= Ctx
.getRegisterInfo();
157 unsigned Written
= 0;
159 uint32_t Val
= RI
->getEncodingValue(RegNum
);
160 Buffer
|= (Val
& 7) << Offset
;
166 Buffer
|= (uint64_t)M68kII::isAddressRegister(RegNum
) << Offset
;
173 static unsigned EmitConstant(uint64_t Val
, unsigned Size
, unsigned Pad
,
174 uint64_t &Buffer
, unsigned Offset
) {
175 assert(Size
+ Offset
<= 64 && isUIntN(Size
, Val
) && "Value does not fit");
177 // Writing Value in host's endianness
178 Buffer
|= (Val
& ((1ULL << Size
) - 1)) << Offset
;
182 unsigned M68kMCCodeEmitter::encodeImm(unsigned ThisByte
, uint8_t Bead
,
183 const MCInst
&MI
, const MCInstrDesc
&Desc
,
184 uint64_t &Buffer
, unsigned Offset
,
185 SmallVectorImpl
<MCFixup
> &Fixups
,
186 const MCSubtargetInfo
&STI
) const {
187 unsigned ThisWord
= ThisByte
/ 2;
190 unsigned FixOffset
= 0;
191 int64_t Addendum
= 0;
194 unsigned Type
= Bead
& 0xF;
195 unsigned Op
= (Bead
& 0x70) >> 4;
196 bool Alt
= (Bead
& 0x80);
198 auto MIOpIdx
= M68k::getLogicalOperandIdx(MI
.getOpcode(), Op
);
199 bool IsPCRel
= Desc
.OpInfo
[MIOpIdx
].OperandType
== MCOI::OPERAND_PCREL
;
201 // The PC value upon instruction reading of a short jump will point to the
202 // next instruction, thus we need to compensate 2 bytes, which is the diff
203 // between the patch point and the PC.
204 if (IsPCRel
&& ThisWord
== 0)
208 // ??? what happens if it is not byte aligned
209 // ??? is it even possible
210 case M68kBeads::Disp8
:
213 FixOffset
= ThisByte
+ 1;
216 case M68kBeads::Imm8
:
219 FixOffset
= ThisByte
;
221 case M68kBeads::Imm16
:
224 FixOffset
= ThisByte
;
226 case M68kBeads::Imm32
:
229 FixOffset
= ThisByte
;
231 case M68kBeads::Imm3
:
238 LLVM_DEBUG(dbgs() << "\tEncodeImm"
239 << " Op: " << Op
<< ", Size: " << Size
<< ", Alt: " << Alt
243 if (M68kII::hasMultiMIOperands(MI
.getOpcode(), Op
)) {
246 assert(!Alt
&& "You cannot use ALT operand with PCRel");
247 MCO
= MI
.getOperand(MIOpIdx
+ M68k::PCRelDisp
);
249 MCO
= MI
.getOperand(MIOpIdx
+ (Alt
? M68k::MemOuter
: M68k::MemDisp
));
253 assert(!NoExpr
&& "Cannot use expression here");
254 const MCExpr
*Expr
= MCO
.getExpr();
256 // This only makes sense for PCRel instructions since PC points to the
257 // extension word and Disp8 for example is right justified and requires
258 // correction. E.g. R_68K_PC32 is calculated as S + A - P, P for Disp8
259 // will be EXTENSION_WORD + 1 thus we need to have A equal to 1 to
261 // TODO count extension words
262 if (IsPCRel
&& Addendum
!= 0) {
263 Expr
= MCBinaryExpr::createAdd(
264 Expr
, MCConstantExpr::create(Addendum
, Ctx
), Ctx
);
267 Fixups
.push_back(MCFixup::create(
268 FixOffset
, Expr
, getFixupForSize(Size
, IsPCRel
), MI
.getLoc()));
270 return EmitConstant(0, Size
, Pad
, Buffer
, Offset
);
274 MCO
= MI
.getOperand(MIOpIdx
);
276 assert(!NoExpr
&& "Cannot use expression here");
277 const MCExpr
*Expr
= MCO
.getExpr();
280 Expr
= MCBinaryExpr::createAdd(
281 Expr
, MCConstantExpr::create(Addendum
, Ctx
), Ctx
);
284 Fixups
.push_back(MCFixup::create(
285 FixOffset
, Expr
, getFixupForSize(Size
, IsPCRel
), MI
.getLoc()));
287 return EmitConstant(0, Size
, Pad
, Buffer
, Offset
);
291 int64_t I
= MCO
.getImm();
293 // Store 8 as 0, thus making range 1-8
294 if (Type
== M68kBeads::Imm3
&& Alt
) {
295 assert(I
&& "Cannot encode Alt Imm3 zero value");
298 assert(isIntN(Size
, I
));
303 // 32 bit Imm requires HI16 first then LO16
305 Offset
+= EmitConstant((Imm
>> 16) & 0xFFFF, 16, Pad
, Buffer
, Offset
);
306 EmitConstant(Imm
& 0xFFFF, 16, Pad
, Buffer
, Offset
);
310 return EmitConstant(Imm
& ((1ULL << Size
) - 1), Size
, Pad
, Buffer
, Offset
);
313 #include "M68kGenMCCodeBeads.inc"
315 void M68kMCCodeEmitter::encodeInstruction(const MCInst
&MI
, raw_ostream
&OS
,
316 SmallVectorImpl
<MCFixup
> &Fixups
,
317 const MCSubtargetInfo
&STI
) const {
318 unsigned Opcode
= MI
.getOpcode();
319 const MCInstrDesc
&Desc
= MCII
.get(Opcode
);
321 LLVM_DEBUG(dbgs() << "EncodeInstruction: " << MCII
.getName(Opcode
) << "("
324 const uint8_t *Beads
= getGenInstrBeads(MI
);
325 if (!Beads
|| !*Beads
) {
326 llvm_unreachable("*** Instruction does not have Beads defined");
331 unsigned ThisByte
= 0;
333 for (uint8_t Bead
= *Beads
; Bead
; Bead
= *++Beads
) {
334 // Check for control beads
337 case M68kBeads::Ignore
:
342 switch (Bead
& 0xF) {
344 llvm_unreachable("Unknown Bead code");
346 case M68kBeads::Bits1
:
347 case M68kBeads::Bits2
:
348 case M68kBeads::Bits3
:
349 case M68kBeads::Bits4
:
351 encodeBits(ThisByte
, Bead
, MI
, Desc
, Buffer
, Offset
, Fixups
, STI
);
353 case M68kBeads::DAReg
:
355 case M68kBeads::DReg
:
358 encodeReg(ThisByte
, Bead
, MI
, Desc
, Buffer
, Offset
, Fixups
, STI
);
360 case M68kBeads::Disp8
:
361 case M68kBeads::Imm8
:
362 case M68kBeads::Imm16
:
363 case M68kBeads::Imm32
:
364 case M68kBeads::Imm3
:
366 encodeImm(ThisByte
, Bead
, MI
, Desc
, Buffer
, Offset
, Fixups
, STI
);
370 // Since M68k is Big Endian we need to rotate each instruction word
371 while (Offset
/ 16) {
372 support::endian::write
<uint16_t>(OS
, Buffer
, support::big
);
379 assert(Offset
== 0 && "M68k Instructions are % 2 bytes");
380 assert((ThisByte
&& !(ThisByte
% 2)) && "M68k Instructions are % 2 bytes");
383 MCCodeEmitter
*llvm::createM68kMCCodeEmitter(const MCInstrInfo
&MCII
,
384 const MCRegisterInfo
&MRI
,
386 return new M68kMCCodeEmitter(MCII
, Ctx
);