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/IR/DataLayout.h" 37 #include "llvm/IR/DebugInfoMetadata.h" 38 #include "llvm/MC/MCAsmInfo.h" 39 #include "llvm/MC/MCContext.h" 40 #include "llvm/MC/MCInst.h" 41 #include "llvm/MC/MCInstBuilder.h" 42 #include "llvm/MC/MCStreamer.h" 43 #include "llvm/MC/MCSymbol.h" 44 #include "llvm/Support/Casting.h" 45 #include "llvm/Support/ErrorHandling.h" 46 #include "llvm/Support/TargetRegistry.h" 47 #include "llvm/Support/raw_ostream.h" 48 #include "llvm/Target/TargetMachine.h" 49 #include "llvm/Target/TargetRegisterInfo.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 } 303 } 304 305 bool AArch64AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode, 306 raw_ostream &O) { 307 unsigned Reg = MO.getReg(); 308 switch (Mode) { 309 default: 310 return true; // Unknown mode. 311 case 'w': 312 Reg = getWRegFromXReg(Reg); 313 break; 314 case 'x': 315 Reg = getXRegFromWReg(Reg); 316 break; 317 } 318 319 O << AArch64InstPrinter::getRegisterName(Reg); 320 return false; 321 } 322 323 // Prints the register in MO using class RC using the offset in the 324 // new register class. This should not be used for cross class 325 // printing. 326 bool AArch64AsmPrinter::printAsmRegInClass(const MachineOperand &MO, 327 const TargetRegisterClass *RC, 328 bool isVector, raw_ostream &O) { 329 assert(MO.isReg() && "Should only get here with a register!"); 330 const TargetRegisterInfo *RI = STI->getRegisterInfo(); 331 unsigned Reg = MO.getReg(); 332 unsigned RegToPrint = RC->getRegister(RI->getEncodingValue(Reg)); 333 assert(RI->regsOverlap(RegToPrint, Reg)); 334 O << AArch64InstPrinter::getRegisterName( 335 RegToPrint, isVector ? AArch64::vreg : AArch64::NoRegAltName); 336 return false; 337 } 338 339 bool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, 340 unsigned AsmVariant, 341 const char *ExtraCode, raw_ostream &O) { 342 const MachineOperand &MO = MI->getOperand(OpNum); 343 344 // First try the generic code, which knows about modifiers like 'c' and 'n'. 345 if (!AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O)) 346 return false; 347 348 // Does this asm operand have a single letter operand modifier? 349 if (ExtraCode && ExtraCode[0]) { 350 if (ExtraCode[1] != 0) 351 return true; // Unknown modifier. 352 353 switch (ExtraCode[0]) { 354 default: 355 return true; // Unknown modifier. 356 case 'a': // Print 'a' modifier 357 PrintAsmMemoryOperand(MI, OpNum, AsmVariant, ExtraCode, O); 358 return false; 359 case 'w': // Print W register 360 case 'x': // Print X register 361 if (MO.isReg()) 362 return printAsmMRegister(MO, ExtraCode[0], O); 363 if (MO.isImm() && MO.getImm() == 0) { 364 unsigned Reg = ExtraCode[0] == 'w' ? AArch64::WZR : AArch64::XZR; 365 O << AArch64InstPrinter::getRegisterName(Reg); 366 return false; 367 } 368 printOperand(MI, OpNum, O); 369 return false; 370 case 'b': // Print B register. 371 case 'h': // Print H register. 372 case 's': // Print S register. 373 case 'd': // Print D register. 374 case 'q': // Print Q register. 375 if (MO.isReg()) { 376 const TargetRegisterClass *RC; 377 switch (ExtraCode[0]) { 378 case 'b': 379 RC = &AArch64::FPR8RegClass; 380 break; 381 case 'h': 382 RC = &AArch64::FPR16RegClass; 383 break; 384 case 's': 385 RC = &AArch64::FPR32RegClass; 386 break; 387 case 'd': 388 RC = &AArch64::FPR64RegClass; 389 break; 390 case 'q': 391 RC = &AArch64::FPR128RegClass; 392 break; 393 default: 394 return true; 395 } 396 return printAsmRegInClass(MO, RC, false /* vector */, O); 397 } 398 printOperand(MI, OpNum, O); 399 return false; 400 } 401 } 402 403 // According to ARM, we should emit x and v registers unless we have a 404 // modifier. 405 if (MO.isReg()) { 406 unsigned Reg = MO.getReg(); 407 408 // If this is a w or x register, print an x register. 409 if (AArch64::GPR32allRegClass.contains(Reg) || 410 AArch64::GPR64allRegClass.contains(Reg)) 411 return printAsmMRegister(MO, 'x', O); 412 413 // If this is a b, h, s, d, or q register, print it as a v register. 414 return printAsmRegInClass(MO, &AArch64::FPR128RegClass, true /* vector */, 415 O); 416 } 417 418 printOperand(MI, OpNum, O); 419 return false; 420 } 421 422 bool AArch64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 423 unsigned OpNum, 424 unsigned AsmVariant, 425 const char *ExtraCode, 426 raw_ostream &O) { 427 if (ExtraCode && ExtraCode[0] && ExtraCode[0] != 'a') 428 return true; // Unknown modifier. 429 430 const MachineOperand &MO = MI->getOperand(OpNum); 431 assert(MO.isReg() && "unexpected inline asm memory operand"); 432 O << "[" << AArch64InstPrinter::getRegisterName(MO.getReg()) << "]"; 433 return false; 434 } 435 436 void AArch64AsmPrinter::PrintDebugValueComment(const MachineInstr *MI, 437 raw_ostream &OS) { 438 unsigned NOps = MI->getNumOperands(); 439 assert(NOps == 4); 440 OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: "; 441 // cast away const; DIetc do not take const operands for some reason. 442 OS << cast<DILocalVariable>(MI->getOperand(NOps - 2).getMetadata()) 443 ->getName(); 444 OS << " <- "; 445 // Frame address. Currently handles register +- offset only. 446 assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm()); 447 OS << '['; 448 printOperand(MI, 0, OS); 449 OS << '+'; 450 printOperand(MI, 1, OS); 451 OS << ']'; 452 OS << "+"; 453 printOperand(MI, NOps - 2, OS); 454 } 455 456 void AArch64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM, 457 const MachineInstr &MI) { 458 unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes(); 459 460 SM.recordStackMap(MI); 461 assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!"); 462 463 // Scan ahead to trim the shadow. 464 const MachineBasicBlock &MBB = *MI.getParent(); 465 MachineBasicBlock::const_iterator MII(MI); 466 ++MII; 467 while (NumNOPBytes > 0) { 468 if (MII == MBB.end() || MII->isCall() || 469 MII->getOpcode() == AArch64::DBG_VALUE || 470 MII->getOpcode() == TargetOpcode::PATCHPOINT || 471 MII->getOpcode() == TargetOpcode::STACKMAP) 472 break; 473 ++MII; 474 NumNOPBytes -= 4; 475 } 476 477 // Emit nops. 478 for (unsigned i = 0; i < NumNOPBytes; i += 4) 479 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0)); 480 } 481 482 // Lower a patchpoint of the form: 483 // [<def>], <id>, <numBytes>, <target>, <numArgs> 484 void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM, 485 const MachineInstr &MI) { 486 SM.recordPatchPoint(MI); 487 488 PatchPointOpers Opers(&MI); 489 490 int64_t CallTarget = Opers.getCallTarget().getImm(); 491 unsigned EncodedBytes = 0; 492 if (CallTarget) { 493 assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget && 494 "High 16 bits of call target should be zero."); 495 unsigned ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg(); 496 EncodedBytes = 16; 497 // Materialize the jump address: 498 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVZXi) 499 .addReg(ScratchReg) 500 .addImm((CallTarget >> 32) & 0xFFFF) 501 .addImm(32)); 502 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi) 503 .addReg(ScratchReg) 504 .addReg(ScratchReg) 505 .addImm((CallTarget >> 16) & 0xFFFF) 506 .addImm(16)); 507 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi) 508 .addReg(ScratchReg) 509 .addReg(ScratchReg) 510 .addImm(CallTarget & 0xFFFF) 511 .addImm(0)); 512 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::BLR).addReg(ScratchReg)); 513 } 514 // Emit padding. 515 unsigned NumBytes = Opers.getNumPatchBytes(); 516 assert(NumBytes >= EncodedBytes && 517 "Patchpoint can't request size less than the length of a call."); 518 assert((NumBytes - EncodedBytes) % 4 == 0 && 519 "Invalid number of NOP bytes requested!"); 520 for (unsigned i = EncodedBytes; i < NumBytes; i += 4) 521 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0)); 522 } 523 524 void AArch64AsmPrinter::EmitFMov0(const MachineInstr &MI) { 525 unsigned DestReg = MI.getOperand(0).getReg(); 526 if (STI->hasZeroCycleZeroing()) { 527 // Convert H/S/D register to corresponding Q register 528 if (AArch64::H0 <= DestReg && DestReg <= AArch64::H31) 529 DestReg = AArch64::Q0 + (DestReg - AArch64::H0); 530 else if (AArch64::S0 <= DestReg && DestReg <= AArch64::S31) 531 DestReg = AArch64::Q0 + (DestReg - AArch64::S0); 532 else { 533 assert(AArch64::D0 <= DestReg && DestReg <= AArch64::D31); 534 DestReg = AArch64::Q0 + (DestReg - AArch64::D0); 535 } 536 MCInst MOVI; 537 MOVI.setOpcode(AArch64::MOVIv2d_ns); 538 MOVI.addOperand(MCOperand::createReg(DestReg)); 539 MOVI.addOperand(MCOperand::createImm(0)); 540 EmitToStreamer(*OutStreamer, MOVI); 541 } else { 542 MCInst FMov; 543 switch (MI.getOpcode()) { 544 default: llvm_unreachable("Unexpected opcode"); 545 case AArch64::FMOVH0: 546 FMov.setOpcode(AArch64::FMOVWHr); 547 FMov.addOperand(MCOperand::createReg(DestReg)); 548 FMov.addOperand(MCOperand::createReg(AArch64::WZR)); 549 break; 550 case AArch64::FMOVS0: 551 FMov.setOpcode(AArch64::FMOVWSr); 552 FMov.addOperand(MCOperand::createReg(DestReg)); 553 FMov.addOperand(MCOperand::createReg(AArch64::WZR)); 554 break; 555 case AArch64::FMOVD0: 556 FMov.setOpcode(AArch64::FMOVXDr); 557 FMov.addOperand(MCOperand::createReg(DestReg)); 558 FMov.addOperand(MCOperand::createReg(AArch64::XZR)); 559 break; 560 } 561 EmitToStreamer(*OutStreamer, FMov); 562 } 563 } 564 565 // Simple pseudo-instructions have their lowering (with expansion to real 566 // instructions) auto-generated. 567 #include "AArch64GenMCPseudoLowering.inc" 568 569 void AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) { 570 // Do any auto-generated pseudo lowerings. 571 if (emitPseudoExpansionLowering(*OutStreamer, MI)) 572 return; 573 574 if (AArch64FI->getLOHRelated().count(MI)) { 575 // Generate a label for LOH related instruction 576 MCSymbol *LOHLabel = createTempSymbol("loh"); 577 // Associate the instruction with the label 578 LOHInstToLabel[MI] = LOHLabel; 579 OutStreamer->EmitLabel(LOHLabel); 580 } 581 582 // Do any manual lowerings. 583 switch (MI->getOpcode()) { 584 default: 585 break; 586 case AArch64::DBG_VALUE: { 587 if (isVerbose() && OutStreamer->hasRawTextSupport()) { 588 SmallString<128> TmpStr; 589 raw_svector_ostream OS(TmpStr); 590 PrintDebugValueComment(MI, OS); 591 OutStreamer->EmitRawText(StringRef(OS.str())); 592 } 593 return; 594 } 595 596 // Tail calls use pseudo instructions so they have the proper code-gen 597 // attributes (isCall, isReturn, etc.). We lower them to the real 598 // instruction here. 599 case AArch64::TCRETURNri: { 600 MCInst TmpInst; 601 TmpInst.setOpcode(AArch64::BR); 602 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg())); 603 EmitToStreamer(*OutStreamer, TmpInst); 604 return; 605 } 606 case AArch64::TCRETURNdi: { 607 MCOperand Dest; 608 MCInstLowering.lowerOperand(MI->getOperand(0), Dest); 609 MCInst TmpInst; 610 TmpInst.setOpcode(AArch64::B); 611 TmpInst.addOperand(Dest); 612 EmitToStreamer(*OutStreamer, TmpInst); 613 return; 614 } 615 case AArch64::TLSDESC_CALLSEQ: { 616 /// lower this to: 617 /// adrp x0, :tlsdesc:var 618 /// ldr x1, [x0, #:tlsdesc_lo12:var] 619 /// add x0, x0, #:tlsdesc_lo12:var 620 /// .tlsdesccall var 621 /// blr x1 622 /// (TPIDR_EL0 offset now in x0) 623 const MachineOperand &MO_Sym = MI->getOperand(0); 624 MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym); 625 MCOperand Sym, SymTLSDescLo12, SymTLSDesc; 626 MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF); 627 MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE); 628 MCInstLowering.lowerOperand(MO_Sym, Sym); 629 MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12); 630 MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc); 631 632 MCInst Adrp; 633 Adrp.setOpcode(AArch64::ADRP); 634 Adrp.addOperand(MCOperand::createReg(AArch64::X0)); 635 Adrp.addOperand(SymTLSDesc); 636 EmitToStreamer(*OutStreamer, Adrp); 637 638 MCInst Ldr; 639 Ldr.setOpcode(AArch64::LDRXui); 640 Ldr.addOperand(MCOperand::createReg(AArch64::X1)); 641 Ldr.addOperand(MCOperand::createReg(AArch64::X0)); 642 Ldr.addOperand(SymTLSDescLo12); 643 Ldr.addOperand(MCOperand::createImm(0)); 644 EmitToStreamer(*OutStreamer, Ldr); 645 646 MCInst Add; 647 Add.setOpcode(AArch64::ADDXri); 648 Add.addOperand(MCOperand::createReg(AArch64::X0)); 649 Add.addOperand(MCOperand::createReg(AArch64::X0)); 650 Add.addOperand(SymTLSDescLo12); 651 Add.addOperand(MCOperand::createImm(AArch64_AM::getShiftValue(0))); 652 EmitToStreamer(*OutStreamer, Add); 653 654 // Emit a relocation-annotation. This expands to no code, but requests 655 // the following instruction gets an R_AARCH64_TLSDESC_CALL. 656 MCInst TLSDescCall; 657 TLSDescCall.setOpcode(AArch64::TLSDESCCALL); 658 TLSDescCall.addOperand(Sym); 659 EmitToStreamer(*OutStreamer, TLSDescCall); 660 661 MCInst Blr; 662 Blr.setOpcode(AArch64::BLR); 663 Blr.addOperand(MCOperand::createReg(AArch64::X1)); 664 EmitToStreamer(*OutStreamer, Blr); 665 666 return; 667 } 668 669 case AArch64::FMOVH0: 670 case AArch64::FMOVS0: 671 case AArch64::FMOVD0: 672 EmitFMov0(*MI); 673 return; 674 675 case TargetOpcode::STACKMAP: 676 return LowerSTACKMAP(*OutStreamer, SM, *MI); 677 678 case TargetOpcode::PATCHPOINT: 679 return LowerPATCHPOINT(*OutStreamer, SM, *MI); 680 681 case TargetOpcode::PATCHABLE_FUNCTION_ENTER: 682 LowerPATCHABLE_FUNCTION_ENTER(*MI); 683 return; 684 685 case TargetOpcode::PATCHABLE_FUNCTION_EXIT: 686 LowerPATCHABLE_FUNCTION_EXIT(*MI); 687 return; 688 689 case TargetOpcode::PATCHABLE_TAIL_CALL: 690 LowerPATCHABLE_TAIL_CALL(*MI); 691 return; 692 } 693 694 // Finally, do the automated lowerings for everything else. 695 MCInst TmpInst; 696 MCInstLowering.Lower(MI, TmpInst); 697 EmitToStreamer(*OutStreamer, TmpInst); 698 } 699 700 // Force static initialization. 701 extern "C" void LLVMInitializeAArch64AsmPrinter() { 702 RegisterAsmPrinter<AArch64AsmPrinter> X(getTheAArch64leTarget()); 703 RegisterAsmPrinter<AArch64AsmPrinter> Y(getTheAArch64beTarget()); 704 RegisterAsmPrinter<AArch64AsmPrinter> Z(getTheARM64Target()); 705 } 706