LLVM  15.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 
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"
26 #include "llvm/MC/MCSymbol.h"
27 #include "llvm/Support/Debug.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,
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 public:
63  M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
64  : MCII(mcii), Ctx(ctx) {}
65 
66  ~M68kMCCodeEmitter() override {}
67 
68  void encodeInstruction(const MCInst &MI, raw_ostream &OS,
70  const MCSubtargetInfo &STI) const override;
71 };
72 
73 } // end anonymous namespace
74 
75 #include "M68kGenMCCodeEmitter.inc"
76 
77 // Select the proper unsigned integer type from a bit size.
78 template <unsigned Size> struct select_uint_t {
79  using type = typename std::conditional<
80  Size == 8, uint8_t,
81  typename std::conditional<
82  Size == 16, uint16_t,
83  typename std::conditional<Size == 32, uint32_t,
85 };
86 
87 // On a LE host:
88 // MSB LSB MSB LSB
89 // | 0x12 0x34 | 0xAB 0xCD | -> | 0xAB 0xCD | 0x12 0x34 |
90 // (On a BE host nothing changes)
91 template <typename value_t> static value_t swapWord(value_t Val) {
92  const unsigned NumWords = sizeof(Val) / 2;
93  if (NumWords <= 1)
94  return Val;
96  value_t NewVal = 0;
97  for (unsigned i = 0U; i != NumWords; ++i) {
98  uint16_t Part = (Val >> (i * 16)) & 0xFFFF;
100  NewVal |= (Part << (i * 16));
101  }
102  return NewVal;
103 }
104 
105 // Figure out which byte we're at in big endian mode.
106 template <unsigned Size> static unsigned getBytePosition(unsigned BitPos) {
107  if (Size % 16) {
108  return static_cast<unsigned>(BitPos / 8 + ((BitPos & 0b1111) < 8 ? 1 : -1));
109  } else {
110  assert(!(BitPos & 0b1111) && "Not aligned to word boundary?");
111  return BitPos / 8;
112  }
113 }
114 
115 // We need special handlings for relocatable & pc-relative operands that are
116 // larger than a word.
117 // A M68k instruction is aligned by word (16 bits). That means, 32-bit
118 // (& 64-bit) immediate values are separated into hi & lo words and placed
119 // at lower & higher addresses, respectively. For immediate values that can
120 // be easily expressed in TG, we explicitly rotate the word ordering like
121 // this:
122 // ```
123 // (ascend (slice "$imm", 31, 16), (slice "$imm", 15, 0))
124 // ```
125 // For operands that call into encoder functions, we need to use the `swapWord`
126 // function to assure the correct word ordering on LE host. Note that
127 // M68kMCCodeEmitter does massage _byte_ ordering of the final encoded
128 // instruction but it assumes everything aligns on word boundaries. So things
129 // will go wrong if we don't take care of the _word_ ordering here.
130 template <unsigned Size>
131 void M68kMCCodeEmitter::encodeRelocImm(const MCInst &MI, unsigned OpIdx,
132  unsigned InsertPos, APInt &Value,
134  const MCSubtargetInfo &STI) const {
135  using value_t = typename select_uint_t<Size>::type;
136  const MCOperand &MCO = MI.getOperand(OpIdx);
137  if (MCO.isImm()) {
138  Value |= swapWord<value_t>(static_cast<value_t>(MCO.getImm()));
139  } else if (MCO.isExpr()) {
140  const MCExpr *Expr = MCO.getExpr();
141 
142  // Absolute address
143  int64_t Addr;
144  if (Expr->evaluateAsAbsolute(Addr)) {
145  Value |= swapWord<value_t>(static_cast<value_t>(Addr));
146  return;
147  }
148 
149  // Relocatable address
150  unsigned InsertByte = getBytePosition<Size>(InsertPos);
151  Fixups.push_back(MCFixup::create(InsertByte, Expr,
152  getFixupForSize(Size, /*IsPCRel=*/false),
153  MI.getLoc()));
154  }
155 }
156 
157 template <unsigned Size>
158 void M68kMCCodeEmitter::encodePCRelImm(const MCInst &MI, unsigned OpIdx,
159  unsigned InsertPos, APInt &Value,
161  const MCSubtargetInfo &STI) const {
162  const MCOperand &MCO = MI.getOperand(OpIdx);
163  if (MCO.isImm()) {
164  using value_t = typename select_uint_t<Size>::type;
165  Value |= swapWord<value_t>(static_cast<value_t>(MCO.getImm()));
166  } else if (MCO.isExpr()) {
167  const MCExpr *Expr = MCO.getExpr();
168  unsigned InsertByte = getBytePosition<Size>(InsertPos);
169 
170  // Special handlings for sizes smaller than a word.
171  if (Size < 16) {
172  int LabelOffset = 0;
173  if (InsertPos < 16)
174  // If the patch point is at the first word, PC is pointing at the
175  // next word.
176  LabelOffset = InsertByte - 2;
177  else if (InsertByte % 2)
178  // Otherwise the PC is pointing at the first byte of this word.
179  // So we need to consider the offset between PC and the fixup byte.
180  LabelOffset = 1;
181 
182  if (LabelOffset)
184  Expr, MCConstantExpr::create(LabelOffset, Ctx), Ctx);
185  }
186 
187  Fixups.push_back(MCFixup::create(InsertByte, Expr,
188  getFixupForSize(Size, /*IsPCRel=*/true),
189  MI.getLoc()));
190  }
191 }
192 
193 void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op,
194  unsigned InsertPos, APInt &Value,
196  const MCSubtargetInfo &STI) const {
197  // Register
198  if (Op.isReg()) {
199  unsigned RegNum = Op.getReg();
200  const auto *RI = Ctx.getRegisterInfo();
201  Value |= RI->getEncodingValue(RegNum);
202  // Setup the D/A bit
203  if (M68kII::isAddressRegister(RegNum))
204  Value |= 0b1000;
205  } else if (Op.isImm()) {
206  // Immediate
207  Value |= static_cast<uint64_t>(Op.getImm());
208  } else if (Op.isExpr()) {
209  // Absolute address
210  int64_t Addr;
211  if (!Op.getExpr()->evaluateAsAbsolute(Addr))
212  report_fatal_error("Unsupported asm expression. Only absolute address "
213  "can be placed here.");
214  Value |= static_cast<uint64_t>(Addr);
215  } else {
216  llvm_unreachable("Unsupported operand type");
217  }
218 }
219 
220 void M68kMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
222  const MCSubtargetInfo &STI) const {
223  unsigned Opcode = MI.getOpcode();
224 
225  LLVM_DEBUG(dbgs() << "EncodeInstruction: " << MCII.getName(Opcode) << "("
226  << Opcode << ")\n");
227 
228  // Try using the new method first.
229  APInt EncodedInst(16, 0U);
230  APInt Scratch(16, 0U);
231  getBinaryCodeForInstr(MI, Fixups, EncodedInst, Scratch, STI);
232 
233  ArrayRef<uint64_t> Data(EncodedInst.getRawData(), EncodedInst.getNumWords());
234  int64_t InstSize = EncodedInst.getBitWidth();
235  for (uint64_t Word : Data) {
236  for (int i = 0; i < 4 && InstSize > 0; ++i, InstSize -= 16) {
237  support::endian::write<uint16_t>(OS, static_cast<uint16_t>(Word),
238  support::big);
239  Word >>= 16;
240  }
241  }
242 }
243 
245  MCContext &Ctx) {
246  return new M68kMCCodeEmitter(MCII, Ctx);
247 }
i
i
Definition: README.txt:29
MI
IRTranslator LLVM IR MI
Definition: IRTranslator.cpp:105
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
llvm::MCContext
Context object for machine code objects.
Definition: MCContext.h:76
MCCodeEmitter.h
llvm::MCConstantExpr::create
static const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition: MCExpr.cpp:194
llvm::MCFixup::create
static MCFixup create(uint32_t Offset, const MCExpr *Value, MCFixupKind Kind, SMLoc Loc=SMLoc())
Definition: MCFixup.h:87
llvm::MCInst
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:184
llvm::Data
@ Data
Definition: SIMachineScheduler.h:55
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
swapWord
static value_t swapWord(value_t Val)
Definition: M68kMCCodeEmitter.cpp:91
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
MCContext.h
MCInstrInfo.h
llvm::MCOperand::getImm
int64_t getImm() const
Definition: MCInst.h:80
MCSymbol.h
llvm::createM68kMCCodeEmitter
MCCodeEmitter * createM68kMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx)
Definition: M68kMCCodeEmitter.cpp:244
MCInst.h
llvm::AArch64::Fixups
Fixups
Definition: AArch64FixupKinds.h:17
MCSubtargetInfo.h
llvm::report_fatal_error
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:145
llvm::raw_ostream
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:54
M68kMCCodeEmitter.h
llvm::MCOperand::isImm
bool isImm() const
Definition: MCInst.h:62
type
AMD64 Optimization Manual has some nice information about optimizing integer multiplication by a constant How much of it applies to Intel s X86 implementation There are definite trade offs to xmm0 cvttss2siq rdx jb L3 subss xmm0 rax cvttss2siq rdx xorq rdx rax ret instead of xmm1 cvttss2siq rcx movaps xmm2 subss xmm2 cvttss2siq rax rdx xorq rax ucomiss xmm0 cmovb rax ret Seems like the jb branch has high likelihood of being taken It would have saved a few instructions It s not possible to reference and DH registers in an instruction requiring REX prefix divb and mulb both produce results in AH If isel emits a CopyFromReg which gets turned into a movb and that can be allocated a r8b r15b To get around isel emits a CopyFromReg from AX and then right shift it down by and truncate it It s not pretty but it works We need some register allocation magic to make the hack go which would often require a callee saved register Callees usually need to keep this value live for most of their body so it doesn t add a significant burden on them We currently implement this in however this is suboptimal because it means that it would be quite awkward to implement the optimization for callers A better implementation would be to relax the LLVM IR rules for sret arguments to allow a function with an sret argument to have a non void return type
Definition: README-X86-64.txt:70
llvm::getFixupForSize
static MCFixupKind getFixupForSize(unsigned Size, bool isPCRel)
Definition: M68kFixupKinds.h:38
M68kMCTargetDesc.h
uint64_t
Addr
uint64_t Addr
Definition: ELFObjHandler.cpp:78
select_uint_t
Definition: M68kMCCodeEmitter.cpp:78
M68kFixupKinds.h
MCRegisterInfo.h
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::irsymtab::storage::Word
support::ulittle32_t Word
Definition: IRSymtab.h:52
llvm::APInt
Class for arbitrary precision integers.
Definition: APInt.h:75
llvm::MCBinaryExpr::createAdd
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition: MCExpr.h:525
llvm::ArrayRef< uint64_t >
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:143
select_uint_t::type
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
Definition: M68kMCCodeEmitter.cpp:84
uint32_t
llvm::MCInstrInfo
Interface to description of machine instruction set.
Definition: MCInstrInfo.h:26
EndianStream.h
uint16_t
llvm::MCCodeEmitter
MCCodeEmitter - Generic instruction encoding interface.
Definition: MCCodeEmitter.h:21
llvm::AMDGPU::SendMsg::Op
Op
Definition: SIDefines.h:348
llvm::support::endian::byte_swap
value_type byte_swap(value_type value, endianness endian)
Definition: Endian.h:49
llvm::MCOperand::getExpr
const MCExpr * getExpr() const
Definition: MCInst.h:114
llvm::MCOperand::isExpr
bool isExpr() const
Definition: MCInst.h:65
getBytePosition
static unsigned getBytePosition(unsigned BitPos)
Definition: M68kMCCodeEmitter.cpp:106
M68kBaseInfo.h
llvm::SmallVectorImpl
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: APFloat.h:42
llvm::M68kII::isAddressRegister
static bool isAddressRegister(unsigned RegNo)
Definition: M68kBaseInfo.h:176
llvm::MCOperand
Instances of this class represent operands of the MCInst class.
Definition: MCInst.h:36
raw_ostream.h
MCExpr.h
llvm::MCSubtargetInfo
Generic base class for all target subtargets.
Definition: MCSubtargetInfo.h:76
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
llvm::MCExpr
Base class for the full range of assembler expressions which are needed for parsing.
Definition: MCExpr.h:35
Debug.h
llvm::support::big
@ big
Definition: Endian.h:27