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