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