1 //===- AArch64AsmPrinter.cpp - AArch64 LLVM assembly writer ---------------===// 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 the AArch64 assembly language. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "AArch64.h" 16 #include "AArch64MCInstLower.h" 17 #include "AArch64MachineFunctionInfo.h" 18 #include "AArch64RegisterInfo.h" 19 #include "AArch64Subtarget.h" 20 #include "AArch64TargetObjectFile.h" 21 #include "InstPrinter/AArch64InstPrinter.h" 22 #include "MCTargetDesc/AArch64AddressingModes.h" 23 #include "MCTargetDesc/AArch64MCTargetDesc.h" 24 #include "Utils/AArch64BaseInfo.h" 25 #include "llvm/ADT/SmallString.h" 26 #include "llvm/ADT/SmallVector.h" 27 #include "llvm/ADT/StringRef.h" 28 #include "llvm/ADT/Triple.h" 29 #include "llvm/ADT/Twine.h" 30 #include "llvm/CodeGen/AsmPrinter.h" 31 #include "llvm/CodeGen/MachineBasicBlock.h" 32 #include "llvm/CodeGen/MachineFunction.h" 33 #include "llvm/CodeGen/MachineInstr.h" 34 #include "llvm/CodeGen/MachineOperand.h" 35 #include "llvm/CodeGen/StackMaps.h" 36 #include "llvm/CodeGen/TargetRegisterInfo.h" 37 #include "llvm/IR/DataLayout.h" 38 #include "llvm/IR/DebugInfoMetadata.h" 39 #include "llvm/MC/MCAsmInfo.h" 40 #include "llvm/MC/MCContext.h" 41 #include "llvm/MC/MCInst.h" 42 #include "llvm/MC/MCInstBuilder.h" 43 #include "llvm/MC/MCStreamer.h" 44 #include "llvm/MC/MCSymbol.h" 45 #include "llvm/Support/Casting.h" 46 #include "llvm/Support/ErrorHandling.h" 47 #include "llvm/Support/TargetRegistry.h" 48 #include "llvm/Support/raw_ostream.h" 49 #include "llvm/Target/TargetMachine.h" 50 #include <algorithm> 51 #include <cassert> 52 #include <cstdint> 53 #include <map> 54 #include <memory> 55 56 using namespace llvm; 57 58 #define DEBUG_TYPE "asm-printer" 59 60 namespace { 61 62 class AArch64AsmPrinter : public AsmPrinter { 63 AArch64MCInstLower MCInstLowering; 64 StackMaps SM; 65 const AArch64Subtarget *STI; 66 67 public: 68 AArch64AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer) 69 : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this), 70 SM(*this) {} 71 72 StringRef getPassName() const override { return "AArch64 Assembly Printer"; } 73 74 /// \brief Wrapper for MCInstLowering.lowerOperand() for the 75 /// tblgen'erated pseudo lowering. 76 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const { 77 return MCInstLowering.lowerOperand(MO, MCOp); 78 } 79 80 void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM, 81 const MachineInstr &MI); 82 void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM, 83 const MachineInstr &MI); 84 85 void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI); 86 void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI); 87 void LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI); 88 89 void EmitSled(const MachineInstr &MI, SledKind Kind); 90 91 /// \brief tblgen'erated driver function for lowering simple MI->MC 92 /// pseudo instructions. 93 bool emitPseudoExpansionLowering(MCStreamer &OutStreamer, 94 const MachineInstr *MI); 95 96 void EmitInstruction(const MachineInstr *MI) override; 97 98 void getAnalysisUsage(AnalysisUsage &AU) const override { 99 AsmPrinter::getAnalysisUsage(AU); 100 AU.setPreservesAll(); 101 } 102 103 bool runOnMachineFunction(MachineFunction &F) override { 104 AArch64FI = F.getInfo<AArch64FunctionInfo>(); 105 STI = static_cast<const AArch64Subtarget*>(&F.getSubtarget()); 106 bool Result = AsmPrinter::runOnMachineFunction(F); 107 emitXRayTable(); 108 return Result; 109 } 110 111 private: 112 void printOperand(const MachineInstr *MI, unsigned OpNum, raw_ostream &O); 113 bool printAsmMRegister(const MachineOperand &MO, char Mode, raw_ostream &O); 114 bool printAsmRegInClass(const MachineOperand &MO, 115 const TargetRegisterClass *RC, bool isVector, 116 raw_ostream &O); 117 118 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, 119 unsigned AsmVariant, const char *ExtraCode, 120 raw_ostream &O) override; 121 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, 122 unsigned AsmVariant, const char *ExtraCode, 123 raw_ostream &O) override; 124 125 void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS); 126 127 void EmitFunctionBodyEnd() override; 128 129 MCSymbol *GetCPISymbol(unsigned CPID) const override; 130 void EmitEndOfAsmFile(Module &M) override; 131 132 AArch64FunctionInfo *AArch64FI = nullptr; 133 134 /// \brief Emit the LOHs contained in AArch64FI. 135 void EmitLOHs(); 136 137 /// Emit instruction to set float register to zero. 138 void EmitFMov0(const MachineInstr &MI); 139 140 using MInstToMCSymbol = std::map<const MachineInstr *, MCSymbol *>; 141 142 MInstToMCSymbol LOHInstToLabel; 143 }; 144 145 } // end anonymous namespace 146 147 void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI) 148 { 149 EmitSled(MI, SledKind::FUNCTION_ENTER); 150 } 151 152 void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) 153 { 154 EmitSled(MI, SledKind::FUNCTION_EXIT); 155 } 156 157 void AArch64AsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) 158 { 159 EmitSled(MI, SledKind::TAIL_CALL); 160 } 161 162 void AArch64AsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind) 163 { 164 static const int8_t NoopsInSledCount = 7; 165 // We want to emit the following pattern: 166 // 167 // .Lxray_sled_N: 168 // ALIGN 169 // B #32 170 // ; 7 NOP instructions (28 bytes) 171 // .tmpN 172 // 173 // We need the 28 bytes (7 instructions) because at runtime, we'd be patching 174 // over the full 32 bytes (8 instructions) with the following pattern: 175 // 176 // STP X0, X30, [SP, #-16]! ; push X0 and the link register to the stack 177 // LDR W0, #12 ; W0 := function ID 178 // LDR X16,#12 ; X16 := addr of __xray_FunctionEntry or __xray_FunctionExit 179 // BLR X16 ; call the tracing trampoline 180 // ;DATA: 32 bits of function ID 181 // ;DATA: lower 32 bits of the address of the trampoline 182 // ;DATA: higher 32 bits of the address of the trampoline 183 // LDP X0, X30, [SP], #16 ; pop X0 and the link register from the stack 184 // 185 OutStreamer->EmitCodeAlignment(4); 186 auto CurSled = OutContext.createTempSymbol("xray_sled_", true); 187 OutStreamer->EmitLabel(CurSled); 188 auto Target = OutContext.createTempSymbol(); 189 190 // Emit "B #32" instruction, which jumps over the next 28 bytes. 191 // The operand has to be the number of 4-byte instructions to jump over, 192 // including the current instruction. 193 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::B).addImm(8)); 194 195 for (int8_t I = 0; I < NoopsInSledCount; I++) 196 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0)); 197 198 OutStreamer->EmitLabel(Target); 199 recordSled(CurSled, MI, Kind); 200 } 201 202 void AArch64AsmPrinter::EmitEndOfAsmFile(Module &M) { 203 const Triple &TT = TM.getTargetTriple(); 204 if (TT.isOSBinFormatMachO()) { 205 // Funny Darwin hack: This flag tells the linker that no global symbols 206 // contain code that falls through to other global symbols (e.g. the obvious 207 // implementation of multiple entry points). If this doesn't occur, the 208 // linker can safely perform dead code stripping. Since LLVM never 209 // generates code that does this, it is always safe to set. 210 OutStreamer->EmitAssemblerFlag(MCAF_SubsectionsViaSymbols); 211 SM.serializeToStackMapSection(); 212 } 213 214 if (TT.isOSBinFormatCOFF()) { 215 const auto &TLOF = 216 static_cast<const TargetLoweringObjectFileCOFF &>(getObjFileLowering()); 217 218 std::string Flags; 219 raw_string_ostream OS(Flags); 220 221 for (const auto &Function : M) 222 TLOF.emitLinkerFlagsForGlobal(OS, &Function); 223 for (const auto &Global : M.globals()) 224 TLOF.emitLinkerFlagsForGlobal(OS, &Global); 225 for (const auto &Alias : M.aliases()) 226 TLOF.emitLinkerFlagsForGlobal(OS, &Alias); 227 228 OS.flush(); 229 230 // Output collected flags 231 if (!Flags.empty()) { 232 OutStreamer->SwitchSection(TLOF.getDrectveSection()); 233 OutStreamer->EmitBytes(Flags); 234 } 235 } 236 } 237 238 void AArch64AsmPrinter::EmitLOHs() { 239 SmallVector<MCSymbol *, 3> MCArgs; 240 241 for (const auto &D : AArch64FI->getLOHContainer()) { 242 for (const MachineInstr *MI : D.getArgs()) { 243 MInstToMCSymbol::iterator LabelIt = LOHInstToLabel.find(MI); 244 assert(LabelIt != LOHInstToLabel.end() && 245 "Label hasn't been inserted for LOH related instruction"); 246 MCArgs.push_back(LabelIt->second); 247 } 248 OutStreamer->EmitLOHDirective(D.getKind(), MCArgs); 249 MCArgs.clear(); 250 } 251 } 252 253 void AArch64AsmPrinter::EmitFunctionBodyEnd() { 254 if (!AArch64FI->getLOHRelated().empty()) 255 EmitLOHs(); 256 } 257 258 /// GetCPISymbol - Return the symbol for the specified constant pool entry. 259 MCSymbol *AArch64AsmPrinter::GetCPISymbol(unsigned CPID) const { 260 // Darwin uses a linker-private symbol name for constant-pools (to 261 // avoid addends on the relocation?), ELF has no such concept and 262 // uses a normal private symbol. 263 if (!getDataLayout().getLinkerPrivateGlobalPrefix().empty()) 264 return OutContext.getOrCreateSymbol( 265 Twine(getDataLayout().getLinkerPrivateGlobalPrefix()) + "CPI" + 266 Twine(getFunctionNumber()) + "_" + Twine(CPID)); 267 268 return OutContext.getOrCreateSymbol( 269 Twine(getDataLayout().getPrivateGlobalPrefix()) + "CPI" + 270 Twine(getFunctionNumber()) + "_" + Twine(CPID)); 271 } 272 273 void AArch64AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNum, 274 raw_ostream &O) { 275 const MachineOperand &MO = MI->getOperand(OpNum); 276 switch (MO.getType()) { 277 default: 278 llvm_unreachable("<unknown operand type>"); 279 case MachineOperand::MO_Register: { 280 unsigned Reg = MO.getReg(); 281 assert(TargetRegisterInfo::isPhysicalRegister(Reg)); 282 assert(!MO.getSubReg() && "Subregs should be eliminated!"); 283 O << AArch64InstPrinter::getRegisterName(Reg); 284 break; 285 } 286 case MachineOperand::MO_Immediate: { 287 int64_t Imm = MO.getImm(); 288 O << '#' << Imm; 289 break; 290 } 291 case MachineOperand::MO_GlobalAddress: { 292 const GlobalValue *GV = MO.getGlobal(); 293 MCSymbol *Sym = getSymbol(GV); 294 295 // FIXME: Can we get anything other than a plain symbol here? 296 assert(!MO.getTargetFlags() && "Unknown operand target flag!"); 297 298 Sym->print(O, MAI); 299 printOffset(MO.getOffset(), O); 300 break; 301 } 302 case MachineOperand::MO_BlockAddress: { 303 MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress()); 304 Sym->print(O, MAI); 305 break; 306 } 307 } 308 } 309 310 bool AArch64AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode, 311 raw_ostream &O) { 312 unsigned Reg = MO.getReg(); 313 switch (Mode) { 314 default: 315 return true; // Unknown mode. 316 case 'w': 317 Reg = getWRegFromXReg(Reg); 318 break; 319 case 'x': 320 Reg = getXRegFromWReg(Reg); 321 break; 322 } 323 324 O << AArch64InstPrinter::getRegisterName(Reg); 325 return false; 326 } 327 328 // Prints the register in MO using class RC using the offset in the 329 // new register class. This should not be used for cross class 330 // printing. 331 bool AArch64AsmPrinter::printAsmRegInClass(const MachineOperand &MO, 332 const TargetRegisterClass *RC, 333 bool isVector, raw_ostream &O) { 334 assert(MO.isReg() && "Should only get here with a register!"); 335 const TargetRegisterInfo *RI = STI->getRegisterInfo(); 336 unsigned Reg = MO.getReg(); 337 unsigned RegToPrint = RC->getRegister(RI->getEncodingValue(Reg)); 338 assert(RI->regsOverlap(RegToPrint, Reg)); 339 O << AArch64InstPrinter::getRegisterName( 340 RegToPrint, isVector ? AArch64::vreg : AArch64::NoRegAltName); 341 return false; 342 } 343 344 bool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, 345 unsigned AsmVariant, 346 const char *ExtraCode, raw_ostream &O) { 347 const MachineOperand &MO = MI->getOperand(OpNum); 348 349 // First try the generic code, which knows about modifiers like 'c' and 'n'. 350 if (!AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O)) 351 return false; 352 353 // Does this asm operand have a single letter operand modifier? 354 if (ExtraCode && ExtraCode[0]) { 355 if (ExtraCode[1] != 0) 356 return true; // Unknown modifier. 357 358 switch (ExtraCode[0]) { 359 default: 360 return true; // Unknown modifier. 361 case 'a': // Print 'a' modifier 362 PrintAsmMemoryOperand(MI, OpNum, AsmVariant, ExtraCode, O); 363 return false; 364 case 'w': // Print W register 365 case 'x': // Print X register 366 if (MO.isReg()) 367 return printAsmMRegister(MO, ExtraCode[0], O); 368 if (MO.isImm() && MO.getImm() == 0) { 369 unsigned Reg = ExtraCode[0] == 'w' ? AArch64::WZR : AArch64::XZR; 370 O << AArch64InstPrinter::getRegisterName(Reg); 371 return false; 372 } 373 printOperand(MI, OpNum, O); 374 return false; 375 case 'b': // Print B register. 376 case 'h': // Print H register. 377 case 's': // Print S register. 378 case 'd': // Print D register. 379 case 'q': // Print Q register. 380 if (MO.isReg()) { 381 const TargetRegisterClass *RC; 382 switch (ExtraCode[0]) { 383 case 'b': 384 RC = &AArch64::FPR8RegClass; 385 break; 386 case 'h': 387 RC = &AArch64::FPR16RegClass; 388 break; 389 case 's': 390 RC = &AArch64::FPR32RegClass; 391 break; 392 case 'd': 393 RC = &AArch64::FPR64RegClass; 394 break; 395 case 'q': 396 RC = &AArch64::FPR128RegClass; 397 break; 398 default: 399 return true; 400 } 401 return printAsmRegInClass(MO, RC, false /* vector */, O); 402 } 403 printOperand(MI, OpNum, O); 404 return false; 405 } 406 } 407 408 // According to ARM, we should emit x and v registers unless we have a 409 // modifier. 410 if (MO.isReg()) { 411 unsigned Reg = MO.getReg(); 412 413 // If this is a w or x register, print an x register. 414 if (AArch64::GPR32allRegClass.contains(Reg) || 415 AArch64::GPR64allRegClass.contains(Reg)) 416 return printAsmMRegister(MO, 'x', O); 417 418 // If this is a b, h, s, d, or q register, print it as a v register. 419 return printAsmRegInClass(MO, &AArch64::FPR128RegClass, true /* vector */, 420 O); 421 } 422 423 printOperand(MI, OpNum, O); 424 return false; 425 } 426 427 bool AArch64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 428 unsigned OpNum, 429 unsigned AsmVariant, 430 const char *ExtraCode, 431 raw_ostream &O) { 432 if (ExtraCode && ExtraCode[0] && ExtraCode[0] != 'a') 433 return true; // Unknown modifier. 434 435 const MachineOperand &MO = MI->getOperand(OpNum); 436 assert(MO.isReg() && "unexpected inline asm memory operand"); 437 O << "[" << AArch64InstPrinter::getRegisterName(MO.getReg()) << "]"; 438 return false; 439 } 440 441 void AArch64AsmPrinter::PrintDebugValueComment(const MachineInstr *MI, 442 raw_ostream &OS) { 443 unsigned NOps = MI->getNumOperands(); 444 assert(NOps == 4); 445 OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: "; 446 // cast away const; DIetc do not take const operands for some reason. 447 OS << cast<DILocalVariable>(MI->getOperand(NOps - 2).getMetadata()) 448 ->getName(); 449 OS << " <- "; 450 // Frame address. Currently handles register +- offset only. 451 assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm()); 452 OS << '['; 453 printOperand(MI, 0, OS); 454 OS << '+'; 455 printOperand(MI, 1, OS); 456 OS << ']'; 457 OS << "+"; 458 printOperand(MI, NOps - 2, OS); 459 } 460 461 void AArch64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM, 462 const MachineInstr &MI) { 463 unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes(); 464 465 SM.recordStackMap(MI); 466 assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!"); 467 468 // Scan ahead to trim the shadow. 469 const MachineBasicBlock &MBB = *MI.getParent(); 470 MachineBasicBlock::const_iterator MII(MI); 471 ++MII; 472 while (NumNOPBytes > 0) { 473 if (MII == MBB.end() || MII->isCall() || 474 MII->getOpcode() == AArch64::DBG_VALUE || 475 MII->getOpcode() == TargetOpcode::PATCHPOINT || 476 MII->getOpcode() == TargetOpcode::STACKMAP) 477 break; 478 ++MII; 479 NumNOPBytes -= 4; 480 } 481 482 // Emit nops. 483 for (unsigned i = 0; i < NumNOPBytes; i += 4) 484 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0)); 485 } 486 487 // Lower a patchpoint of the form: 488 // [<def>], <id>, <numBytes>, <target>, <numArgs> 489 void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM, 490 const MachineInstr &MI) { 491 SM.recordPatchPoint(MI); 492 493 PatchPointOpers Opers(&MI); 494 495 int64_t CallTarget = Opers.getCallTarget().getImm(); 496 unsigned EncodedBytes = 0; 497 if (CallTarget) { 498 assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget && 499 "High 16 bits of call target should be zero."); 500 unsigned ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg(); 501 EncodedBytes = 16; 502 // Materialize the jump address: 503 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVZXi) 504 .addReg(ScratchReg) 505 .addImm((CallTarget >> 32) & 0xFFFF) 506 .addImm(32)); 507 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi) 508 .addReg(ScratchReg) 509 .addReg(ScratchReg) 510 .addImm((CallTarget >> 16) & 0xFFFF) 511 .addImm(16)); 512 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi) 513 .addReg(ScratchReg) 514 .addReg(ScratchReg) 515 .addImm(CallTarget & 0xFFFF) 516 .addImm(0)); 517 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::BLR).addReg(ScratchReg)); 518 } 519 // Emit padding. 520 unsigned NumBytes = Opers.getNumPatchBytes(); 521 assert(NumBytes >= EncodedBytes && 522 "Patchpoint can't request size less than the length of a call."); 523 assert((NumBytes - EncodedBytes) % 4 == 0 && 524 "Invalid number of NOP bytes requested!"); 525 for (unsigned i = EncodedBytes; i < NumBytes; i += 4) 526 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0)); 527 } 528 529 void AArch64AsmPrinter::EmitFMov0(const MachineInstr &MI) { 530 unsigned DestReg = MI.getOperand(0).getReg(); 531 if (STI->hasZeroCycleZeroing() && !STI->hasZeroCycleZeroingFPWorkaround()) { 532 // Convert H/S/D register to corresponding Q register 533 if (AArch64::H0 <= DestReg && DestReg <= AArch64::H31) 534 DestReg = AArch64::Q0 + (DestReg - AArch64::H0); 535 else if (AArch64::S0 <= DestReg && DestReg <= AArch64::S31) 536 DestReg = AArch64::Q0 + (DestReg - AArch64::S0); 537 else { 538 assert(AArch64::D0 <= DestReg && DestReg <= AArch64::D31); 539 DestReg = AArch64::Q0 + (DestReg - AArch64::D0); 540 } 541 MCInst MOVI; 542 MOVI.setOpcode(AArch64::MOVIv2d_ns); 543 MOVI.addOperand(MCOperand::createReg(DestReg)); 544 MOVI.addOperand(MCOperand::createImm(0)); 545 EmitToStreamer(*OutStreamer, MOVI); 546 } else { 547 MCInst FMov; 548 switch (MI.getOpcode()) { 549 default: llvm_unreachable("Unexpected opcode"); 550 case AArch64::FMOVH0: 551 FMov.setOpcode(AArch64::FMOVWHr); 552 FMov.addOperand(MCOperand::createReg(DestReg)); 553 FMov.addOperand(MCOperand::createReg(AArch64::WZR)); 554 break; 555 case AArch64::FMOVS0: 556 FMov.setOpcode(AArch64::FMOVWSr); 557 FMov.addOperand(MCOperand::createReg(DestReg)); 558 FMov.addOperand(MCOperand::createReg(AArch64::WZR)); 559 break; 560 case AArch64::FMOVD0: 561 FMov.setOpcode(AArch64::FMOVXDr); 562 FMov.addOperand(MCOperand::createReg(DestReg)); 563 FMov.addOperand(MCOperand::createReg(AArch64::XZR)); 564 break; 565 } 566 EmitToStreamer(*OutStreamer, FMov); 567 } 568 } 569 570 // Simple pseudo-instructions have their lowering (with expansion to real 571 // instructions) auto-generated. 572 #include "AArch64GenMCPseudoLowering.inc" 573 574 void AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) { 575 // Do any auto-generated pseudo lowerings. 576 if (emitPseudoExpansionLowering(*OutStreamer, MI)) 577 return; 578 579 if (AArch64FI->getLOHRelated().count(MI)) { 580 // Generate a label for LOH related instruction 581 MCSymbol *LOHLabel = createTempSymbol("loh"); 582 // Associate the instruction with the label 583 LOHInstToLabel[MI] = LOHLabel; 584 OutStreamer->EmitLabel(LOHLabel); 585 } 586 587 // Do any manual lowerings. 588 switch (MI->getOpcode()) { 589 default: 590 break; 591 case AArch64::MOVIv2d_ns: 592 // If the target has <rdar://problem/16473581>, lower this 593 // instruction to movi.16b instead. 594 if (STI->hasZeroCycleZeroingFPWorkaround() && 595 MI->getOperand(1).getImm() == 0) { 596 MCInst TmpInst; 597 TmpInst.setOpcode(AArch64::MOVIv16b_ns); 598 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg())); 599 TmpInst.addOperand(MCOperand::createImm(MI->getOperand(1).getImm())); 600 EmitToStreamer(*OutStreamer, TmpInst); 601 return; 602 } 603 break; 604 605 case AArch64::DBG_VALUE: { 606 if (isVerbose() && OutStreamer->hasRawTextSupport()) { 607 SmallString<128> TmpStr; 608 raw_svector_ostream OS(TmpStr); 609 PrintDebugValueComment(MI, OS); 610 OutStreamer->EmitRawText(StringRef(OS.str())); 611 } 612 return; 613 } 614 615 // Tail calls use pseudo instructions so they have the proper code-gen 616 // attributes (isCall, isReturn, etc.). We lower them to the real 617 // instruction here. 618 case AArch64::TCRETURNri: { 619 MCInst TmpInst; 620 TmpInst.setOpcode(AArch64::BR); 621 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg())); 622 EmitToStreamer(*OutStreamer, TmpInst); 623 return; 624 } 625 case AArch64::TCRETURNdi: { 626 MCOperand Dest; 627 MCInstLowering.lowerOperand(MI->getOperand(0), Dest); 628 MCInst TmpInst; 629 TmpInst.setOpcode(AArch64::B); 630 TmpInst.addOperand(Dest); 631 EmitToStreamer(*OutStreamer, TmpInst); 632 return; 633 } 634 case AArch64::TLSDESC_CALLSEQ: { 635 /// lower this to: 636 /// adrp x0, :tlsdesc:var 637 /// ldr x1, [x0, #:tlsdesc_lo12:var] 638 /// add x0, x0, #:tlsdesc_lo12:var 639 /// .tlsdesccall var 640 /// blr x1 641 /// (TPIDR_EL0 offset now in x0) 642 const MachineOperand &MO_Sym = MI->getOperand(0); 643 MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym); 644 MCOperand Sym, SymTLSDescLo12, SymTLSDesc; 645 MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF); 646 MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE); 647 MCInstLowering.lowerOperand(MO_Sym, Sym); 648 MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12); 649 MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc); 650 651 MCInst Adrp; 652 Adrp.setOpcode(AArch64::ADRP); 653 Adrp.addOperand(MCOperand::createReg(AArch64::X0)); 654 Adrp.addOperand(SymTLSDesc); 655 EmitToStreamer(*OutStreamer, Adrp); 656 657 MCInst Ldr; 658 Ldr.setOpcode(AArch64::LDRXui); 659 Ldr.addOperand(MCOperand::createReg(AArch64::X1)); 660 Ldr.addOperand(MCOperand::createReg(AArch64::X0)); 661 Ldr.addOperand(SymTLSDescLo12); 662 Ldr.addOperand(MCOperand::createImm(0)); 663 EmitToStreamer(*OutStreamer, Ldr); 664 665 MCInst Add; 666 Add.setOpcode(AArch64::ADDXri); 667 Add.addOperand(MCOperand::createReg(AArch64::X0)); 668 Add.addOperand(MCOperand::createReg(AArch64::X0)); 669 Add.addOperand(SymTLSDescLo12); 670 Add.addOperand(MCOperand::createImm(AArch64_AM::getShiftValue(0))); 671 EmitToStreamer(*OutStreamer, Add); 672 673 // Emit a relocation-annotation. This expands to no code, but requests 674 // the following instruction gets an R_AARCH64_TLSDESC_CALL. 675 MCInst TLSDescCall; 676 TLSDescCall.setOpcode(AArch64::TLSDESCCALL); 677 TLSDescCall.addOperand(Sym); 678 EmitToStreamer(*OutStreamer, TLSDescCall); 679 680 MCInst Blr; 681 Blr.setOpcode(AArch64::BLR); 682 Blr.addOperand(MCOperand::createReg(AArch64::X1)); 683 EmitToStreamer(*OutStreamer, Blr); 684 685 return; 686 } 687 688 case AArch64::FMOVH0: 689 case AArch64::FMOVS0: 690 case AArch64::FMOVD0: 691 EmitFMov0(*MI); 692 return; 693 694 case TargetOpcode::STACKMAP: 695 return LowerSTACKMAP(*OutStreamer, SM, *MI); 696 697 case TargetOpcode::PATCHPOINT: 698 return LowerPATCHPOINT(*OutStreamer, SM, *MI); 699 700 case TargetOpcode::PATCHABLE_FUNCTION_ENTER: 701 LowerPATCHABLE_FUNCTION_ENTER(*MI); 702 return; 703 704 case TargetOpcode::PATCHABLE_FUNCTION_EXIT: 705 LowerPATCHABLE_FUNCTION_EXIT(*MI); 706 return; 707 708 case TargetOpcode::PATCHABLE_TAIL_CALL: 709 LowerPATCHABLE_TAIL_CALL(*MI); 710 return; 711 } 712 713 // Finally, do the automated lowerings for everything else. 714 MCInst TmpInst; 715 MCInstLowering.Lower(MI, TmpInst); 716 EmitToStreamer(*OutStreamer, TmpInst); 717 } 718 719 // Force static initialization. 720 extern "C" void LLVMInitializeAArch64AsmPrinter() { 721 RegisterAsmPrinter<AArch64AsmPrinter> X(getTheAArch64leTarget()); 722 RegisterAsmPrinter<AArch64AsmPrinter> Y(getTheAArch64beTarget()); 723 RegisterAsmPrinter<AArch64AsmPrinter> Z(getTheARM64Target()); 724 } 725