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