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/ADT/SmallString.h" 19 #include "llvm/CodeGen/MachineModuleInfoImpls.h" 20 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" 21 #include "llvm/DebugInfo.h" 22 #include "llvm/IR/Mangler.h" 23 #include "llvm/MC/MCAsmInfo.h" 24 #include "llvm/MC/MCInst.h" 25 #include "llvm/MC/MCSymbol.h" 26 #include "llvm/Support/TargetRegistry.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 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. 52 static 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 78 bool 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_ConstantPoolIndex: 118 Name = GetCPISymbol(MO.getIndex())->getName(); 119 break; 120 } 121 122 // Some instructions (notably ADRP) don't take the # prefix for 123 // immediates. Only print it if asked to. 124 if (PrintImmediatePrefix) 125 O << '#'; 126 127 // Only need the joining "_" if both the prefix and the suffix are 128 // non-null. This little block simply takes care of the four possibly 129 // combinations involved there. 130 if (Modifier == "" && Suffix == "") 131 O << Name; 132 else if (Modifier == "" && Suffix != "") 133 O << ":" << Suffix << ':' << Name; 134 else if (Modifier != "" && Suffix == "") 135 O << ":" << Modifier << ':' << Name; 136 else 137 O << ":" << Modifier << '_' << Suffix << ':' << Name; 138 139 return false; 140 } 141 142 bool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, 143 unsigned AsmVariant, 144 const char *ExtraCode, raw_ostream &O) { 145 const TargetRegisterInfo *TRI = MF->getTarget().getRegisterInfo(); 146 147 if (!ExtraCode) 148 ExtraCode = ""; 149 150 switch(ExtraCode[0]) { 151 default: 152 if (!AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O)) 153 return false; 154 break; 155 case 'w': 156 // Output 32-bit general register operand, constant zero as wzr, or stack 157 // pointer as wsp. Ignored when used with other operand types. 158 if (!printModifiedGPRAsmOperand(MI->getOperand(OpNum), TRI, 159 AArch64::GPR32RegClass, O)) 160 return false; 161 break; 162 case 'x': 163 // Output 64-bit general register operand, constant zero as xzr, or stack 164 // pointer as sp. Ignored when used with other operand types. 165 if (!printModifiedGPRAsmOperand(MI->getOperand(OpNum), TRI, 166 AArch64::GPR64RegClass, O)) 167 return false; 168 break; 169 case 'H': 170 // Output higher numbered of a 64-bit general register pair 171 case 'Q': 172 // Output least significant register of a 64-bit general register pair 173 case 'R': 174 // Output most significant register of a 64-bit general register pair 175 176 // FIXME note: these three operand modifiers will require, to some extent, 177 // adding a paired GPR64 register class. Initial investigation suggests that 178 // assertions are hit unless it has a type and is made legal for that type 179 // in ISelLowering. After that step is made, the number of modifications 180 // needed explodes (operation legality, calling conventions, stores, reg 181 // copies ...). 182 llvm_unreachable("FIXME: Unimplemented register pairs"); 183 case 'b': 184 case 'h': 185 case 's': 186 case 'd': 187 case 'q': 188 if (!printModifiedFPRAsmOperand(MI->getOperand(OpNum), TRI, 189 ExtraCode[0], O)) 190 return false; 191 break; 192 case 'A': 193 // Output symbolic address with appropriate relocation modifier (also 194 // suitable for ADRP). 195 if (!printSymbolicAddress(MI->getOperand(OpNum), false, "", O)) 196 return false; 197 break; 198 case 'L': 199 // Output bits 11:0 of symbolic address with appropriate :lo12: relocation 200 // modifier. 201 if (!printSymbolicAddress(MI->getOperand(OpNum), true, "lo12", O)) 202 return false; 203 break; 204 case 'G': 205 // Output bits 23:12 of symbolic address with appropriate :hi12: relocation 206 // modifier (currently only for TLS local exec). 207 if (!printSymbolicAddress(MI->getOperand(OpNum), true, "hi12", O)) 208 return false; 209 break; 210 case 'a': 211 return PrintAsmMemoryOperand(MI, OpNum, AsmVariant, ExtraCode, O); 212 } 213 214 // There's actually no operand modifier, which leads to a slightly eclectic 215 // set of behaviour which we have to handle here. 216 const MachineOperand &MO = MI->getOperand(OpNum); 217 switch (MO.getType()) { 218 default: 219 llvm_unreachable("Unexpected operand for inline assembly"); 220 case MachineOperand::MO_Register: 221 // GCC prints the unmodified operand of a 'w' constraint as the vector 222 // register. Technically, we could allocate the argument as a VPR128, but 223 // that leads to extremely dodgy copies being generated to get the data 224 // there. 225 if (printModifiedFPRAsmOperand(MO, TRI, 'v', O)) 226 O << AArch64InstPrinter::getRegisterName(MO.getReg()); 227 break; 228 case MachineOperand::MO_Immediate: 229 O << '#' << MO.getImm(); 230 break; 231 case MachineOperand::MO_FPImmediate: 232 assert(MO.getFPImm()->isExactlyValue(0.0) && "Only FP 0.0 expected"); 233 O << "#0.0"; 234 break; 235 case MachineOperand::MO_BlockAddress: 236 case MachineOperand::MO_ConstantPoolIndex: 237 case MachineOperand::MO_GlobalAddress: 238 return printSymbolicAddress(MO, false, "", O); 239 } 240 241 return false; 242 } 243 244 bool AArch64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 245 unsigned OpNum, 246 unsigned AsmVariant, 247 const char *ExtraCode, 248 raw_ostream &O) { 249 // Currently both the memory constraints (m and Q) behave the same and amount 250 // to the address as a single register. In future, we may allow "m" to provide 251 // both a base and an offset. 252 const MachineOperand &MO = MI->getOperand(OpNum); 253 assert(MO.isReg() && "unexpected inline assembly memory operand"); 254 O << '[' << AArch64InstPrinter::getRegisterName(MO.getReg()) << ']'; 255 return false; 256 } 257 258 #include "AArch64GenMCPseudoLowering.inc" 259 260 void AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) { 261 // Do any auto-generated pseudo lowerings. 262 if (emitPseudoExpansionLowering(OutStreamer, MI)) 263 return; 264 265 MCInst TmpInst; 266 LowerAArch64MachineInstrToMCInst(MI, TmpInst, *this); 267 EmitToStreamer(OutStreamer, TmpInst); 268 } 269 270 void AArch64AsmPrinter::EmitEndOfAsmFile(Module &M) { 271 if (Subtarget->isTargetELF()) { 272 const TargetLoweringObjectFileELF &TLOFELF = 273 static_cast<const TargetLoweringObjectFileELF &>(getObjFileLowering()); 274 275 MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>(); 276 277 // Output stubs for external and common global variables. 278 MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList(); 279 if (!Stubs.empty()) { 280 OutStreamer.SwitchSection(TLOFELF.getDataRelSection()); 281 const DataLayout *TD = TM.getDataLayout(); 282 283 for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { 284 OutStreamer.EmitLabel(Stubs[i].first); 285 OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(), 286 TD->getPointerSize(0)); 287 } 288 Stubs.clear(); 289 } 290 } 291 } 292 293 bool AArch64AsmPrinter::runOnMachineFunction(MachineFunction &MF) { 294 return AsmPrinter::runOnMachineFunction(MF); 295 } 296 297 // Force static initialization. 298 extern "C" void LLVMInitializeAArch64AsmPrinter() { 299 RegisterAsmPrinter<AArch64AsmPrinter> X(TheAArch64Target); 300 } 301 302