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