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