AArch64AsmPrinter.cpp revision 627ef0cf5e3d1989eadab38e491268847b32869f
1//===-- AArch64AsmPrinter.cpp - Print machine code to an AArch64 .s file --===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file contains a printer that converts from our internal representation 11// of machine-dependent LLVM code to GAS-format AArch64 assembly language. 12// 13//===----------------------------------------------------------------------===// 14 15#define DEBUG_TYPE "asm-printer" 16#include "AArch64AsmPrinter.h" 17#include "InstPrinter/AArch64InstPrinter.h" 18#include "llvm/DebugInfo.h" 19#include "llvm/ADT/SmallString.h" 20#include "llvm/CodeGen/MachineModuleInfoImpls.h" 21#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" 22#include "llvm/MC/MCAsmInfo.h" 23#include "llvm/MC/MCInst.h" 24#include "llvm/MC/MCSymbol.h" 25#include "llvm/Support/TargetRegistry.h" 26#include "llvm/Target/Mangler.h" 27 28using namespace llvm; 29 30/// Try to print a floating-point register as if it belonged to a specified 31/// register-class. For example the inline asm operand modifier "b" requires its 32/// argument to be printed as "bN". 33static bool printModifiedFPRAsmOperand(const MachineOperand &MO, 34 const TargetRegisterInfo *TRI, 35 char RegType, raw_ostream &O) { 36 if (!MO.isReg()) 37 return true; 38 39 for (MCRegAliasIterator AR(MO.getReg(), TRI, true); AR.isValid(); ++AR) { 40 if (AArch64::FPR8RegClass.contains(*AR)) { 41 O << RegType << TRI->getEncodingValue(MO.getReg()); 42 return false; 43 } 44 } 45 46 // The register doesn't correspond to anything floating-point like. 47 return true; 48} 49 50/// Implements the 'w' and 'x' inline asm operand modifiers, which print a GPR 51/// with the obvious type and an immediate 0 as either wzr or xzr. 52static bool printModifiedGPRAsmOperand(const MachineOperand &MO, 53 const TargetRegisterInfo *TRI, 54 const TargetRegisterClass &RegClass, 55 raw_ostream &O) { 56 char Prefix = &RegClass == &AArch64::GPR32RegClass ? 'w' : 'x'; 57 58 if (MO.isImm() && MO.getImm() == 0) { 59 O << Prefix << "zr"; 60 return false; 61 } else if (MO.isReg()) { 62 if (MO.getReg() == AArch64::XSP || MO.getReg() == AArch64::WSP) { 63 O << (Prefix == 'x' ? "sp" : "wsp"); 64 return false; 65 } 66 67 for (MCRegAliasIterator AR(MO.getReg(), TRI, true); AR.isValid(); ++AR) { 68 if (RegClass.contains(*AR)) { 69 O << AArch64InstPrinter::getRegisterName(*AR); 70 return false; 71 } 72 } 73 } 74 75 return true; 76} 77 78bool AArch64AsmPrinter::printSymbolicAddress(const MachineOperand &MO, 79 bool PrintImmediatePrefix, 80 StringRef Suffix, raw_ostream &O) { 81 StringRef Name; 82 StringRef Modifier; 83 switch (MO.getType()) { 84 default: 85 return true; 86 case MachineOperand::MO_GlobalAddress: 87 Name = getSymbol(MO.getGlobal())->getName(); 88 89 // Global variables may be accessed either via a GOT or in various fun and 90 // interesting TLS-model specific ways. Set the prefix modifier as 91 // appropriate here. 92 if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(MO.getGlobal())) { 93 Reloc::Model RelocM = TM.getRelocationModel(); 94 if (GV->isThreadLocal()) { 95 switch (TM.getTLSModel(GV)) { 96 case TLSModel::GeneralDynamic: 97 Modifier = "tlsdesc"; 98 break; 99 case TLSModel::LocalDynamic: 100 Modifier = "dtprel"; 101 break; 102 case TLSModel::InitialExec: 103 Modifier = "gottprel"; 104 break; 105 case TLSModel::LocalExec: 106 Modifier = "tprel"; 107 break; 108 } 109 } else if (Subtarget->GVIsIndirectSymbol(GV, RelocM)) { 110 Modifier = "got"; 111 } 112 } 113 break; 114 case MachineOperand::MO_BlockAddress: 115 Name = GetBlockAddressSymbol(MO.getBlockAddress())->getName(); 116 break; 117 case MachineOperand::MO_ExternalSymbol: 118 Name = MO.getSymbolName(); 119 break; 120 case MachineOperand::MO_ConstantPoolIndex: 121 Name = GetCPISymbol(MO.getIndex())->getName(); 122 break; 123 } 124 125 // Some instructions (notably ADRP) don't take the # prefix for 126 // immediates. Only print it if asked to. 127 if (PrintImmediatePrefix) 128 O << '#'; 129 130 // Only need the joining "_" if both the prefix and the suffix are 131 // non-null. This little block simply takes care of the four possibly 132 // combinations involved there. 133 if (Modifier == "" && Suffix == "") 134 O << Name; 135 else if (Modifier == "" && Suffix != "") 136 O << ":" << Suffix << ':' << Name; 137 else if (Modifier != "" && Suffix == "") 138 O << ":" << Modifier << ':' << Name; 139 else 140 O << ":" << Modifier << '_' << Suffix << ':' << Name; 141 142 return false; 143} 144 145bool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, 146 unsigned AsmVariant, 147 const char *ExtraCode, raw_ostream &O) { 148 const TargetRegisterInfo *TRI = MF->getTarget().getRegisterInfo(); 149 150 if (!ExtraCode) 151 ExtraCode = ""; 152 153 switch(ExtraCode[0]) { 154 default: 155 break; 156 case 'c': // Don't print "#" before an immediate operand. 157 if (MI->getOperand(OpNum).isImm()) { 158 O << MI->getOperand(OpNum).getImm(); 159 return false; 160 } 161 break; 162 case 'w': 163 // Output 32-bit general register operand, constant zero as wzr, or stack 164 // pointer as wsp. Ignored when used with other operand types. 165 if (!printModifiedGPRAsmOperand(MI->getOperand(OpNum), TRI, 166 AArch64::GPR32RegClass, O)) 167 return false; 168 break; 169 case 'x': 170 // Output 64-bit general register operand, constant zero as xzr, or stack 171 // pointer as sp. Ignored when used with other operand types. 172 if (!printModifiedGPRAsmOperand(MI->getOperand(OpNum), TRI, 173 AArch64::GPR64RegClass, O)) 174 return false; 175 break; 176 case 'H': 177 // Output higher numbered of a 64-bit general register pair 178 case 'Q': 179 // Output least significant register of a 64-bit general register pair 180 case 'R': 181 // Output most significant register of a 64-bit general register pair 182 183 // FIXME note: these three operand modifiers will require, to some extent, 184 // adding a paired GPR64 register class. Initial investigation suggests that 185 // assertions are hit unless it has a type and is made legal for that type 186 // in ISelLowering. After that step is made, the number of modifications 187 // needed explodes (operation legality, calling conventions, stores, reg 188 // copies ...). 189 llvm_unreachable("FIXME: Unimplemented register pairs"); 190 case 'b': 191 case 'h': 192 case 's': 193 case 'd': 194 case 'q': 195 if (!printModifiedFPRAsmOperand(MI->getOperand(OpNum), TRI, 196 ExtraCode[0], O)) 197 return false; 198 break; 199 case 'A': 200 // Output symbolic address with appropriate relocation modifier (also 201 // suitable for ADRP). 202 if (!printSymbolicAddress(MI->getOperand(OpNum), false, "", O)) 203 return false; 204 break; 205 case 'L': 206 // Output bits 11:0 of symbolic address with appropriate :lo12: relocation 207 // modifier. 208 if (!printSymbolicAddress(MI->getOperand(OpNum), true, "lo12", O)) 209 return false; 210 break; 211 case 'G': 212 // Output bits 23:12 of symbolic address with appropriate :hi12: relocation 213 // modifier (currently only for TLS local exec). 214 if (!printSymbolicAddress(MI->getOperand(OpNum), true, "hi12", O)) 215 return false; 216 break; 217 case 'a': 218 return PrintAsmMemoryOperand(MI, OpNum, AsmVariant, ExtraCode, O); 219 } 220 221 // There's actually no operand modifier, which leads to a slightly eclectic 222 // set of behaviour which we have to handle here. 223 const MachineOperand &MO = MI->getOperand(OpNum); 224 switch (MO.getType()) { 225 default: 226 llvm_unreachable("Unexpected operand for inline assembly"); 227 case MachineOperand::MO_Register: 228 // GCC prints the unmodified operand of a 'w' constraint as the vector 229 // register. Technically, we could allocate the argument as a VPR128, but 230 // that leads to extremely dodgy copies being generated to get the data 231 // there. 232 if (printModifiedFPRAsmOperand(MO, TRI, 'v', O)) 233 O << AArch64InstPrinter::getRegisterName(MO.getReg()); 234 break; 235 case MachineOperand::MO_Immediate: 236 O << '#' << MO.getImm(); 237 break; 238 case MachineOperand::MO_FPImmediate: 239 assert(MO.getFPImm()->isExactlyValue(0.0) && "Only FP 0.0 expected"); 240 O << "#0.0"; 241 break; 242 case MachineOperand::MO_BlockAddress: 243 case MachineOperand::MO_ConstantPoolIndex: 244 case MachineOperand::MO_GlobalAddress: 245 case MachineOperand::MO_ExternalSymbol: 246 return printSymbolicAddress(MO, false, "", O); 247 } 248 249 return false; 250} 251 252bool AArch64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 253 unsigned OpNum, 254 unsigned AsmVariant, 255 const char *ExtraCode, 256 raw_ostream &O) { 257 // Currently both the memory constraints (m and Q) behave the same and amount 258 // to the address as a single register. In future, we may allow "m" to provide 259 // both a base and an offset. 260 const MachineOperand &MO = MI->getOperand(OpNum); 261 assert(MO.isReg() && "unexpected inline assembly memory operand"); 262 O << '[' << AArch64InstPrinter::getRegisterName(MO.getReg()) << ']'; 263 return false; 264} 265 266#include "AArch64GenMCPseudoLowering.inc" 267 268void AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) { 269 // Do any auto-generated pseudo lowerings. 270 if (emitPseudoExpansionLowering(OutStreamer, MI)) 271 return; 272 273 MCInst TmpInst; 274 LowerAArch64MachineInstrToMCInst(MI, TmpInst, *this); 275 OutStreamer.EmitInstruction(TmpInst); 276} 277 278void AArch64AsmPrinter::EmitEndOfAsmFile(Module &M) { 279 if (Subtarget->isTargetELF()) { 280 const TargetLoweringObjectFileELF &TLOFELF = 281 static_cast<const TargetLoweringObjectFileELF &>(getObjFileLowering()); 282 283 MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>(); 284 285 // Output stubs for external and common global variables. 286 MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList(); 287 if (!Stubs.empty()) { 288 OutStreamer.SwitchSection(TLOFELF.getDataRelSection()); 289 const DataLayout *TD = TM.getDataLayout(); 290 291 for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { 292 OutStreamer.EmitLabel(Stubs[i].first); 293 OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(), 294 TD->getPointerSize(0)); 295 } 296 Stubs.clear(); 297 } 298 } 299} 300 301bool AArch64AsmPrinter::runOnMachineFunction(MachineFunction &MF) { 302 return AsmPrinter::runOnMachineFunction(MF); 303} 304 305// Force static initialization. 306extern "C" void LLVMInitializeAArch64AsmPrinter() { 307 RegisterAsmPrinter<AArch64AsmPrinter> X(TheAArch64Target); 308} 309 310