1249259Sdim//===-- AArch64AsmPrinter.cpp - Print machine code to an AArch64 .s file --===//
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 contains a printer that converts from our internal representation
11249259Sdim// of machine-dependent LLVM code to GAS-format AArch64 assembly language.
12249259Sdim//
13249259Sdim//===----------------------------------------------------------------------===//
14249259Sdim
15249259Sdim#define DEBUG_TYPE "asm-printer"
16249259Sdim#include "AArch64AsmPrinter.h"
17249259Sdim#include "InstPrinter/AArch64InstPrinter.h"
18249259Sdim#include "llvm/DebugInfo.h"
19249259Sdim#include "llvm/ADT/SmallString.h"
20249259Sdim#include "llvm/CodeGen/MachineModuleInfoImpls.h"
21249259Sdim#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
22249259Sdim#include "llvm/MC/MCAsmInfo.h"
23249259Sdim#include "llvm/MC/MCInst.h"
24249259Sdim#include "llvm/MC/MCSymbol.h"
25249259Sdim#include "llvm/Support/TargetRegistry.h"
26249259Sdim#include "llvm/Target/Mangler.h"
27249259Sdim
28249259Sdimusing namespace llvm;
29249259Sdim
30249259Sdim/// Try to print a floating-point register as if it belonged to a specified
31249259Sdim/// register-class. For example the inline asm operand modifier "b" requires its
32249259Sdim/// argument to be printed as "bN".
33249259Sdimstatic bool printModifiedFPRAsmOperand(const MachineOperand &MO,
34249259Sdim                                       const TargetRegisterInfo *TRI,
35263508Sdim                                       char RegType, raw_ostream &O) {
36249259Sdim  if (!MO.isReg())
37249259Sdim    return true;
38249259Sdim
39249259Sdim  for (MCRegAliasIterator AR(MO.getReg(), TRI, true); AR.isValid(); ++AR) {
40263508Sdim    if (AArch64::FPR8RegClass.contains(*AR)) {
41263508Sdim      O << RegType << TRI->getEncodingValue(MO.getReg());
42249259Sdim      return false;
43249259Sdim    }
44249259Sdim  }
45263508Sdim
46263508Sdim  // The register doesn't correspond to anything floating-point like.
47249259Sdim  return true;
48249259Sdim}
49249259Sdim
50249259Sdim/// Implements the 'w' and 'x' inline asm operand modifiers, which print a GPR
51249259Sdim/// with the obvious type and an immediate 0 as either wzr or xzr.
52249259Sdimstatic bool printModifiedGPRAsmOperand(const MachineOperand &MO,
53249259Sdim                                       const TargetRegisterInfo *TRI,
54249259Sdim                                       const TargetRegisterClass &RegClass,
55249259Sdim                                       raw_ostream &O) {
56249259Sdim  char Prefix = &RegClass == &AArch64::GPR32RegClass ? 'w' : 'x';
57249259Sdim
58249259Sdim  if (MO.isImm() && MO.getImm() == 0) {
59249259Sdim    O << Prefix << "zr";
60249259Sdim    return false;
61249259Sdim  } else if (MO.isReg()) {
62249259Sdim    if (MO.getReg() == AArch64::XSP || MO.getReg() == AArch64::WSP) {
63249259Sdim      O << (Prefix == 'x' ? "sp" : "wsp");
64249259Sdim      return false;
65249259Sdim    }
66249259Sdim
67249259Sdim    for (MCRegAliasIterator AR(MO.getReg(), TRI, true); AR.isValid(); ++AR) {
68249259Sdim      if (RegClass.contains(*AR)) {
69249259Sdim        O << AArch64InstPrinter::getRegisterName(*AR);
70249259Sdim        return false;
71249259Sdim      }
72249259Sdim    }
73249259Sdim  }
74249259Sdim
75249259Sdim  return true;
76249259Sdim}
77249259Sdim
78249259Sdimbool AArch64AsmPrinter::printSymbolicAddress(const MachineOperand &MO,
79249259Sdim                                             bool PrintImmediatePrefix,
80249259Sdim                                             StringRef Suffix, raw_ostream &O) {
81249259Sdim  StringRef Name;
82249259Sdim  StringRef Modifier;
83249259Sdim  switch (MO.getType()) {
84249259Sdim  default:
85263508Sdim    return true;
86249259Sdim  case MachineOperand::MO_GlobalAddress:
87263508Sdim    Name = getSymbol(MO.getGlobal())->getName();
88249259Sdim
89249259Sdim    // Global variables may be accessed either via a GOT or in various fun and
90249259Sdim    // interesting TLS-model specific ways. Set the prefix modifier as
91249259Sdim    // appropriate here.
92249259Sdim    if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(MO.getGlobal())) {
93249259Sdim      Reloc::Model RelocM = TM.getRelocationModel();
94249259Sdim      if (GV->isThreadLocal()) {
95249259Sdim        switch (TM.getTLSModel(GV)) {
96249259Sdim        case TLSModel::GeneralDynamic:
97249259Sdim          Modifier = "tlsdesc";
98249259Sdim          break;
99249259Sdim        case TLSModel::LocalDynamic:
100249259Sdim          Modifier = "dtprel";
101249259Sdim          break;
102249259Sdim        case TLSModel::InitialExec:
103249259Sdim          Modifier = "gottprel";
104249259Sdim          break;
105249259Sdim        case TLSModel::LocalExec:
106249259Sdim          Modifier = "tprel";
107249259Sdim          break;
108249259Sdim        }
109249259Sdim      } else if (Subtarget->GVIsIndirectSymbol(GV, RelocM)) {
110249259Sdim        Modifier = "got";
111249259Sdim      }
112249259Sdim    }
113249259Sdim    break;
114249259Sdim  case MachineOperand::MO_BlockAddress:
115249259Sdim    Name = GetBlockAddressSymbol(MO.getBlockAddress())->getName();
116249259Sdim    break;
117249259Sdim  case MachineOperand::MO_ExternalSymbol:
118249259Sdim    Name = MO.getSymbolName();
119249259Sdim    break;
120249259Sdim  case MachineOperand::MO_ConstantPoolIndex:
121249259Sdim    Name = GetCPISymbol(MO.getIndex())->getName();
122249259Sdim    break;
123249259Sdim  }
124249259Sdim
125249259Sdim  // Some instructions (notably ADRP) don't take the # prefix for
126249259Sdim  // immediates. Only print it if asked to.
127249259Sdim  if (PrintImmediatePrefix)
128249259Sdim    O << '#';
129249259Sdim
130249259Sdim  // Only need the joining "_" if both the prefix and the suffix are
131249259Sdim  // non-null. This little block simply takes care of the four possibly
132249259Sdim  // combinations involved there.
133249259Sdim  if (Modifier == "" && Suffix == "")
134249259Sdim    O << Name;
135249259Sdim  else if (Modifier == "" && Suffix != "")
136249259Sdim    O << ":" << Suffix << ':' << Name;
137249259Sdim  else if (Modifier != "" && Suffix == "")
138249259Sdim    O << ":" << Modifier << ':' << Name;
139249259Sdim  else
140249259Sdim    O << ":" << Modifier << '_' << Suffix << ':' << Name;
141249259Sdim
142249259Sdim  return false;
143249259Sdim}
144249259Sdim
145249259Sdimbool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
146249259Sdim                                        unsigned AsmVariant,
147249259Sdim                                        const char *ExtraCode, raw_ostream &O) {
148249259Sdim  const TargetRegisterInfo *TRI = MF->getTarget().getRegisterInfo();
149249259Sdim
150263508Sdim  if (!ExtraCode)
151263508Sdim    ExtraCode = "";
152263508Sdim
153249259Sdim  switch(ExtraCode[0]) {
154249259Sdim  default:
155263508Sdim    if (!AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O))
156263508Sdim        return false;
157263508Sdim    break;
158249259Sdim  case 'w':
159249259Sdim    // Output 32-bit general register operand, constant zero as wzr, or stack
160249259Sdim    // pointer as wsp. Ignored when used with other operand types.
161263508Sdim    if (!printModifiedGPRAsmOperand(MI->getOperand(OpNum), TRI,
162263508Sdim                                    AArch64::GPR32RegClass, O))
163263508Sdim      return false;
164263508Sdim    break;
165249259Sdim  case 'x':
166249259Sdim    // Output 64-bit general register operand, constant zero as xzr, or stack
167249259Sdim    // pointer as sp. Ignored when used with other operand types.
168263508Sdim    if (!printModifiedGPRAsmOperand(MI->getOperand(OpNum), TRI,
169263508Sdim                                    AArch64::GPR64RegClass, O))
170263508Sdim      return false;
171263508Sdim    break;
172249259Sdim  case 'H':
173249259Sdim    // Output higher numbered of a 64-bit general register pair
174249259Sdim  case 'Q':
175249259Sdim    // Output least significant register of a 64-bit general register pair
176249259Sdim  case 'R':
177249259Sdim    // Output most significant register of a 64-bit general register pair
178249259Sdim
179249259Sdim    // FIXME note: these three operand modifiers will require, to some extent,
180249259Sdim    // adding a paired GPR64 register class. Initial investigation suggests that
181249259Sdim    // assertions are hit unless it has a type and is made legal for that type
182249259Sdim    // in ISelLowering. After that step is made, the number of modifications
183249259Sdim    // needed explodes (operation legality, calling conventions, stores, reg
184249259Sdim    // copies ...).
185249259Sdim    llvm_unreachable("FIXME: Unimplemented register pairs");
186249259Sdim  case 'b':
187249259Sdim  case 'h':
188249259Sdim  case 's':
189249259Sdim  case 'd':
190249259Sdim  case 'q':
191263508Sdim    if (!printModifiedFPRAsmOperand(MI->getOperand(OpNum), TRI,
192263508Sdim                                    ExtraCode[0], O))
193263508Sdim      return false;
194263508Sdim    break;
195249259Sdim  case 'A':
196249259Sdim    // Output symbolic address with appropriate relocation modifier (also
197249259Sdim    // suitable for ADRP).
198263508Sdim    if (!printSymbolicAddress(MI->getOperand(OpNum), false, "", O))
199263508Sdim      return false;
200263508Sdim    break;
201249259Sdim  case 'L':
202249259Sdim    // Output bits 11:0 of symbolic address with appropriate :lo12: relocation
203249259Sdim    // modifier.
204263508Sdim    if (!printSymbolicAddress(MI->getOperand(OpNum), true, "lo12", O))
205263508Sdim      return false;
206263508Sdim    break;
207249259Sdim  case 'G':
208249259Sdim    // Output bits 23:12 of symbolic address with appropriate :hi12: relocation
209249259Sdim    // modifier (currently only for TLS local exec).
210263508Sdim    if (!printSymbolicAddress(MI->getOperand(OpNum), true, "hi12", O))
211263508Sdim      return false;
212263508Sdim    break;
213263508Sdim  case 'a':
214263508Sdim    return PrintAsmMemoryOperand(MI, OpNum, AsmVariant, ExtraCode, O);
215249259Sdim  }
216249259Sdim
217263508Sdim  // There's actually no operand modifier, which leads to a slightly eclectic
218263508Sdim  // set of behaviour which we have to handle here.
219263508Sdim  const MachineOperand &MO = MI->getOperand(OpNum);
220263508Sdim  switch (MO.getType()) {
221263508Sdim  default:
222263508Sdim    llvm_unreachable("Unexpected operand for inline assembly");
223263508Sdim  case MachineOperand::MO_Register:
224263508Sdim    // GCC prints the unmodified operand of a 'w' constraint as the vector
225263508Sdim    // register. Technically, we could allocate the argument as a VPR128, but
226263508Sdim    // that leads to extremely dodgy copies being generated to get the data
227263508Sdim    // there.
228263508Sdim    if (printModifiedFPRAsmOperand(MO, TRI, 'v', O))
229263508Sdim      O << AArch64InstPrinter::getRegisterName(MO.getReg());
230263508Sdim    break;
231263508Sdim  case MachineOperand::MO_Immediate:
232263508Sdim    O << '#' << MO.getImm();
233263508Sdim    break;
234263508Sdim  case MachineOperand::MO_FPImmediate:
235263508Sdim    assert(MO.getFPImm()->isExactlyValue(0.0) && "Only FP 0.0 expected");
236263508Sdim    O << "#0.0";
237263508Sdim    break;
238263508Sdim  case MachineOperand::MO_BlockAddress:
239263508Sdim  case MachineOperand::MO_ConstantPoolIndex:
240263508Sdim  case MachineOperand::MO_GlobalAddress:
241263508Sdim  case MachineOperand::MO_ExternalSymbol:
242263508Sdim    return printSymbolicAddress(MO, false, "", O);
243263508Sdim  }
244249259Sdim
245263508Sdim  return false;
246249259Sdim}
247249259Sdim
248249259Sdimbool AArch64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
249249259Sdim                                              unsigned OpNum,
250249259Sdim                                              unsigned AsmVariant,
251249259Sdim                                              const char *ExtraCode,
252249259Sdim                                              raw_ostream &O) {
253249259Sdim  // Currently both the memory constraints (m and Q) behave the same and amount
254249259Sdim  // to the address as a single register. In future, we may allow "m" to provide
255249259Sdim  // both a base and an offset.
256249259Sdim  const MachineOperand &MO = MI->getOperand(OpNum);
257249259Sdim  assert(MO.isReg() && "unexpected inline assembly memory operand");
258249259Sdim  O << '[' << AArch64InstPrinter::getRegisterName(MO.getReg()) << ']';
259249259Sdim  return false;
260249259Sdim}
261249259Sdim
262249259Sdim#include "AArch64GenMCPseudoLowering.inc"
263249259Sdim
264249259Sdimvoid AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
265249259Sdim  // Do any auto-generated pseudo lowerings.
266249259Sdim  if (emitPseudoExpansionLowering(OutStreamer, MI))
267249259Sdim    return;
268249259Sdim
269249259Sdim  MCInst TmpInst;
270249259Sdim  LowerAArch64MachineInstrToMCInst(MI, TmpInst, *this);
271249259Sdim  OutStreamer.EmitInstruction(TmpInst);
272249259Sdim}
273249259Sdim
274249259Sdimvoid AArch64AsmPrinter::EmitEndOfAsmFile(Module &M) {
275249259Sdim  if (Subtarget->isTargetELF()) {
276249259Sdim    const TargetLoweringObjectFileELF &TLOFELF =
277249259Sdim      static_cast<const TargetLoweringObjectFileELF &>(getObjFileLowering());
278249259Sdim
279249259Sdim    MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>();
280249259Sdim
281249259Sdim    // Output stubs for external and common global variables.
282249259Sdim    MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList();
283249259Sdim    if (!Stubs.empty()) {
284249259Sdim      OutStreamer.SwitchSection(TLOFELF.getDataRelSection());
285249259Sdim      const DataLayout *TD = TM.getDataLayout();
286249259Sdim
287249259Sdim      for (unsigned i = 0, e = Stubs.size(); i != e; ++i) {
288249259Sdim        OutStreamer.EmitLabel(Stubs[i].first);
289249259Sdim        OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(),
290263508Sdim                                    TD->getPointerSize(0));
291249259Sdim      }
292249259Sdim      Stubs.clear();
293249259Sdim    }
294249259Sdim  }
295249259Sdim}
296249259Sdim
297249259Sdimbool AArch64AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
298249259Sdim  return AsmPrinter::runOnMachineFunction(MF);
299249259Sdim}
300249259Sdim
301249259Sdim// Force static initialization.
302249259Sdimextern "C" void LLVMInitializeAArch64AsmPrinter() {
303249259Sdim    RegisterAsmPrinter<AArch64AsmPrinter> X(TheAArch64Target);
304249259Sdim}
305249259Sdim
306