1249259Sdim//=- AArch64/AArch64MCCodeEmitter.cpp - Convert AArch64 code to machine code =//
2249259Sdim//
3249259Sdim//                     The LLVM Compiler Infrastructure
4249259Sdim//
5249259Sdim// This file is distributed under the University of Illinois Open Source
6249259Sdim// License. See LICENSE.TXT for details.
7249259Sdim//
8249259Sdim//===----------------------------------------------------------------------===//
9249259Sdim//
10249259Sdim// This file implements the AArch64MCCodeEmitter class.
11249259Sdim//
12249259Sdim//===----------------------------------------------------------------------===//
13249259Sdim
14249259Sdim#define DEBUG_TYPE "mccodeemitter"
15249259Sdim#include "MCTargetDesc/AArch64FixupKinds.h"
16249259Sdim#include "MCTargetDesc/AArch64MCExpr.h"
17249259Sdim#include "MCTargetDesc/AArch64MCTargetDesc.h"
18249259Sdim#include "Utils/AArch64BaseInfo.h"
19249259Sdim#include "llvm/MC/MCCodeEmitter.h"
20249259Sdim#include "llvm/MC/MCContext.h"
21249259Sdim#include "llvm/MC/MCInst.h"
22249259Sdim#include "llvm/MC/MCInstrInfo.h"
23249259Sdim#include "llvm/MC/MCRegisterInfo.h"
24249259Sdim#include "llvm/MC/MCSubtargetInfo.h"
25249259Sdim#include "llvm/Support/ErrorHandling.h"
26249259Sdim#include "llvm/Support/raw_ostream.h"
27249259Sdim
28249259Sdimusing namespace llvm;
29249259Sdim
30249259Sdimnamespace {
31249259Sdimclass AArch64MCCodeEmitter : public MCCodeEmitter {
32249259Sdim  AArch64MCCodeEmitter(const AArch64MCCodeEmitter &) LLVM_DELETED_FUNCTION;
33249259Sdim  void operator=(const AArch64MCCodeEmitter &) LLVM_DELETED_FUNCTION;
34249259Sdim  MCContext &Ctx;
35249259Sdim
36249259Sdimpublic:
37249259Sdim  AArch64MCCodeEmitter(MCContext &ctx) : Ctx(ctx) {}
38249259Sdim
39249259Sdim  ~AArch64MCCodeEmitter() {}
40249259Sdim
41249259Sdim  unsigned getAddSubImmOpValue(const MCInst &MI, unsigned OpIdx,
42249259Sdim                               SmallVectorImpl<MCFixup> &Fixups) const;
43249259Sdim
44249259Sdim  unsigned getAdrpLabelOpValue(const MCInst &MI, unsigned OpIdx,
45249259Sdim                               SmallVectorImpl<MCFixup> &Fixups) const;
46249259Sdim
47249259Sdim  template<int MemSize>
48249259Sdim  unsigned getOffsetUImm12OpValue(const MCInst &MI, unsigned OpIdx,
49249259Sdim                                    SmallVectorImpl<MCFixup> &Fixups) const {
50249259Sdim    return getOffsetUImm12OpValue(MI, OpIdx, Fixups, MemSize);
51249259Sdim  }
52249259Sdim
53249259Sdim  unsigned getOffsetUImm12OpValue(const MCInst &MI, unsigned OpIdx,
54249259Sdim                                    SmallVectorImpl<MCFixup> &Fixups,
55249259Sdim                                    int MemSize) const;
56249259Sdim
57249259Sdim  unsigned getBitfield32LSLOpValue(const MCInst &MI, unsigned OpIdx,
58249259Sdim                                   SmallVectorImpl<MCFixup> &Fixups) const;
59249259Sdim  unsigned getBitfield64LSLOpValue(const MCInst &MI, unsigned OpIdx,
60249259Sdim                                   SmallVectorImpl<MCFixup> &Fixups) const;
61249259Sdim
62263508Sdim  unsigned getShiftRightImm8(const MCInst &MI, unsigned Op,
63263508Sdim                             SmallVectorImpl<MCFixup> &Fixups) const;
64263508Sdim  unsigned getShiftRightImm16(const MCInst &MI, unsigned Op,
65263508Sdim                              SmallVectorImpl<MCFixup> &Fixups) const;
66263508Sdim  unsigned getShiftRightImm32(const MCInst &MI, unsigned Op,
67263508Sdim                              SmallVectorImpl<MCFixup> &Fixups) const;
68263508Sdim  unsigned getShiftRightImm64(const MCInst &MI, unsigned Op,
69263508Sdim                              SmallVectorImpl<MCFixup> &Fixups) const;
70249259Sdim
71263508Sdim  unsigned getShiftLeftImm8(const MCInst &MI, unsigned Op,
72263508Sdim                            SmallVectorImpl<MCFixup> &Fixups) const;
73263508Sdim  unsigned getShiftLeftImm16(const MCInst &MI, unsigned Op,
74263508Sdim                             SmallVectorImpl<MCFixup> &Fixups) const;
75263508Sdim  unsigned getShiftLeftImm32(const MCInst &MI, unsigned Op,
76263508Sdim                             SmallVectorImpl<MCFixup> &Fixups) const;
77263508Sdim  unsigned getShiftLeftImm64(const MCInst &MI, unsigned Op,
78263508Sdim                             SmallVectorImpl<MCFixup> &Fixups) const;
79263508Sdim
80249259Sdim  // Labels are handled mostly the same way: a symbol is needed, and
81249259Sdim  // just gets some fixup attached.
82249259Sdim  template<AArch64::Fixups fixupDesired>
83249259Sdim  unsigned getLabelOpValue(const MCInst &MI, unsigned OpIdx,
84249259Sdim                           SmallVectorImpl<MCFixup> &Fixups) const;
85249259Sdim
86249259Sdim  unsigned  getLoadLitLabelOpValue(const MCInst &MI, unsigned OpIdx,
87249259Sdim                                   SmallVectorImpl<MCFixup> &Fixups) const;
88249259Sdim
89249259Sdim
90249259Sdim  unsigned getMoveWideImmOpValue(const MCInst &MI, unsigned OpIdx,
91249259Sdim                                 SmallVectorImpl<MCFixup> &Fixups) const;
92249259Sdim
93249259Sdim
94249259Sdim  unsigned getAddressWithFixup(const MCOperand &MO,
95249259Sdim                               unsigned FixupKind,
96249259Sdim                               SmallVectorImpl<MCFixup> &Fixups) const;
97249259Sdim
98249259Sdim
99249259Sdim  // getBinaryCodeForInstr - TableGen'erated function for getting the
100249259Sdim  // binary encoding for an instruction.
101249259Sdim  uint64_t getBinaryCodeForInstr(const MCInst &MI,
102249259Sdim                                 SmallVectorImpl<MCFixup> &Fixups) const;
103249259Sdim
104249259Sdim  /// getMachineOpValue - Return binary encoding of operand. If the machine
105249259Sdim  /// operand requires relocation, record the relocation and return zero.
106249259Sdim  unsigned getMachineOpValue(const MCInst &MI,const MCOperand &MO,
107249259Sdim                             SmallVectorImpl<MCFixup> &Fixups) const;
108249259Sdim
109249259Sdim
110249259Sdim  void EmitByte(unsigned char C, raw_ostream &OS) const {
111249259Sdim    OS << (char)C;
112249259Sdim  }
113249259Sdim
114249259Sdim  void EmitInstruction(uint32_t Val, raw_ostream &OS) const {
115249259Sdim    // Output the constant in little endian byte order.
116249259Sdim    for (unsigned i = 0; i != 4; ++i) {
117249259Sdim      EmitByte(Val & 0xff, OS);
118249259Sdim      Val >>= 8;
119249259Sdim    }
120249259Sdim  }
121249259Sdim
122249259Sdim
123249259Sdim  void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
124249259Sdim                         SmallVectorImpl<MCFixup> &Fixups) const;
125249259Sdim
126249259Sdim  template<int hasRs, int hasRt2> unsigned
127249259Sdim  fixLoadStoreExclusive(const MCInst &MI, unsigned EncodedValue) const;
128249259Sdim
129249259Sdim  unsigned fixMOVZ(const MCInst &MI, unsigned EncodedValue) const;
130249259Sdim
131249259Sdim  unsigned fixMulHigh(const MCInst &MI, unsigned EncodedValue) const;
132249259Sdim
133249259Sdim
134249259Sdim};
135249259Sdim
136249259Sdim} // end anonymous namespace
137249259Sdim
138249259Sdimunsigned AArch64MCCodeEmitter::getAddressWithFixup(const MCOperand &MO,
139249259Sdim                                       unsigned FixupKind,
140249259Sdim                                       SmallVectorImpl<MCFixup> &Fixups) const {
141249259Sdim  if (!MO.isExpr()) {
142249259Sdim    // This can occur for manually decoded or constructed MCInsts, but neither
143249259Sdim    // the assembly-parser nor instruction selection will currently produce an
144249259Sdim    // MCInst that's not a symbol reference.
145249259Sdim    assert(MO.isImm() && "Unexpected address requested");
146249259Sdim    return MO.getImm();
147249259Sdim  }
148249259Sdim
149249259Sdim  const MCExpr *Expr = MO.getExpr();
150249259Sdim  MCFixupKind Kind = MCFixupKind(FixupKind);
151249259Sdim  Fixups.push_back(MCFixup::Create(0, Expr, Kind));
152249259Sdim
153249259Sdim  return 0;
154249259Sdim}
155249259Sdim
156249259Sdimunsigned AArch64MCCodeEmitter::
157249259SdimgetOffsetUImm12OpValue(const MCInst &MI, unsigned OpIdx,
158249259Sdim                       SmallVectorImpl<MCFixup> &Fixups,
159249259Sdim                       int MemSize) const {
160249259Sdim  const MCOperand &ImmOp = MI.getOperand(OpIdx);
161249259Sdim  if (ImmOp.isImm())
162249259Sdim    return ImmOp.getImm();
163249259Sdim
164249259Sdim  assert(ImmOp.isExpr() && "Unexpected operand type");
165249259Sdim  const AArch64MCExpr *Expr = cast<AArch64MCExpr>(ImmOp.getExpr());
166249259Sdim  unsigned FixupKind;
167249259Sdim
168249259Sdim
169249259Sdim  switch (Expr->getKind()) {
170249259Sdim  default: llvm_unreachable("Unexpected operand modifier");
171249259Sdim  case AArch64MCExpr::VK_AARCH64_LO12: {
172263508Sdim    static const unsigned FixupsBySize[] = { AArch64::fixup_a64_ldst8_lo12,
173263508Sdim                                             AArch64::fixup_a64_ldst16_lo12,
174263508Sdim                                             AArch64::fixup_a64_ldst32_lo12,
175263508Sdim                                             AArch64::fixup_a64_ldst64_lo12,
176249259Sdim                                AArch64::fixup_a64_ldst128_lo12 };
177249259Sdim    assert(MemSize <= 16 && "Invalid fixup for operation");
178249259Sdim    FixupKind = FixupsBySize[Log2_32(MemSize)];
179249259Sdim    break;
180249259Sdim  }
181249259Sdim  case AArch64MCExpr::VK_AARCH64_GOT_LO12:
182249259Sdim    assert(MemSize == 8 && "Invalid fixup for operation");
183249259Sdim    FixupKind = AArch64::fixup_a64_ld64_got_lo12_nc;
184249259Sdim    break;
185249259Sdim  case AArch64MCExpr::VK_AARCH64_DTPREL_LO12:  {
186263508Sdim    static const unsigned FixupsBySize[] = {
187263508Sdim      AArch64::fixup_a64_ldst8_dtprel_lo12,
188263508Sdim      AArch64::fixup_a64_ldst16_dtprel_lo12,
189263508Sdim      AArch64::fixup_a64_ldst32_dtprel_lo12,
190263508Sdim      AArch64::fixup_a64_ldst64_dtprel_lo12
191263508Sdim    };
192249259Sdim    assert(MemSize <= 8 && "Invalid fixup for operation");
193249259Sdim    FixupKind = FixupsBySize[Log2_32(MemSize)];
194249259Sdim    break;
195249259Sdim  }
196249259Sdim  case AArch64MCExpr::VK_AARCH64_DTPREL_LO12_NC: {
197263508Sdim    static const unsigned FixupsBySize[] = {
198263508Sdim      AArch64::fixup_a64_ldst8_dtprel_lo12_nc,
199263508Sdim      AArch64::fixup_a64_ldst16_dtprel_lo12_nc,
200263508Sdim      AArch64::fixup_a64_ldst32_dtprel_lo12_nc,
201263508Sdim      AArch64::fixup_a64_ldst64_dtprel_lo12_nc
202263508Sdim    };
203249259Sdim    assert(MemSize <= 8 && "Invalid fixup for operation");
204249259Sdim    FixupKind = FixupsBySize[Log2_32(MemSize)];
205249259Sdim    break;
206249259Sdim  }
207249259Sdim  case AArch64MCExpr::VK_AARCH64_GOTTPREL_LO12:
208249259Sdim    assert(MemSize == 8 && "Invalid fixup for operation");
209249259Sdim    FixupKind = AArch64::fixup_a64_ld64_gottprel_lo12_nc;
210249259Sdim    break;
211249259Sdim  case AArch64MCExpr::VK_AARCH64_TPREL_LO12:{
212263508Sdim    static const unsigned FixupsBySize[] = {
213263508Sdim      AArch64::fixup_a64_ldst8_tprel_lo12,
214263508Sdim      AArch64::fixup_a64_ldst16_tprel_lo12,
215263508Sdim      AArch64::fixup_a64_ldst32_tprel_lo12,
216263508Sdim      AArch64::fixup_a64_ldst64_tprel_lo12
217263508Sdim    };
218249259Sdim    assert(MemSize <= 8 && "Invalid fixup for operation");
219249259Sdim    FixupKind = FixupsBySize[Log2_32(MemSize)];
220249259Sdim    break;
221249259Sdim  }
222249259Sdim  case AArch64MCExpr::VK_AARCH64_TPREL_LO12_NC: {
223263508Sdim    static const unsigned FixupsBySize[] = {
224263508Sdim      AArch64::fixup_a64_ldst8_tprel_lo12_nc,
225263508Sdim      AArch64::fixup_a64_ldst16_tprel_lo12_nc,
226263508Sdim      AArch64::fixup_a64_ldst32_tprel_lo12_nc,
227263508Sdim      AArch64::fixup_a64_ldst64_tprel_lo12_nc
228263508Sdim    };
229249259Sdim    assert(MemSize <= 8 && "Invalid fixup for operation");
230249259Sdim    FixupKind = FixupsBySize[Log2_32(MemSize)];
231249259Sdim    break;
232249259Sdim  }
233249259Sdim  case AArch64MCExpr::VK_AARCH64_TLSDESC_LO12:
234249259Sdim    assert(MemSize == 8 && "Invalid fixup for operation");
235249259Sdim    FixupKind = AArch64::fixup_a64_tlsdesc_ld64_lo12_nc;
236249259Sdim    break;
237249259Sdim  }
238249259Sdim
239249259Sdim  return getAddressWithFixup(ImmOp, FixupKind, Fixups);
240249259Sdim}
241249259Sdim
242249259Sdimunsigned
243249259SdimAArch64MCCodeEmitter::getAddSubImmOpValue(const MCInst &MI, unsigned OpIdx,
244249259Sdim                                       SmallVectorImpl<MCFixup> &Fixups) const {
245249259Sdim  const MCOperand &MO = MI.getOperand(OpIdx);
246249259Sdim  if (MO.isImm())
247249259Sdim    return static_cast<unsigned>(MO.getImm());
248249259Sdim
249249259Sdim  assert(MO.isExpr());
250249259Sdim
251249259Sdim  unsigned FixupKind = 0;
252249259Sdim  switch(cast<AArch64MCExpr>(MO.getExpr())->getKind()) {
253249259Sdim  default: llvm_unreachable("Invalid expression modifier");
254249259Sdim  case AArch64MCExpr::VK_AARCH64_LO12:
255249259Sdim    FixupKind = AArch64::fixup_a64_add_lo12; break;
256249259Sdim  case AArch64MCExpr::VK_AARCH64_DTPREL_HI12:
257249259Sdim    FixupKind = AArch64::fixup_a64_add_dtprel_hi12; break;
258249259Sdim  case AArch64MCExpr::VK_AARCH64_DTPREL_LO12:
259249259Sdim    FixupKind = AArch64::fixup_a64_add_dtprel_lo12; break;
260249259Sdim  case AArch64MCExpr::VK_AARCH64_DTPREL_LO12_NC:
261249259Sdim    FixupKind = AArch64::fixup_a64_add_dtprel_lo12_nc; break;
262249259Sdim  case AArch64MCExpr::VK_AARCH64_TPREL_HI12:
263249259Sdim    FixupKind = AArch64::fixup_a64_add_tprel_hi12; break;
264249259Sdim  case AArch64MCExpr::VK_AARCH64_TPREL_LO12:
265249259Sdim    FixupKind = AArch64::fixup_a64_add_tprel_lo12; break;
266249259Sdim  case AArch64MCExpr::VK_AARCH64_TPREL_LO12_NC:
267249259Sdim    FixupKind = AArch64::fixup_a64_add_tprel_lo12_nc; break;
268249259Sdim  case AArch64MCExpr::VK_AARCH64_TLSDESC_LO12:
269249259Sdim    FixupKind = AArch64::fixup_a64_tlsdesc_add_lo12_nc; break;
270249259Sdim  }
271249259Sdim
272249259Sdim  return getAddressWithFixup(MO, FixupKind, Fixups);
273249259Sdim}
274249259Sdim
275249259Sdimunsigned
276249259SdimAArch64MCCodeEmitter::getAdrpLabelOpValue(const MCInst &MI, unsigned OpIdx,
277249259Sdim                                       SmallVectorImpl<MCFixup> &Fixups) const {
278249259Sdim
279249259Sdim  const MCOperand &MO = MI.getOperand(OpIdx);
280249259Sdim  if (MO.isImm())
281249259Sdim    return static_cast<unsigned>(MO.getImm());
282249259Sdim
283249259Sdim  assert(MO.isExpr());
284249259Sdim
285249259Sdim  unsigned Modifier = AArch64MCExpr::VK_AARCH64_None;
286249259Sdim  if (const AArch64MCExpr *Expr = dyn_cast<AArch64MCExpr>(MO.getExpr()))
287249259Sdim    Modifier = Expr->getKind();
288249259Sdim
289249259Sdim  unsigned FixupKind = 0;
290249259Sdim  switch(Modifier) {
291249259Sdim  case AArch64MCExpr::VK_AARCH64_None:
292249259Sdim    FixupKind = AArch64::fixup_a64_adr_prel_page;
293249259Sdim    break;
294249259Sdim  case AArch64MCExpr::VK_AARCH64_GOT:
295249259Sdim    FixupKind = AArch64::fixup_a64_adr_prel_got_page;
296249259Sdim    break;
297249259Sdim  case AArch64MCExpr::VK_AARCH64_GOTTPREL:
298249259Sdim    FixupKind = AArch64::fixup_a64_adr_gottprel_page;
299249259Sdim    break;
300249259Sdim  case AArch64MCExpr::VK_AARCH64_TLSDESC:
301249259Sdim    FixupKind = AArch64::fixup_a64_tlsdesc_adr_page;
302249259Sdim    break;
303249259Sdim  default:
304249259Sdim    llvm_unreachable("Unknown symbol reference kind for ADRP instruction");
305249259Sdim  }
306249259Sdim
307249259Sdim  return getAddressWithFixup(MO, FixupKind, Fixups);
308249259Sdim}
309249259Sdim
310249259Sdimunsigned
311249259SdimAArch64MCCodeEmitter::getBitfield32LSLOpValue(const MCInst &MI, unsigned OpIdx,
312249259Sdim                                       SmallVectorImpl<MCFixup> &Fixups) const {
313249259Sdim
314249259Sdim  const MCOperand &MO = MI.getOperand(OpIdx);
315249259Sdim  assert(MO.isImm() && "Only immediate expected for shift");
316249259Sdim
317249259Sdim  return ((32 - MO.getImm()) & 0x1f) | (31 - MO.getImm()) << 6;
318249259Sdim}
319249259Sdim
320249259Sdimunsigned
321249259SdimAArch64MCCodeEmitter::getBitfield64LSLOpValue(const MCInst &MI, unsigned OpIdx,
322249259Sdim                                       SmallVectorImpl<MCFixup> &Fixups) const {
323249259Sdim
324249259Sdim  const MCOperand &MO = MI.getOperand(OpIdx);
325249259Sdim  assert(MO.isImm() && "Only immediate expected for shift");
326249259Sdim
327249259Sdim  return ((64 - MO.getImm()) & 0x3f) | (63 - MO.getImm()) << 6;
328249259Sdim}
329249259Sdim
330263508Sdimunsigned AArch64MCCodeEmitter::getShiftRightImm8(
331263508Sdim    const MCInst &MI, unsigned Op, SmallVectorImpl<MCFixup> &Fixups) const {
332263508Sdim  return 8 - MI.getOperand(Op).getImm();
333263508Sdim}
334249259Sdim
335263508Sdimunsigned AArch64MCCodeEmitter::getShiftRightImm16(
336263508Sdim    const MCInst &MI, unsigned Op, SmallVectorImpl<MCFixup> &Fixups) const {
337263508Sdim  return 16 - MI.getOperand(Op).getImm();
338263508Sdim}
339263508Sdim
340263508Sdimunsigned AArch64MCCodeEmitter::getShiftRightImm32(
341263508Sdim    const MCInst &MI, unsigned Op, SmallVectorImpl<MCFixup> &Fixups) const {
342263508Sdim  return 32 - MI.getOperand(Op).getImm();
343263508Sdim}
344263508Sdim
345263508Sdimunsigned AArch64MCCodeEmitter::getShiftRightImm64(
346263508Sdim    const MCInst &MI, unsigned Op, SmallVectorImpl<MCFixup> &Fixups) const {
347263508Sdim  return 64 - MI.getOperand(Op).getImm();
348263508Sdim}
349263508Sdim
350263508Sdimunsigned AArch64MCCodeEmitter::getShiftLeftImm8(
351263508Sdim    const MCInst &MI, unsigned Op, SmallVectorImpl<MCFixup> &Fixups) const {
352263508Sdim  return MI.getOperand(Op).getImm() - 8;
353263508Sdim}
354263508Sdim
355263508Sdimunsigned AArch64MCCodeEmitter::getShiftLeftImm16(
356263508Sdim    const MCInst &MI, unsigned Op, SmallVectorImpl<MCFixup> &Fixups) const {
357263508Sdim  return MI.getOperand(Op).getImm() - 16;
358263508Sdim}
359263508Sdim
360263508Sdimunsigned AArch64MCCodeEmitter::getShiftLeftImm32(
361263508Sdim    const MCInst &MI, unsigned Op, SmallVectorImpl<MCFixup> &Fixups) const {
362263508Sdim  return MI.getOperand(Op).getImm() - 32;
363263508Sdim}
364263508Sdim
365263508Sdimunsigned AArch64MCCodeEmitter::getShiftLeftImm64(
366263508Sdim    const MCInst &MI, unsigned Op, SmallVectorImpl<MCFixup> &Fixups) const {
367263508Sdim  return MI.getOperand(Op).getImm() - 64;
368263508Sdim}
369263508Sdim
370249259Sdimtemplate<AArch64::Fixups fixupDesired> unsigned
371249259SdimAArch64MCCodeEmitter::getLabelOpValue(const MCInst &MI,
372249259Sdim                                      unsigned OpIdx,
373249259Sdim                                      SmallVectorImpl<MCFixup> &Fixups) const {
374249259Sdim  const MCOperand &MO = MI.getOperand(OpIdx);
375249259Sdim
376249259Sdim  if (MO.isExpr())
377249259Sdim    return getAddressWithFixup(MO, fixupDesired, Fixups);
378249259Sdim
379249259Sdim  assert(MO.isImm());
380249259Sdim  return MO.getImm();
381249259Sdim}
382249259Sdim
383249259Sdimunsigned
384249259SdimAArch64MCCodeEmitter::getLoadLitLabelOpValue(const MCInst &MI,
385249259Sdim                                       unsigned OpIdx,
386249259Sdim                                       SmallVectorImpl<MCFixup> &Fixups) const {
387249259Sdim  const MCOperand &MO = MI.getOperand(OpIdx);
388249259Sdim
389249259Sdim  if (MO.isImm())
390249259Sdim    return MO.getImm();
391249259Sdim
392249259Sdim  assert(MO.isExpr());
393249259Sdim
394249259Sdim  unsigned FixupKind;
395249259Sdim  if (isa<AArch64MCExpr>(MO.getExpr())) {
396249259Sdim    assert(dyn_cast<AArch64MCExpr>(MO.getExpr())->getKind()
397249259Sdim           == AArch64MCExpr::VK_AARCH64_GOTTPREL
398249259Sdim           && "Invalid symbol modifier for literal load");
399249259Sdim    FixupKind = AArch64::fixup_a64_ld_gottprel_prel19;
400249259Sdim  } else {
401249259Sdim    FixupKind = AArch64::fixup_a64_ld_prel;
402249259Sdim  }
403249259Sdim
404249259Sdim  return getAddressWithFixup(MO, FixupKind, Fixups);
405249259Sdim}
406249259Sdim
407249259Sdim
408249259Sdimunsigned
409249259SdimAArch64MCCodeEmitter::getMachineOpValue(const MCInst &MI,
410249259Sdim                                       const MCOperand &MO,
411249259Sdim                                       SmallVectorImpl<MCFixup> &Fixups) const {
412249259Sdim  if (MO.isReg()) {
413263508Sdim    return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());
414249259Sdim  } else if (MO.isImm()) {
415249259Sdim    return static_cast<unsigned>(MO.getImm());
416249259Sdim  }
417249259Sdim
418249259Sdim  llvm_unreachable("Unable to encode MCOperand!");
419249259Sdim  return 0;
420249259Sdim}
421249259Sdim
422249259Sdimunsigned
423249259SdimAArch64MCCodeEmitter::getMoveWideImmOpValue(const MCInst &MI, unsigned OpIdx,
424249259Sdim                                       SmallVectorImpl<MCFixup> &Fixups) const {
425249259Sdim  const MCOperand &UImm16MO = MI.getOperand(OpIdx);
426249259Sdim  const MCOperand &ShiftMO = MI.getOperand(OpIdx + 1);
427249259Sdim
428249259Sdim  unsigned Result = static_cast<unsigned>(ShiftMO.getImm()) << 16;
429249259Sdim
430249259Sdim  if (UImm16MO.isImm()) {
431249259Sdim    Result |= UImm16MO.getImm();
432249259Sdim    return Result;
433249259Sdim  }
434249259Sdim
435249259Sdim  const AArch64MCExpr *A64E = cast<AArch64MCExpr>(UImm16MO.getExpr());
436249259Sdim  AArch64::Fixups requestedFixup;
437249259Sdim  switch (A64E->getKind()) {
438249259Sdim  default: llvm_unreachable("unexpected expression modifier");
439249259Sdim  case AArch64MCExpr::VK_AARCH64_ABS_G0:
440249259Sdim    requestedFixup = AArch64::fixup_a64_movw_uabs_g0; break;
441249259Sdim  case AArch64MCExpr::VK_AARCH64_ABS_G0_NC:
442249259Sdim    requestedFixup = AArch64::fixup_a64_movw_uabs_g0_nc; break;
443249259Sdim  case AArch64MCExpr::VK_AARCH64_ABS_G1:
444249259Sdim    requestedFixup = AArch64::fixup_a64_movw_uabs_g1; break;
445249259Sdim  case AArch64MCExpr::VK_AARCH64_ABS_G1_NC:
446249259Sdim    requestedFixup = AArch64::fixup_a64_movw_uabs_g1_nc; break;
447249259Sdim  case AArch64MCExpr::VK_AARCH64_ABS_G2:
448249259Sdim    requestedFixup = AArch64::fixup_a64_movw_uabs_g2; break;
449249259Sdim  case AArch64MCExpr::VK_AARCH64_ABS_G2_NC:
450249259Sdim    requestedFixup = AArch64::fixup_a64_movw_uabs_g2_nc; break;
451249259Sdim  case AArch64MCExpr::VK_AARCH64_ABS_G3:
452249259Sdim    requestedFixup = AArch64::fixup_a64_movw_uabs_g3; break;
453249259Sdim  case AArch64MCExpr::VK_AARCH64_SABS_G0:
454249259Sdim    requestedFixup = AArch64::fixup_a64_movw_sabs_g0; break;
455249259Sdim  case AArch64MCExpr::VK_AARCH64_SABS_G1:
456249259Sdim    requestedFixup = AArch64::fixup_a64_movw_sabs_g1; break;
457249259Sdim  case AArch64MCExpr::VK_AARCH64_SABS_G2:
458249259Sdim    requestedFixup = AArch64::fixup_a64_movw_sabs_g2; break;
459249259Sdim  case AArch64MCExpr::VK_AARCH64_DTPREL_G2:
460249259Sdim    requestedFixup = AArch64::fixup_a64_movw_dtprel_g2; break;
461249259Sdim  case AArch64MCExpr::VK_AARCH64_DTPREL_G1:
462249259Sdim    requestedFixup = AArch64::fixup_a64_movw_dtprel_g1; break;
463249259Sdim  case AArch64MCExpr::VK_AARCH64_DTPREL_G1_NC:
464249259Sdim    requestedFixup = AArch64::fixup_a64_movw_dtprel_g1_nc; break;
465249259Sdim  case AArch64MCExpr::VK_AARCH64_DTPREL_G0:
466249259Sdim    requestedFixup = AArch64::fixup_a64_movw_dtprel_g0; break;
467249259Sdim  case AArch64MCExpr::VK_AARCH64_DTPREL_G0_NC:
468249259Sdim    requestedFixup = AArch64::fixup_a64_movw_dtprel_g0_nc; break;
469249259Sdim  case AArch64MCExpr::VK_AARCH64_GOTTPREL_G1:
470249259Sdim    requestedFixup = AArch64::fixup_a64_movw_gottprel_g1; break;
471249259Sdim  case AArch64MCExpr::VK_AARCH64_GOTTPREL_G0_NC:
472249259Sdim    requestedFixup = AArch64::fixup_a64_movw_gottprel_g0_nc; break;
473249259Sdim  case AArch64MCExpr::VK_AARCH64_TPREL_G2:
474249259Sdim    requestedFixup = AArch64::fixup_a64_movw_tprel_g2; break;
475249259Sdim  case AArch64MCExpr::VK_AARCH64_TPREL_G1:
476249259Sdim    requestedFixup = AArch64::fixup_a64_movw_tprel_g1; break;
477249259Sdim  case AArch64MCExpr::VK_AARCH64_TPREL_G1_NC:
478249259Sdim    requestedFixup = AArch64::fixup_a64_movw_tprel_g1_nc; break;
479249259Sdim  case AArch64MCExpr::VK_AARCH64_TPREL_G0:
480249259Sdim    requestedFixup = AArch64::fixup_a64_movw_tprel_g0; break;
481249259Sdim  case AArch64MCExpr::VK_AARCH64_TPREL_G0_NC:
482249259Sdim    requestedFixup = AArch64::fixup_a64_movw_tprel_g0_nc; break;
483249259Sdim  }
484249259Sdim
485249259Sdim  return Result | getAddressWithFixup(UImm16MO, requestedFixup, Fixups);
486249259Sdim}
487249259Sdim
488249259Sdimtemplate<int hasRs, int hasRt2> unsigned
489249259SdimAArch64MCCodeEmitter::fixLoadStoreExclusive(const MCInst &MI,
490249259Sdim                                            unsigned EncodedValue) const {
491249259Sdim  if (!hasRs) EncodedValue |= 0x001F0000;
492249259Sdim  if (!hasRt2) EncodedValue |= 0x00007C00;
493249259Sdim
494249259Sdim  return EncodedValue;
495249259Sdim}
496249259Sdim
497249259Sdimunsigned
498249259SdimAArch64MCCodeEmitter::fixMOVZ(const MCInst &MI, unsigned EncodedValue) const {
499249259Sdim  // If one of the signed fixup kinds is applied to a MOVZ instruction, the
500249259Sdim  // eventual result could be either a MOVZ or a MOVN. It's the MCCodeEmitter's
501249259Sdim  // job to ensure that any bits possibly affected by this are 0. This means we
502249259Sdim  // must zero out bit 30 (essentially emitting a MOVN).
503249259Sdim  MCOperand UImm16MO = MI.getOperand(1);
504249259Sdim
505249259Sdim  // Nothing to do if there's no fixup.
506249259Sdim  if (UImm16MO.isImm())
507249259Sdim    return EncodedValue;
508249259Sdim
509249259Sdim  const AArch64MCExpr *A64E = cast<AArch64MCExpr>(UImm16MO.getExpr());
510249259Sdim  switch (A64E->getKind()) {
511249259Sdim  case AArch64MCExpr::VK_AARCH64_SABS_G0:
512249259Sdim  case AArch64MCExpr::VK_AARCH64_SABS_G1:
513249259Sdim  case AArch64MCExpr::VK_AARCH64_SABS_G2:
514249259Sdim  case AArch64MCExpr::VK_AARCH64_DTPREL_G2:
515249259Sdim  case AArch64MCExpr::VK_AARCH64_DTPREL_G1:
516249259Sdim  case AArch64MCExpr::VK_AARCH64_DTPREL_G0:
517249259Sdim  case AArch64MCExpr::VK_AARCH64_GOTTPREL_G1:
518249259Sdim  case AArch64MCExpr::VK_AARCH64_TPREL_G2:
519249259Sdim  case AArch64MCExpr::VK_AARCH64_TPREL_G1:
520249259Sdim  case AArch64MCExpr::VK_AARCH64_TPREL_G0:
521249259Sdim    return EncodedValue & ~(1u << 30);
522249259Sdim  default:
523249259Sdim    // Nothing to do for an unsigned fixup.
524249259Sdim    return EncodedValue;
525249259Sdim  }
526249259Sdim
527249259Sdim  llvm_unreachable("Should have returned by now");
528249259Sdim}
529249259Sdim
530249259Sdimunsigned
531249259SdimAArch64MCCodeEmitter::fixMulHigh(const MCInst &MI,
532249259Sdim                                 unsigned EncodedValue) const {
533249259Sdim  // The Ra field of SMULH and UMULH is unused: it should be assembled as 31
534249259Sdim  // (i.e. all bits 1) but is ignored by the processor.
535249259Sdim  EncodedValue |= 0x1f << 10;
536249259Sdim  return EncodedValue;
537249259Sdim}
538249259Sdim
539249259SdimMCCodeEmitter *llvm::createAArch64MCCodeEmitter(const MCInstrInfo &MCII,
540249259Sdim                                                const MCRegisterInfo &MRI,
541249259Sdim                                                const MCSubtargetInfo &STI,
542249259Sdim                                                MCContext &Ctx) {
543249259Sdim  return new AArch64MCCodeEmitter(Ctx);
544249259Sdim}
545249259Sdim
546249259Sdimvoid AArch64MCCodeEmitter::
547249259SdimEncodeInstruction(const MCInst &MI, raw_ostream &OS,
548249259Sdim                  SmallVectorImpl<MCFixup> &Fixups) const {
549249259Sdim  if (MI.getOpcode() == AArch64::TLSDESCCALL) {
550249259Sdim    // This is a directive which applies an R_AARCH64_TLSDESC_CALL to the
551249259Sdim    // following (BLR) instruction. It doesn't emit any code itself so it
552249259Sdim    // doesn't go through the normal TableGenerated channels.
553249259Sdim    MCFixupKind Fixup = MCFixupKind(AArch64::fixup_a64_tlsdesc_call);
554249259Sdim    const MCExpr *Expr;
555249259Sdim    Expr = AArch64MCExpr::CreateTLSDesc(MI.getOperand(0).getExpr(), Ctx);
556249259Sdim    Fixups.push_back(MCFixup::Create(0, Expr, Fixup));
557249259Sdim    return;
558249259Sdim  }
559249259Sdim
560249259Sdim  uint32_t Binary = getBinaryCodeForInstr(MI, Fixups);
561249259Sdim
562249259Sdim  EmitInstruction(Binary, OS);
563249259Sdim}
564249259Sdim
565249259Sdim
566249259Sdim#include "AArch64GenMCCodeEmitter.inc"
567