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 "MCTargetDesc/AArch64MCExpr.h"
17 #include "AArch64.h"
18 #include "AArch64MCInstLower.h"
19 #include "AArch64MachineFunctionInfo.h"
20 #include "AArch64RegisterInfo.h"
21 #include "AArch64Subtarget.h"
22 #include "InstPrinter/AArch64InstPrinter.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/Support/Debug.h"
40 #include "llvm/Support/TargetRegistry.h"
41 using namespace llvm;
42
43 #define DEBUG_TYPE "asm-printer"
44
45 namespace {
46
47 class AArch64AsmPrinter : public AsmPrinter {
48 /// Subtarget - Keep a pointer to the AArch64Subtarget around so that we can
49 /// make the right decision when printing asm code for different targets.
50 const AArch64Subtarget *Subtarget;
51
52 AArch64MCInstLower MCInstLowering;
53 StackMaps SM;
54
55 public:
AArch64AsmPrinter(TargetMachine & TM,MCStreamer & Streamer)56 AArch64AsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
57 : AsmPrinter(TM, Streamer),
58 Subtarget(&TM.getSubtarget<AArch64Subtarget>()),
59 MCInstLowering(OutContext, *this), SM(*this), AArch64FI(nullptr),
60 LOHLabelCounter(0) {}
61
getPassName() const62 const char *getPassName() const override {
63 return "AArch64 Assembly Printer";
64 }
65
66 /// \brief Wrapper for MCInstLowering.lowerOperand() for the
67 /// tblgen'erated pseudo lowering.
lowerOperand(const MachineOperand & MO,MCOperand & MCOp) const68 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
69 return MCInstLowering.lowerOperand(MO, MCOp);
70 }
71
72 void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
73 const MachineInstr &MI);
74 void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
75 const MachineInstr &MI);
76 /// \brief tblgen'erated driver function for lowering simple MI->MC
77 /// pseudo instructions.
78 bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
79 const MachineInstr *MI);
80
81 void EmitInstruction(const MachineInstr *MI) override;
82
getAnalysisUsage(AnalysisUsage & AU) const83 void getAnalysisUsage(AnalysisUsage &AU) const override {
84 AsmPrinter::getAnalysisUsage(AU);
85 AU.setPreservesAll();
86 }
87
runOnMachineFunction(MachineFunction & F)88 bool runOnMachineFunction(MachineFunction &F) override {
89 AArch64FI = F.getInfo<AArch64FunctionInfo>();
90 return AsmPrinter::runOnMachineFunction(F);
91 }
92
93 private:
94 MachineLocation getDebugValueLocation(const MachineInstr *MI) const;
95 void printOperand(const MachineInstr *MI, unsigned OpNum, raw_ostream &O);
96 bool printAsmMRegister(const MachineOperand &MO, char Mode, raw_ostream &O);
97 bool printAsmRegInClass(const MachineOperand &MO,
98 const TargetRegisterClass *RC, bool isVector,
99 raw_ostream &O);
100
101 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
102 unsigned AsmVariant, const char *ExtraCode,
103 raw_ostream &O) override;
104 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
105 unsigned AsmVariant, const char *ExtraCode,
106 raw_ostream &O) override;
107
108 void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
109
110 void EmitFunctionBodyEnd() override;
111
112 MCSymbol *GetCPISymbol(unsigned CPID) const override;
113 void EmitEndOfAsmFile(Module &M) override;
114 AArch64FunctionInfo *AArch64FI;
115
116 /// \brief Emit the LOHs contained in AArch64FI.
117 void EmitLOHs();
118
119 typedef std::map<const MachineInstr *, MCSymbol *> MInstToMCSymbol;
120 MInstToMCSymbol LOHInstToLabel;
121 unsigned LOHLabelCounter;
122 };
123
124 } // end of anonymous namespace
125
126 //===----------------------------------------------------------------------===//
127
EmitEndOfAsmFile(Module & M)128 void AArch64AsmPrinter::EmitEndOfAsmFile(Module &M) {
129 if (Subtarget->isTargetMachO()) {
130 // Funny Darwin hack: This flag tells the linker that no global symbols
131 // contain code that falls through to other global symbols (e.g. the obvious
132 // implementation of multiple entry points). If this doesn't occur, the
133 // linker can safely perform dead code stripping. Since LLVM never
134 // generates code that does this, it is always safe to set.
135 OutStreamer.EmitAssemblerFlag(MCAF_SubsectionsViaSymbols);
136 SM.serializeToStackMapSection();
137 }
138
139 // Emit a .data.rel section containing any stubs that were created.
140 if (Subtarget->isTargetELF()) {
141 const TargetLoweringObjectFileELF &TLOFELF =
142 static_cast<const TargetLoweringObjectFileELF &>(getObjFileLowering());
143
144 MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>();
145
146 // Output stubs for external and common global variables.
147 MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList();
148 if (!Stubs.empty()) {
149 OutStreamer.SwitchSection(TLOFELF.getDataRelSection());
150 const DataLayout *TD = TM.getSubtargetImpl()->getDataLayout();
151
152 for (unsigned i = 0, e = Stubs.size(); i != e; ++i) {
153 OutStreamer.EmitLabel(Stubs[i].first);
154 OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(),
155 TD->getPointerSize(0));
156 }
157 Stubs.clear();
158 }
159 }
160
161 }
162
163 MachineLocation
getDebugValueLocation(const MachineInstr * MI) const164 AArch64AsmPrinter::getDebugValueLocation(const MachineInstr *MI) const {
165 MachineLocation Location;
166 assert(MI->getNumOperands() == 4 && "Invalid no. of machine operands!");
167 // Frame address. Currently handles register +- offset only.
168 if (MI->getOperand(0).isReg() && MI->getOperand(1).isImm())
169 Location.set(MI->getOperand(0).getReg(), MI->getOperand(1).getImm());
170 else {
171 DEBUG(dbgs() << "DBG_VALUE instruction ignored! " << *MI << "\n");
172 }
173 return Location;
174 }
175
EmitLOHs()176 void AArch64AsmPrinter::EmitLOHs() {
177 SmallVector<MCSymbol *, 3> MCArgs;
178
179 for (const auto &D : AArch64FI->getLOHContainer()) {
180 for (const MachineInstr *MI : D.getArgs()) {
181 MInstToMCSymbol::iterator LabelIt = LOHInstToLabel.find(MI);
182 assert(LabelIt != LOHInstToLabel.end() &&
183 "Label hasn't been inserted for LOH related instruction");
184 MCArgs.push_back(LabelIt->second);
185 }
186 OutStreamer.EmitLOHDirective(D.getKind(), MCArgs);
187 MCArgs.clear();
188 }
189 }
190
EmitFunctionBodyEnd()191 void AArch64AsmPrinter::EmitFunctionBodyEnd() {
192 if (!AArch64FI->getLOHRelated().empty())
193 EmitLOHs();
194 }
195
196 /// GetCPISymbol - Return the symbol for the specified constant pool entry.
GetCPISymbol(unsigned CPID) const197 MCSymbol *AArch64AsmPrinter::GetCPISymbol(unsigned CPID) const {
198 // Darwin uses a linker-private symbol name for constant-pools (to
199 // avoid addends on the relocation?), ELF has no such concept and
200 // uses a normal private symbol.
201 if (getDataLayout().getLinkerPrivateGlobalPrefix()[0])
202 return OutContext.GetOrCreateSymbol(
203 Twine(getDataLayout().getLinkerPrivateGlobalPrefix()) + "CPI" +
204 Twine(getFunctionNumber()) + "_" + Twine(CPID));
205
206 return OutContext.GetOrCreateSymbol(
207 Twine(getDataLayout().getPrivateGlobalPrefix()) + "CPI" +
208 Twine(getFunctionNumber()) + "_" + Twine(CPID));
209 }
210
printOperand(const MachineInstr * MI,unsigned OpNum,raw_ostream & O)211 void AArch64AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNum,
212 raw_ostream &O) {
213 const MachineOperand &MO = MI->getOperand(OpNum);
214 switch (MO.getType()) {
215 default:
216 llvm_unreachable("<unknown operand type>");
217 case MachineOperand::MO_Register: {
218 unsigned Reg = MO.getReg();
219 assert(TargetRegisterInfo::isPhysicalRegister(Reg));
220 assert(!MO.getSubReg() && "Subregs should be eliminated!");
221 O << AArch64InstPrinter::getRegisterName(Reg);
222 break;
223 }
224 case MachineOperand::MO_Immediate: {
225 int64_t Imm = MO.getImm();
226 O << '#' << Imm;
227 break;
228 }
229 }
230 }
231
printAsmMRegister(const MachineOperand & MO,char Mode,raw_ostream & O)232 bool AArch64AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode,
233 raw_ostream &O) {
234 unsigned Reg = MO.getReg();
235 switch (Mode) {
236 default:
237 return true; // Unknown mode.
238 case 'w':
239 Reg = getWRegFromXReg(Reg);
240 break;
241 case 'x':
242 Reg = getXRegFromWReg(Reg);
243 break;
244 }
245
246 O << AArch64InstPrinter::getRegisterName(Reg);
247 return false;
248 }
249
250 // Prints the register in MO using class RC using the offset in the
251 // new register class. This should not be used for cross class
252 // printing.
printAsmRegInClass(const MachineOperand & MO,const TargetRegisterClass * RC,bool isVector,raw_ostream & O)253 bool AArch64AsmPrinter::printAsmRegInClass(const MachineOperand &MO,
254 const TargetRegisterClass *RC,
255 bool isVector, raw_ostream &O) {
256 assert(MO.isReg() && "Should only get here with a register!");
257 const AArch64RegisterInfo *RI = static_cast<const AArch64RegisterInfo *>(
258 TM.getSubtargetImpl()->getRegisterInfo());
259 unsigned Reg = MO.getReg();
260 unsigned RegToPrint = RC->getRegister(RI->getEncodingValue(Reg));
261 assert(RI->regsOverlap(RegToPrint, Reg));
262 O << AArch64InstPrinter::getRegisterName(
263 RegToPrint, isVector ? AArch64::vreg : AArch64::NoRegAltName);
264 return false;
265 }
266
PrintAsmOperand(const MachineInstr * MI,unsigned OpNum,unsigned AsmVariant,const char * ExtraCode,raw_ostream & O)267 bool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
268 unsigned AsmVariant,
269 const char *ExtraCode, raw_ostream &O) {
270 const MachineOperand &MO = MI->getOperand(OpNum);
271
272 // First try the generic code, which knows about modifiers like 'c' and 'n'.
273 if (!AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O))
274 return false;
275
276 // Does this asm operand have a single letter operand modifier?
277 if (ExtraCode && ExtraCode[0]) {
278 if (ExtraCode[1] != 0)
279 return true; // Unknown modifier.
280
281 switch (ExtraCode[0]) {
282 default:
283 return true; // Unknown modifier.
284 case 'w': // Print W register
285 case 'x': // Print X register
286 if (MO.isReg())
287 return printAsmMRegister(MO, ExtraCode[0], O);
288 if (MO.isImm() && MO.getImm() == 0) {
289 unsigned Reg = ExtraCode[0] == 'w' ? AArch64::WZR : AArch64::XZR;
290 O << AArch64InstPrinter::getRegisterName(Reg);
291 return false;
292 }
293 printOperand(MI, OpNum, O);
294 return false;
295 case 'b': // Print B register.
296 case 'h': // Print H register.
297 case 's': // Print S register.
298 case 'd': // Print D register.
299 case 'q': // Print Q register.
300 if (MO.isReg()) {
301 const TargetRegisterClass *RC;
302 switch (ExtraCode[0]) {
303 case 'b':
304 RC = &AArch64::FPR8RegClass;
305 break;
306 case 'h':
307 RC = &AArch64::FPR16RegClass;
308 break;
309 case 's':
310 RC = &AArch64::FPR32RegClass;
311 break;
312 case 'd':
313 RC = &AArch64::FPR64RegClass;
314 break;
315 case 'q':
316 RC = &AArch64::FPR128RegClass;
317 break;
318 default:
319 return true;
320 }
321 return printAsmRegInClass(MO, RC, false /* vector */, O);
322 }
323 printOperand(MI, OpNum, O);
324 return false;
325 }
326 }
327
328 // According to ARM, we should emit x and v registers unless we have a
329 // modifier.
330 if (MO.isReg()) {
331 unsigned Reg = MO.getReg();
332
333 // If this is a w or x register, print an x register.
334 if (AArch64::GPR32allRegClass.contains(Reg) ||
335 AArch64::GPR64allRegClass.contains(Reg))
336 return printAsmMRegister(MO, 'x', O);
337
338 // If this is a b, h, s, d, or q register, print it as a v register.
339 return printAsmRegInClass(MO, &AArch64::FPR128RegClass, true /* vector */,
340 O);
341 }
342
343 printOperand(MI, OpNum, O);
344 return false;
345 }
346
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNum,unsigned AsmVariant,const char * ExtraCode,raw_ostream & O)347 bool AArch64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
348 unsigned OpNum,
349 unsigned AsmVariant,
350 const char *ExtraCode,
351 raw_ostream &O) {
352 if (ExtraCode && ExtraCode[0])
353 return true; // Unknown modifier.
354
355 const MachineOperand &MO = MI->getOperand(OpNum);
356 assert(MO.isReg() && "unexpected inline asm memory operand");
357 O << "[" << AArch64InstPrinter::getRegisterName(MO.getReg()) << "]";
358 return false;
359 }
360
PrintDebugValueComment(const MachineInstr * MI,raw_ostream & OS)361 void AArch64AsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
362 raw_ostream &OS) {
363 unsigned NOps = MI->getNumOperands();
364 assert(NOps == 4);
365 OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: ";
366 // cast away const; DIetc do not take const operands for some reason.
367 DIVariable V(const_cast<MDNode *>(MI->getOperand(NOps - 1).getMetadata()));
368 OS << V.getName();
369 OS << " <- ";
370 // Frame address. Currently handles register +- offset only.
371 assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm());
372 OS << '[';
373 printOperand(MI, 0, OS);
374 OS << '+';
375 printOperand(MI, 1, OS);
376 OS << ']';
377 OS << "+";
378 printOperand(MI, NOps - 2, OS);
379 }
380
LowerSTACKMAP(MCStreamer & OutStreamer,StackMaps & SM,const MachineInstr & MI)381 void AArch64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
382 const MachineInstr &MI) {
383 unsigned NumNOPBytes = MI.getOperand(1).getImm();
384
385 SM.recordStackMap(MI);
386 assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
387
388 // Scan ahead to trim the shadow.
389 const MachineBasicBlock &MBB = *MI.getParent();
390 MachineBasicBlock::const_iterator MII(MI);
391 ++MII;
392 while (NumNOPBytes > 0) {
393 if (MII == MBB.end() || MII->isCall() ||
394 MII->getOpcode() == AArch64::DBG_VALUE ||
395 MII->getOpcode() == TargetOpcode::PATCHPOINT ||
396 MII->getOpcode() == TargetOpcode::STACKMAP)
397 break;
398 ++MII;
399 NumNOPBytes -= 4;
400 }
401
402 // Emit nops.
403 for (unsigned i = 0; i < NumNOPBytes; i += 4)
404 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
405 }
406
407 // Lower a patchpoint of the form:
408 // [<def>], <id>, <numBytes>, <target>, <numArgs>
LowerPATCHPOINT(MCStreamer & OutStreamer,StackMaps & SM,const MachineInstr & MI)409 void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
410 const MachineInstr &MI) {
411 SM.recordPatchPoint(MI);
412
413 PatchPointOpers Opers(&MI);
414
415 int64_t CallTarget = Opers.getMetaOper(PatchPointOpers::TargetPos).getImm();
416 unsigned EncodedBytes = 0;
417 if (CallTarget) {
418 assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget &&
419 "High 16 bits of call target should be zero.");
420 unsigned ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg();
421 EncodedBytes = 16;
422 // Materialize the jump address:
423 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVZWi)
424 .addReg(ScratchReg)
425 .addImm((CallTarget >> 32) & 0xFFFF)
426 .addImm(32));
427 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKWi)
428 .addReg(ScratchReg)
429 .addReg(ScratchReg)
430 .addImm((CallTarget >> 16) & 0xFFFF)
431 .addImm(16));
432 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKWi)
433 .addReg(ScratchReg)
434 .addReg(ScratchReg)
435 .addImm(CallTarget & 0xFFFF)
436 .addImm(0));
437 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::BLR).addReg(ScratchReg));
438 }
439 // Emit padding.
440 unsigned NumBytes = Opers.getMetaOper(PatchPointOpers::NBytesPos).getImm();
441 assert(NumBytes >= EncodedBytes &&
442 "Patchpoint can't request size less than the length of a call.");
443 assert((NumBytes - EncodedBytes) % 4 == 0 &&
444 "Invalid number of NOP bytes requested!");
445 for (unsigned i = EncodedBytes; i < NumBytes; i += 4)
446 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
447 }
448
449 // Simple pseudo-instructions have their lowering (with expansion to real
450 // instructions) auto-generated.
451 #include "AArch64GenMCPseudoLowering.inc"
452
EmitInstruction(const MachineInstr * MI)453 void AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
454 // Do any auto-generated pseudo lowerings.
455 if (emitPseudoExpansionLowering(OutStreamer, MI))
456 return;
457
458 if (AArch64FI->getLOHRelated().count(MI)) {
459 // Generate a label for LOH related instruction
460 MCSymbol *LOHLabel = GetTempSymbol("loh", LOHLabelCounter++);
461 // Associate the instruction with the label
462 LOHInstToLabel[MI] = LOHLabel;
463 OutStreamer.EmitLabel(LOHLabel);
464 }
465
466 // Do any manual lowerings.
467 switch (MI->getOpcode()) {
468 default:
469 break;
470 case AArch64::DBG_VALUE: {
471 if (isVerbose() && OutStreamer.hasRawTextSupport()) {
472 SmallString<128> TmpStr;
473 raw_svector_ostream OS(TmpStr);
474 PrintDebugValueComment(MI, OS);
475 OutStreamer.EmitRawText(StringRef(OS.str()));
476 }
477 return;
478 }
479
480 // Tail calls use pseudo instructions so they have the proper code-gen
481 // attributes (isCall, isReturn, etc.). We lower them to the real
482 // instruction here.
483 case AArch64::TCRETURNri: {
484 MCInst TmpInst;
485 TmpInst.setOpcode(AArch64::BR);
486 TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg()));
487 EmitToStreamer(OutStreamer, TmpInst);
488 return;
489 }
490 case AArch64::TCRETURNdi: {
491 MCOperand Dest;
492 MCInstLowering.lowerOperand(MI->getOperand(0), Dest);
493 MCInst TmpInst;
494 TmpInst.setOpcode(AArch64::B);
495 TmpInst.addOperand(Dest);
496 EmitToStreamer(OutStreamer, TmpInst);
497 return;
498 }
499 case AArch64::TLSDESC_CALLSEQ: {
500 /// lower this to:
501 /// adrp x0, :tlsdesc:var
502 /// ldr x1, [x0, #:tlsdesc_lo12:var]
503 /// add x0, x0, #:tlsdesc_lo12:var
504 /// .tlsdesccall var
505 /// blr x1
506 /// (TPIDR_EL0 offset now in x0)
507 const MachineOperand &MO_Sym = MI->getOperand(0);
508 MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym);
509 MCOperand Sym, SymTLSDescLo12, SymTLSDesc;
510 MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF |
511 AArch64II::MO_NC);
512 MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE);
513 MCInstLowering.lowerOperand(MO_Sym, Sym);
514 MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12);
515 MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc);
516
517 MCInst Adrp;
518 Adrp.setOpcode(AArch64::ADRP);
519 Adrp.addOperand(MCOperand::CreateReg(AArch64::X0));
520 Adrp.addOperand(SymTLSDesc);
521 EmitToStreamer(OutStreamer, Adrp);
522
523 MCInst Ldr;
524 Ldr.setOpcode(AArch64::LDRXui);
525 Ldr.addOperand(MCOperand::CreateReg(AArch64::X1));
526 Ldr.addOperand(MCOperand::CreateReg(AArch64::X0));
527 Ldr.addOperand(SymTLSDescLo12);
528 Ldr.addOperand(MCOperand::CreateImm(0));
529 EmitToStreamer(OutStreamer, Ldr);
530
531 MCInst Add;
532 Add.setOpcode(AArch64::ADDXri);
533 Add.addOperand(MCOperand::CreateReg(AArch64::X0));
534 Add.addOperand(MCOperand::CreateReg(AArch64::X0));
535 Add.addOperand(SymTLSDescLo12);
536 Add.addOperand(MCOperand::CreateImm(AArch64_AM::getShiftValue(0)));
537 EmitToStreamer(OutStreamer, Add);
538
539 // Emit a relocation-annotation. This expands to no code, but requests
540 // the following instruction gets an R_AARCH64_TLSDESC_CALL.
541 MCInst TLSDescCall;
542 TLSDescCall.setOpcode(AArch64::TLSDESCCALL);
543 TLSDescCall.addOperand(Sym);
544 EmitToStreamer(OutStreamer, TLSDescCall);
545
546 MCInst Blr;
547 Blr.setOpcode(AArch64::BLR);
548 Blr.addOperand(MCOperand::CreateReg(AArch64::X1));
549 EmitToStreamer(OutStreamer, Blr);
550
551 return;
552 }
553
554 case TargetOpcode::STACKMAP:
555 return LowerSTACKMAP(OutStreamer, SM, *MI);
556
557 case TargetOpcode::PATCHPOINT:
558 return LowerPATCHPOINT(OutStreamer, SM, *MI);
559 }
560
561 // Finally, do the automated lowerings for everything else.
562 MCInst TmpInst;
563 MCInstLowering.Lower(MI, TmpInst);
564 EmitToStreamer(OutStreamer, TmpInst);
565 }
566
567 // Force static initialization.
LLVMInitializeAArch64AsmPrinter()568 extern "C" void LLVMInitializeAArch64AsmPrinter() {
569 RegisterAsmPrinter<AArch64AsmPrinter> X(TheAArch64leTarget);
570 RegisterAsmPrinter<AArch64AsmPrinter> Y(TheAArch64beTarget);
571 RegisterAsmPrinter<AArch64AsmPrinter> Z(TheARM64Target);
572 }
573