blob: e18458fc31e6066b5a42e77467ab378529f70be2 [file] [log] [blame]
Eugene Zelenko96d933d2017-07-25 23:51:02 +00001//===- AArch64AsmPrinter.cpp - AArch64 LLVM assembly writer ---------------===//
Tim Northover3b0846e2014-05-24 12:50:23 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Tim Northover3b0846e2014-05-24 12:50:23 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This file contains a printer that converts from our internal representation
10// of machine-dependent LLVM code to the AArch64 assembly language.
11//
12//===----------------------------------------------------------------------===//
13
14#include "AArch64.h"
Tim Northover3b0846e2014-05-24 12:50:23 +000015#include "AArch64MCInstLower.h"
Benjamin Kramer1f8930e2014-07-25 11:42:14 +000016#include "AArch64MachineFunctionInfo.h"
Tim Northover3b0846e2014-05-24 12:50:23 +000017#include "AArch64RegisterInfo.h"
18#include "AArch64Subtarget.h"
Martin Storsjo865d01a2017-08-31 08:28:48 +000019#include "AArch64TargetObjectFile.h"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000020#include "MCTargetDesc/AArch64AddressingModes.h"
Richard Trieu7ba06052019-05-10 23:50:01 +000021#include "MCTargetDesc/AArch64InstPrinter.h"
Mitch Phillips790edbc2019-03-08 21:22:35 +000022#include "MCTargetDesc/AArch64MCExpr.h"
Eugene Zelenko96d933d2017-07-25 23:51:02 +000023#include "MCTargetDesc/AArch64MCTargetDesc.h"
Sanjin Sijaric96f2ea32018-10-27 06:13:06 +000024#include "MCTargetDesc/AArch64TargetStreamer.h"
Eugene Zelenko96d933d2017-07-25 23:51:02 +000025#include "Utils/AArch64BaseInfo.h"
Tim Northover3b0846e2014-05-24 12:50:23 +000026#include "llvm/ADT/SmallString.h"
Eugene Zelenko96d933d2017-07-25 23:51:02 +000027#include "llvm/ADT/SmallVector.h"
28#include "llvm/ADT/StringRef.h"
29#include "llvm/ADT/Triple.h"
Tim Northover3b0846e2014-05-24 12:50:23 +000030#include "llvm/ADT/Twine.h"
Mandeep Singh Grang802dc40f2018-12-11 18:36:14 +000031#include "llvm/BinaryFormat/COFF.h"
Peter Collingbourne73078ec2019-01-23 02:20:10 +000032#include "llvm/BinaryFormat/ELF.h"
Tim Northover3b0846e2014-05-24 12:50:23 +000033#include "llvm/CodeGen/AsmPrinter.h"
Eugene Zelenko96d933d2017-07-25 23:51:02 +000034#include "llvm/CodeGen/MachineBasicBlock.h"
35#include "llvm/CodeGen/MachineFunction.h"
Tim Northover3b0846e2014-05-24 12:50:23 +000036#include "llvm/CodeGen/MachineInstr.h"
Tim Northover1c353412018-10-24 20:19:09 +000037#include "llvm/CodeGen/MachineJumpTableInfo.h"
38#include "llvm/CodeGen/MachineModuleInfoImpls.h"
Eugene Zelenko96d933d2017-07-25 23:51:02 +000039#include "llvm/CodeGen/MachineOperand.h"
Benjamin Kramer1f8930e2014-07-25 11:42:14 +000040#include "llvm/CodeGen/StackMaps.h"
David Blaikieb3bde2e2017-11-17 01:07:10 +000041#include "llvm/CodeGen/TargetRegisterInfo.h"
Tim Northover3b0846e2014-05-24 12:50:23 +000042#include "llvm/IR/DataLayout.h"
Eugene Zelenko96d933d2017-07-25 23:51:02 +000043#include "llvm/IR/DebugInfoMetadata.h"
Tim Northover3b0846e2014-05-24 12:50:23 +000044#include "llvm/MC/MCAsmInfo.h"
45#include "llvm/MC/MCContext.h"
46#include "llvm/MC/MCInst.h"
47#include "llvm/MC/MCInstBuilder.h"
Peter Collingbourne73078ec2019-01-23 02:20:10 +000048#include "llvm/MC/MCSectionELF.h"
Tim Northover3b0846e2014-05-24 12:50:23 +000049#include "llvm/MC/MCStreamer.h"
Ahmed Bougacha1b676302015-03-05 20:04:21 +000050#include "llvm/MC/MCSymbol.h"
Eugene Zelenko96d933d2017-07-25 23:51:02 +000051#include "llvm/Support/Casting.h"
52#include "llvm/Support/ErrorHandling.h"
Tim Northover3b0846e2014-05-24 12:50:23 +000053#include "llvm/Support/TargetRegistry.h"
Benjamin Kramer799003b2015-03-23 19:32:43 +000054#include "llvm/Support/raw_ostream.h"
Eugene Zelenko96d933d2017-07-25 23:51:02 +000055#include "llvm/Target/TargetMachine.h"
Eugene Zelenko96d933d2017-07-25 23:51:02 +000056#include <algorithm>
57#include <cassert>
58#include <cstdint>
59#include <map>
60#include <memory>
61
Tim Northover3b0846e2014-05-24 12:50:23 +000062using namespace llvm;
63
64#define DEBUG_TYPE "asm-printer"
65
66namespace {
67
68class AArch64AsmPrinter : public AsmPrinter {
Tim Northover3b0846e2014-05-24 12:50:23 +000069 AArch64MCInstLower MCInstLowering;
70 StackMaps SM;
Matthias Braunad0032a2016-07-06 21:39:33 +000071 const AArch64Subtarget *STI;
Tim Northover3b0846e2014-05-24 12:50:23 +000072
73public:
David Blaikie94598322015-01-18 20:29:04 +000074 AArch64AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
Eric Christopherbb1ae662015-02-03 06:40:19 +000075 : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this),
Eugene Zelenko96d933d2017-07-25 23:51:02 +000076 SM(*this) {}
Tim Northover3b0846e2014-05-24 12:50:23 +000077
Mehdi Amini117296c2016-10-01 02:56:57 +000078 StringRef getPassName() const override { return "AArch64 Assembly Printer"; }
Tim Northover3b0846e2014-05-24 12:50:23 +000079
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000080 /// Wrapper for MCInstLowering.lowerOperand() for the
Tim Northover3b0846e2014-05-24 12:50:23 +000081 /// tblgen'erated pseudo lowering.
82 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
83 return MCInstLowering.lowerOperand(MO, MCOp);
84 }
85
Tim Northover1c353412018-10-24 20:19:09 +000086 void EmitJumpTableInfo() override;
87 void emitJumpTableEntry(const MachineJumpTableInfo *MJTI,
88 const MachineBasicBlock *MBB, unsigned JTI);
89
90 void LowerJumpTableDestSmall(MCStreamer &OutStreamer, const MachineInstr &MI);
91
Tim Northover3b0846e2014-05-24 12:50:23 +000092 void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
93 const MachineInstr &MI);
94 void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
95 const MachineInstr &MI);
Dean Michael Berris3234d3a2016-11-17 05:15:37 +000096
97 void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI);
98 void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI);
99 void LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI);
100
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000101 std::map<std::pair<unsigned, uint32_t>, MCSymbol *> HwasanMemaccessSymbols;
102 void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);
103 void EmitHwasanMemaccessSymbols(Module &M);
104
Dean Michael Berris3234d3a2016-11-17 05:15:37 +0000105 void EmitSled(const MachineInstr &MI, SledKind Kind);
106
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000107 /// tblgen'erated driver function for lowering simple MI->MC
Tim Northover3b0846e2014-05-24 12:50:23 +0000108 /// pseudo instructions.
109 bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
110 const MachineInstr *MI);
111
112 void EmitInstruction(const MachineInstr *MI) override;
113
114 void getAnalysisUsage(AnalysisUsage &AU) const override {
115 AsmPrinter::getAnalysisUsage(AU);
116 AU.setPreservesAll();
117 }
118
Mandeep Singh Grang802dc40f2018-12-11 18:36:14 +0000119 bool runOnMachineFunction(MachineFunction &MF) override {
120 AArch64FI = MF.getInfo<AArch64FunctionInfo>();
121 STI = static_cast<const AArch64Subtarget*>(&MF.getSubtarget());
122
123 SetupMachineFunction(MF);
124
125 if (STI->isTargetCOFF()) {
126 bool Internal = MF.getFunction().hasInternalLinkage();
127 COFF::SymbolStorageClass Scl = Internal ? COFF::IMAGE_SYM_CLASS_STATIC
128 : COFF::IMAGE_SYM_CLASS_EXTERNAL;
129 int Type =
130 COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT;
131
132 OutStreamer->BeginCOFFSymbolDef(CurrentFnSym);
133 OutStreamer->EmitCOFFSymbolStorageClass(Scl);
134 OutStreamer->EmitCOFFSymbolType(Type);
135 OutStreamer->EndCOFFSymbolDef();
136 }
137
138 // Emit the rest of the function body.
139 EmitFunctionBody();
140
141 // Emit the XRay table for this function.
Dean Michael Berrisf7e7b932017-01-03 04:30:21 +0000142 emitXRayTable();
Mandeep Singh Grang802dc40f2018-12-11 18:36:14 +0000143
144 // We didn't modify anything.
145 return false;
Tim Northover3b0846e2014-05-24 12:50:23 +0000146 }
147
148private:
Tim Northover3b0846e2014-05-24 12:50:23 +0000149 void printOperand(const MachineInstr *MI, unsigned OpNum, raw_ostream &O);
150 bool printAsmMRegister(const MachineOperand &MO, char Mode, raw_ostream &O);
151 bool printAsmRegInClass(const MachineOperand &MO,
152 const TargetRegisterClass *RC, bool isVector,
153 raw_ostream &O);
154
155 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
Nick Desaulniers5277b3f2019-04-10 16:38:43 +0000156 const char *ExtraCode, raw_ostream &O) override;
Tim Northover3b0846e2014-05-24 12:50:23 +0000157 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
Nick Desaulniers5277b3f2019-04-10 16:38:43 +0000158 const char *ExtraCode, raw_ostream &O) override;
Tim Northover3b0846e2014-05-24 12:50:23 +0000159
160 void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
161
162 void EmitFunctionBodyEnd() override;
163
164 MCSymbol *GetCPISymbol(unsigned CPID) const override;
165 void EmitEndOfAsmFile(Module &M) override;
Eugene Zelenko96d933d2017-07-25 23:51:02 +0000166
167 AArch64FunctionInfo *AArch64FI = nullptr;
Tim Northover3b0846e2014-05-24 12:50:23 +0000168
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000169 /// Emit the LOHs contained in AArch64FI.
Tim Northover3b0846e2014-05-24 12:50:23 +0000170 void EmitLOHs();
171
Matthias Braunad0032a2016-07-06 21:39:33 +0000172 /// Emit instruction to set float register to zero.
173 void EmitFMov0(const MachineInstr &MI);
174
Eugene Zelenko96d933d2017-07-25 23:51:02 +0000175 using MInstToMCSymbol = std::map<const MachineInstr *, MCSymbol *>;
176
Tim Northover3b0846e2014-05-24 12:50:23 +0000177 MInstToMCSymbol LOHInstToLabel;
Tim Northover3b0846e2014-05-24 12:50:23 +0000178};
179
Eugene Zelenko96d933d2017-07-25 23:51:02 +0000180} // end anonymous namespace
Tim Northover3b0846e2014-05-24 12:50:23 +0000181
Dean Michael Berris3234d3a2016-11-17 05:15:37 +0000182void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
183{
184 EmitSled(MI, SledKind::FUNCTION_ENTER);
185}
186
187void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI)
188{
189 EmitSled(MI, SledKind::FUNCTION_EXIT);
190}
191
192void AArch64AsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI)
193{
194 EmitSled(MI, SledKind::TAIL_CALL);
195}
196
Dean Michael Berris3234d3a2016-11-17 05:15:37 +0000197void AArch64AsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind)
198{
199 static const int8_t NoopsInSledCount = 7;
200 // We want to emit the following pattern:
201 //
202 // .Lxray_sled_N:
203 // ALIGN
204 // B #32
205 // ; 7 NOP instructions (28 bytes)
206 // .tmpN
207 //
208 // We need the 28 bytes (7 instructions) because at runtime, we'd be patching
209 // over the full 32 bytes (8 instructions) with the following pattern:
210 //
211 // STP X0, X30, [SP, #-16]! ; push X0 and the link register to the stack
212 // LDR W0, #12 ; W0 := function ID
213 // LDR X16,#12 ; X16 := addr of __xray_FunctionEntry or __xray_FunctionExit
214 // BLR X16 ; call the tracing trampoline
215 // ;DATA: 32 bits of function ID
216 // ;DATA: lower 32 bits of the address of the trampoline
217 // ;DATA: higher 32 bits of the address of the trampoline
218 // LDP X0, X30, [SP], #16 ; pop X0 and the link register from the stack
219 //
220 OutStreamer->EmitCodeAlignment(4);
221 auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
222 OutStreamer->EmitLabel(CurSled);
223 auto Target = OutContext.createTempSymbol();
224
225 // Emit "B #32" instruction, which jumps over the next 28 bytes.
Dean Michael Berris31761f32016-11-21 03:01:43 +0000226 // The operand has to be the number of 4-byte instructions to jump over,
227 // including the current instruction.
228 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::B).addImm(8));
Dean Michael Berris3234d3a2016-11-17 05:15:37 +0000229
230 for (int8_t I = 0; I < NoopsInSledCount; I++)
231 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
232
233 OutStreamer->EmitLabel(Target);
234 recordSled(CurSled, MI, Kind);
235}
236
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000237void AArch64AsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
238 unsigned Reg = MI.getOperand(0).getReg();
239 uint32_t AccessInfo = MI.getOperand(1).getImm();
240 MCSymbol *&Sym = HwasanMemaccessSymbols[{Reg, AccessInfo}];
241 if (!Sym) {
242 // FIXME: Make this work on non-ELF.
243 if (!TM.getTargetTriple().isOSBinFormatELF())
244 report_fatal_error("llvm.hwasan.check.memaccess only supported on ELF");
245
246 std::string SymName = "__hwasan_check_x" + utostr(Reg - AArch64::X0) + "_" +
247 utostr(AccessInfo);
248 Sym = OutContext.getOrCreateSymbol(SymName);
249 }
250
251 EmitToStreamer(*OutStreamer,
252 MCInstBuilder(AArch64::BL)
253 .addExpr(MCSymbolRefExpr::create(Sym, OutContext)));
254}
255
256void AArch64AsmPrinter::EmitHwasanMemaccessSymbols(Module &M) {
257 if (HwasanMemaccessSymbols.empty())
258 return;
259
260 const Triple &TT = TM.getTargetTriple();
261 assert(TT.isOSBinFormatELF());
262 std::unique_ptr<MCSubtargetInfo> STI(
263 TM.getTarget().createMCSubtargetInfo(TT.str(), "", ""));
264
265 MCSymbol *HwasanTagMismatchSym =
266 OutContext.getOrCreateSymbol("__hwasan_tag_mismatch");
267
Mitch Phillips790edbc2019-03-08 21:22:35 +0000268 const MCSymbolRefExpr *HwasanTagMismatchRef =
269 MCSymbolRefExpr::create(HwasanTagMismatchSym, OutContext);
270
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000271 for (auto &P : HwasanMemaccessSymbols) {
272 unsigned Reg = P.first.first;
273 uint32_t AccessInfo = P.first.second;
274 MCSymbol *Sym = P.second;
275
276 OutStreamer->SwitchSection(OutContext.getELFSection(
277 ".text.hot", ELF::SHT_PROGBITS,
278 ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_GROUP, 0,
279 Sym->getName()));
280
281 OutStreamer->EmitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
282 OutStreamer->EmitSymbolAttribute(Sym, MCSA_Weak);
283 OutStreamer->EmitSymbolAttribute(Sym, MCSA_Hidden);
284 OutStreamer->EmitLabel(Sym);
285
286 OutStreamer->EmitInstruction(MCInstBuilder(AArch64::UBFMXri)
287 .addReg(AArch64::X16)
288 .addReg(Reg)
289 .addImm(4)
290 .addImm(55),
291 *STI);
292 OutStreamer->EmitInstruction(MCInstBuilder(AArch64::LDRBBroX)
293 .addReg(AArch64::W16)
294 .addReg(AArch64::X9)
295 .addReg(AArch64::X16)
296 .addImm(0)
297 .addImm(0),
298 *STI);
299 OutStreamer->EmitInstruction(MCInstBuilder(AArch64::UBFMXri)
300 .addReg(AArch64::X17)
301 .addReg(Reg)
302 .addImm(56)
303 .addImm(63),
304 *STI);
305 OutStreamer->EmitInstruction(MCInstBuilder(AArch64::SUBSWrs)
306 .addReg(AArch64::WZR)
307 .addReg(AArch64::W16)
308 .addReg(AArch64::W17)
309 .addImm(0),
310 *STI);
311 MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
312 OutStreamer->EmitInstruction(
313 MCInstBuilder(AArch64::Bcc)
314 .addImm(AArch64CC::NE)
315 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
316 *STI);
317 OutStreamer->EmitInstruction(
318 MCInstBuilder(AArch64::RET).addReg(AArch64::LR), *STI);
319
320 OutStreamer->EmitLabel(HandleMismatchSym);
Mitch Phillips790edbc2019-03-08 21:22:35 +0000321
322 OutStreamer->EmitInstruction(MCInstBuilder(AArch64::STPXpre)
323 .addReg(AArch64::SP)
324 .addReg(AArch64::X0)
325 .addReg(AArch64::X1)
326 .addReg(AArch64::SP)
327 .addImm(-32),
328 *STI);
329 OutStreamer->EmitInstruction(MCInstBuilder(AArch64::STPXi)
330 .addReg(AArch64::FP)
331 .addReg(AArch64::LR)
332 .addReg(AArch64::SP)
333 .addImm(29),
334 *STI);
335
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000336 if (Reg != AArch64::X0)
337 OutStreamer->EmitInstruction(MCInstBuilder(AArch64::ORRXrs)
338 .addReg(AArch64::X0)
339 .addReg(AArch64::XZR)
340 .addReg(Reg)
341 .addImm(0),
342 *STI);
343 OutStreamer->EmitInstruction(MCInstBuilder(AArch64::MOVZXi)
344 .addReg(AArch64::X1)
345 .addImm(AccessInfo)
346 .addImm(0),
347 *STI);
Mitch Phillips790edbc2019-03-08 21:22:35 +0000348
349 // Intentionally load the GOT entry and branch to it, rather than possibly
350 // late binding the function, which may clobber the registers before we have
351 // a chance to save them.
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000352 OutStreamer->EmitInstruction(
Mitch Phillips790edbc2019-03-08 21:22:35 +0000353 MCInstBuilder(AArch64::ADRP)
354 .addReg(AArch64::X16)
355 .addExpr(AArch64MCExpr::create(
356 HwasanTagMismatchRef,
357 AArch64MCExpr::VariantKind::VK_GOT_PAGE, OutContext)),
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000358 *STI);
Mitch Phillips790edbc2019-03-08 21:22:35 +0000359 OutStreamer->EmitInstruction(
360 MCInstBuilder(AArch64::LDRXui)
361 .addReg(AArch64::X16)
362 .addReg(AArch64::X16)
363 .addExpr(AArch64MCExpr::create(
364 HwasanTagMismatchRef,
365 AArch64MCExpr::VariantKind::VK_GOT_LO12, OutContext)),
366 *STI);
367 OutStreamer->EmitInstruction(
368 MCInstBuilder(AArch64::BR).addReg(AArch64::X16), *STI);
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000369 }
370}
371
Tim Northover3b0846e2014-05-24 12:50:23 +0000372void AArch64AsmPrinter::EmitEndOfAsmFile(Module &M) {
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000373 EmitHwasanMemaccessSymbols(M);
374
Daniel Sandersc81f4502015-06-16 15:44:21 +0000375 const Triple &TT = TM.getTargetTriple();
Eric Christopherbb1ae662015-02-03 06:40:19 +0000376 if (TT.isOSBinFormatMachO()) {
Tim Northover3b0846e2014-05-24 12:50:23 +0000377 // Funny Darwin hack: This flag tells the linker that no global symbols
378 // contain code that falls through to other global symbols (e.g. the obvious
379 // implementation of multiple entry points). If this doesn't occur, the
380 // linker can safely perform dead code stripping. Since LLVM never
381 // generates code that does this, it is always safe to set.
Lang Hames9ff69c82015-04-24 19:11:51 +0000382 OutStreamer->EmitAssemblerFlag(MCAF_SubsectionsViaSymbols);
Than McIntosh30c804b2018-11-26 18:43:48 +0000383 emitStackMaps(SM);
Tim Northover3b0846e2014-05-24 12:50:23 +0000384 }
Tim Northover3b0846e2014-05-24 12:50:23 +0000385}
386
Tim Northover3b0846e2014-05-24 12:50:23 +0000387void AArch64AsmPrinter::EmitLOHs() {
388 SmallVector<MCSymbol *, 3> MCArgs;
389
390 for (const auto &D : AArch64FI->getLOHContainer()) {
391 for (const MachineInstr *MI : D.getArgs()) {
392 MInstToMCSymbol::iterator LabelIt = LOHInstToLabel.find(MI);
393 assert(LabelIt != LOHInstToLabel.end() &&
394 "Label hasn't been inserted for LOH related instruction");
395 MCArgs.push_back(LabelIt->second);
396 }
Lang Hames9ff69c82015-04-24 19:11:51 +0000397 OutStreamer->EmitLOHDirective(D.getKind(), MCArgs);
Tim Northover3b0846e2014-05-24 12:50:23 +0000398 MCArgs.clear();
399 }
400}
401
402void AArch64AsmPrinter::EmitFunctionBodyEnd() {
403 if (!AArch64FI->getLOHRelated().empty())
404 EmitLOHs();
405}
406
407/// GetCPISymbol - Return the symbol for the specified constant pool entry.
408MCSymbol *AArch64AsmPrinter::GetCPISymbol(unsigned CPID) const {
409 // Darwin uses a linker-private symbol name for constant-pools (to
410 // avoid addends on the relocation?), ELF has no such concept and
411 // uses a normal private symbol.
Mehdi Amini48878ae2016-10-01 05:57:55 +0000412 if (!getDataLayout().getLinkerPrivateGlobalPrefix().empty())
Jim Grosbach6f482002015-05-18 18:43:14 +0000413 return OutContext.getOrCreateSymbol(
Tim Northover3b0846e2014-05-24 12:50:23 +0000414 Twine(getDataLayout().getLinkerPrivateGlobalPrefix()) + "CPI" +
415 Twine(getFunctionNumber()) + "_" + Twine(CPID));
416
Martin Storsjod2662c32018-07-25 18:35:31 +0000417 return AsmPrinter::GetCPISymbol(CPID);
Tim Northover3b0846e2014-05-24 12:50:23 +0000418}
419
420void AArch64AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNum,
421 raw_ostream &O) {
422 const MachineOperand &MO = MI->getOperand(OpNum);
423 switch (MO.getType()) {
424 default:
Craig Topper2a30d782014-06-18 05:05:13 +0000425 llvm_unreachable("<unknown operand type>");
Tim Northover3b0846e2014-05-24 12:50:23 +0000426 case MachineOperand::MO_Register: {
427 unsigned Reg = MO.getReg();
428 assert(TargetRegisterInfo::isPhysicalRegister(Reg));
429 assert(!MO.getSubReg() && "Subregs should be eliminated!");
430 O << AArch64InstPrinter::getRegisterName(Reg);
431 break;
432 }
433 case MachineOperand::MO_Immediate: {
434 int64_t Imm = MO.getImm();
435 O << '#' << Imm;
436 break;
437 }
Ahmed Bougacha1b676302015-03-05 20:04:21 +0000438 case MachineOperand::MO_GlobalAddress: {
Nick Desaulniers7ab164c2019-04-26 18:45:04 +0000439 PrintSymbolOperand(MO, O);
Ahmed Bougacha1b676302015-03-05 20:04:21 +0000440 break;
441 }
Peter Smithc8117582018-05-16 09:33:25 +0000442 case MachineOperand::MO_BlockAddress: {
443 MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());
444 Sym->print(O, MAI);
445 break;
446 }
Tim Northover3b0846e2014-05-24 12:50:23 +0000447 }
448}
449
450bool AArch64AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode,
451 raw_ostream &O) {
452 unsigned Reg = MO.getReg();
453 switch (Mode) {
454 default:
455 return true; // Unknown mode.
456 case 'w':
457 Reg = getWRegFromXReg(Reg);
458 break;
459 case 'x':
460 Reg = getXRegFromWReg(Reg);
461 break;
462 }
463
464 O << AArch64InstPrinter::getRegisterName(Reg);
465 return false;
466}
467
468// Prints the register in MO using class RC using the offset in the
469// new register class. This should not be used for cross class
470// printing.
471bool AArch64AsmPrinter::printAsmRegInClass(const MachineOperand &MO,
472 const TargetRegisterClass *RC,
473 bool isVector, raw_ostream &O) {
474 assert(MO.isReg() && "Should only get here with a register!");
Matthias Braunad0032a2016-07-06 21:39:33 +0000475 const TargetRegisterInfo *RI = STI->getRegisterInfo();
Tim Northover3b0846e2014-05-24 12:50:23 +0000476 unsigned Reg = MO.getReg();
477 unsigned RegToPrint = RC->getRegister(RI->getEncodingValue(Reg));
478 assert(RI->regsOverlap(RegToPrint, Reg));
479 O << AArch64InstPrinter::getRegisterName(
480 RegToPrint, isVector ? AArch64::vreg : AArch64::NoRegAltName);
481 return false;
482}
483
484bool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
Tim Northover3b0846e2014-05-24 12:50:23 +0000485 const char *ExtraCode, raw_ostream &O) {
486 const MachineOperand &MO = MI->getOperand(OpNum);
Tim Northover47190412014-05-27 07:37:21 +0000487
488 // First try the generic code, which knows about modifiers like 'c' and 'n'.
Nick Desaulniers5277b3f2019-04-10 16:38:43 +0000489 if (!AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O))
Tim Northover47190412014-05-27 07:37:21 +0000490 return false;
491
Tim Northover3b0846e2014-05-24 12:50:23 +0000492 // Does this asm operand have a single letter operand modifier?
493 if (ExtraCode && ExtraCode[0]) {
494 if (ExtraCode[1] != 0)
495 return true; // Unknown modifier.
496
497 switch (ExtraCode[0]) {
498 default:
499 return true; // Unknown modifier.
500 case 'w': // Print W register
501 case 'x': // Print X register
502 if (MO.isReg())
503 return printAsmMRegister(MO, ExtraCode[0], O);
504 if (MO.isImm() && MO.getImm() == 0) {
505 unsigned Reg = ExtraCode[0] == 'w' ? AArch64::WZR : AArch64::XZR;
506 O << AArch64InstPrinter::getRegisterName(Reg);
507 return false;
508 }
509 printOperand(MI, OpNum, O);
510 return false;
511 case 'b': // Print B register.
512 case 'h': // Print H register.
513 case 's': // Print S register.
514 case 'd': // Print D register.
515 case 'q': // Print Q register.
516 if (MO.isReg()) {
517 const TargetRegisterClass *RC;
518 switch (ExtraCode[0]) {
519 case 'b':
520 RC = &AArch64::FPR8RegClass;
521 break;
522 case 'h':
523 RC = &AArch64::FPR16RegClass;
524 break;
525 case 's':
526 RC = &AArch64::FPR32RegClass;
527 break;
528 case 'd':
529 RC = &AArch64::FPR64RegClass;
530 break;
531 case 'q':
532 RC = &AArch64::FPR128RegClass;
533 break;
534 default:
535 return true;
536 }
537 return printAsmRegInClass(MO, RC, false /* vector */, O);
538 }
539 printOperand(MI, OpNum, O);
540 return false;
541 }
542 }
543
544 // According to ARM, we should emit x and v registers unless we have a
545 // modifier.
546 if (MO.isReg()) {
547 unsigned Reg = MO.getReg();
548
549 // If this is a w or x register, print an x register.
550 if (AArch64::GPR32allRegClass.contains(Reg) ||
551 AArch64::GPR64allRegClass.contains(Reg))
552 return printAsmMRegister(MO, 'x', O);
553
554 // If this is a b, h, s, d, or q register, print it as a v register.
555 return printAsmRegInClass(MO, &AArch64::FPR128RegClass, true /* vector */,
556 O);
557 }
558
559 printOperand(MI, OpNum, O);
560 return false;
561}
562
563bool AArch64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
564 unsigned OpNum,
Tim Northover3b0846e2014-05-24 12:50:23 +0000565 const char *ExtraCode,
566 raw_ostream &O) {
Manoj Guptad5361802017-05-25 19:07:57 +0000567 if (ExtraCode && ExtraCode[0] && ExtraCode[0] != 'a')
Tim Northover3b0846e2014-05-24 12:50:23 +0000568 return true; // Unknown modifier.
569
570 const MachineOperand &MO = MI->getOperand(OpNum);
571 assert(MO.isReg() && "unexpected inline asm memory operand");
572 O << "[" << AArch64InstPrinter::getRegisterName(MO.getReg()) << "]";
573 return false;
574}
575
576void AArch64AsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
577 raw_ostream &OS) {
578 unsigned NOps = MI->getNumOperands();
579 assert(NOps == 4);
580 OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: ";
581 // cast away const; DIetc do not take const operands for some reason.
Duncan P. N. Exon Smitha9308c42015-04-29 16:38:44 +0000582 OS << cast<DILocalVariable>(MI->getOperand(NOps - 2).getMetadata())
Duncan P. N. Exon Smith7348dda2015-04-14 02:22:36 +0000583 ->getName();
Tim Northover3b0846e2014-05-24 12:50:23 +0000584 OS << " <- ";
585 // Frame address. Currently handles register +- offset only.
586 assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm());
587 OS << '[';
588 printOperand(MI, 0, OS);
589 OS << '+';
590 printOperand(MI, 1, OS);
591 OS << ']';
592 OS << "+";
593 printOperand(MI, NOps - 2, OS);
594}
595
Tim Northover1c353412018-10-24 20:19:09 +0000596void AArch64AsmPrinter::EmitJumpTableInfo() {
597 const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
598 if (!MJTI) return;
599
600 const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
601 if (JT.empty()) return;
602
Martin Storsjof5884d22019-01-29 09:36:48 +0000603 const Function &F = MF->getFunction();
Tim Northover1c353412018-10-24 20:19:09 +0000604 const TargetLoweringObjectFile &TLOF = getObjFileLowering();
Martin Storsjof5884d22019-01-29 09:36:48 +0000605 bool JTInDiffSection =
606 !STI->isTargetCOFF() ||
607 !TLOF.shouldPutJumpTableInFunctionSection(
608 MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32,
609 F);
610 if (JTInDiffSection) {
611 // Drop it in the readonly section.
612 MCSection *ReadOnlySec = TLOF.getSectionForJumpTable(F, TM);
613 OutStreamer->SwitchSection(ReadOnlySec);
614 }
Tim Northover1c353412018-10-24 20:19:09 +0000615
616 auto AFI = MF->getInfo<AArch64FunctionInfo>();
617 for (unsigned JTI = 0, e = JT.size(); JTI != e; ++JTI) {
618 const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
619
620 // If this jump table was deleted, ignore it.
621 if (JTBBs.empty()) continue;
622
623 unsigned Size = AFI->getJumpTableEntrySize(JTI);
624 EmitAlignment(Log2_32(Size));
625 OutStreamer->EmitLabel(GetJTISymbol(JTI));
626
627 for (auto *JTBB : JTBBs)
628 emitJumpTableEntry(MJTI, JTBB, JTI);
629 }
630}
631
632void AArch64AsmPrinter::emitJumpTableEntry(const MachineJumpTableInfo *MJTI,
633 const MachineBasicBlock *MBB,
634 unsigned JTI) {
635 const MCExpr *Value = MCSymbolRefExpr::create(MBB->getSymbol(), OutContext);
636 auto AFI = MF->getInfo<AArch64FunctionInfo>();
637 unsigned Size = AFI->getJumpTableEntrySize(JTI);
638
639 if (Size == 4) {
640 // .word LBB - LJTI
641 const TargetLowering *TLI = MF->getSubtarget().getTargetLowering();
642 const MCExpr *Base = TLI->getPICJumpTableRelocBaseExpr(MF, JTI, OutContext);
643 Value = MCBinaryExpr::createSub(Value, Base, OutContext);
644 } else {
645 // .byte (LBB - LBB) >> 2 (or .hword)
646 const MCSymbol *BaseSym = AFI->getJumpTableEntryPCRelSymbol(JTI);
647 const MCExpr *Base = MCSymbolRefExpr::create(BaseSym, OutContext);
648 Value = MCBinaryExpr::createSub(Value, Base, OutContext);
649 Value = MCBinaryExpr::createLShr(
650 Value, MCConstantExpr::create(2, OutContext), OutContext);
651 }
652
653 OutStreamer->EmitValue(Value, Size);
654}
655
656/// Small jump tables contain an unsigned byte or half, representing the offset
657/// from the lowest-addressed possible destination to the desired basic
658/// block. Since all instructions are 4-byte aligned, this is further compressed
659/// by counting in instructions rather than bytes (i.e. divided by 4). So, to
660/// materialize the correct destination we need:
661///
662/// adr xDest, .LBB0_0
663/// ldrb wScratch, [xTable, xEntry] (with "lsl #1" for ldrh).
664/// add xDest, xDest, xScratch, lsl #2
665void AArch64AsmPrinter::LowerJumpTableDestSmall(llvm::MCStreamer &OutStreamer,
666 const llvm::MachineInstr &MI) {
667 unsigned DestReg = MI.getOperand(0).getReg();
668 unsigned ScratchReg = MI.getOperand(1).getReg();
669 unsigned ScratchRegW =
670 STI->getRegisterInfo()->getSubReg(ScratchReg, AArch64::sub_32);
671 unsigned TableReg = MI.getOperand(2).getReg();
672 unsigned EntryReg = MI.getOperand(3).getReg();
673 int JTIdx = MI.getOperand(4).getIndex();
674 bool IsByteEntry = MI.getOpcode() == AArch64::JumpTableDest8;
675
676 // This has to be first because the compression pass based its reachability
677 // calculations on the start of the JumpTableDest instruction.
678 auto Label =
679 MF->getInfo<AArch64FunctionInfo>()->getJumpTableEntryPCRelSymbol(JTIdx);
680 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADR)
681 .addReg(DestReg)
682 .addExpr(MCSymbolRefExpr::create(
683 Label, MF->getContext())));
684
685 // Load the number of instruction-steps to offset from the label.
686 unsigned LdrOpcode = IsByteEntry ? AArch64::LDRBBroX : AArch64::LDRHHroX;
687 EmitToStreamer(OutStreamer, MCInstBuilder(LdrOpcode)
688 .addReg(ScratchRegW)
689 .addReg(TableReg)
690 .addReg(EntryReg)
691 .addImm(0)
692 .addImm(IsByteEntry ? 0 : 1));
693
694 // Multiply the steps by 4 and add to the already materialized base label
695 // address.
696 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADDXrs)
697 .addReg(DestReg)
698 .addReg(DestReg)
699 .addReg(ScratchReg)
700 .addImm(2));
701}
702
Tim Northover3b0846e2014-05-24 12:50:23 +0000703void AArch64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
704 const MachineInstr &MI) {
Diana Picus760c7572016-08-31 12:43:49 +0000705 unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes();
Tim Northover3b0846e2014-05-24 12:50:23 +0000706
707 SM.recordStackMap(MI);
Tim Northover3b0846e2014-05-24 12:50:23 +0000708 assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
Lang Hamesa7395bf2014-12-02 21:36:24 +0000709
710 // Scan ahead to trim the shadow.
711 const MachineBasicBlock &MBB = *MI.getParent();
712 MachineBasicBlock::const_iterator MII(MI);
713 ++MII;
714 while (NumNOPBytes > 0) {
715 if (MII == MBB.end() || MII->isCall() ||
716 MII->getOpcode() == AArch64::DBG_VALUE ||
717 MII->getOpcode() == TargetOpcode::PATCHPOINT ||
718 MII->getOpcode() == TargetOpcode::STACKMAP)
719 break;
720 ++MII;
721 NumNOPBytes -= 4;
722 }
723
724 // Emit nops.
Tim Northover3b0846e2014-05-24 12:50:23 +0000725 for (unsigned i = 0; i < NumNOPBytes; i += 4)
726 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
727}
728
729// Lower a patchpoint of the form:
730// [<def>], <id>, <numBytes>, <target>, <numArgs>
731void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
732 const MachineInstr &MI) {
733 SM.recordPatchPoint(MI);
734
735 PatchPointOpers Opers(&MI);
736
Philip Reamese83c4b32016-08-23 23:33:29 +0000737 int64_t CallTarget = Opers.getCallTarget().getImm();
Tim Northover3b0846e2014-05-24 12:50:23 +0000738 unsigned EncodedBytes = 0;
739 if (CallTarget) {
740 assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget &&
741 "High 16 bits of call target should be zero.");
742 unsigned ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg();
743 EncodedBytes = 16;
744 // Materialize the jump address:
Tim Northover389a1e32016-06-15 20:33:36 +0000745 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVZXi)
Tim Northover3b0846e2014-05-24 12:50:23 +0000746 .addReg(ScratchReg)
747 .addImm((CallTarget >> 32) & 0xFFFF)
748 .addImm(32));
Tim Northover389a1e32016-06-15 20:33:36 +0000749 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi)
Tim Northover3b0846e2014-05-24 12:50:23 +0000750 .addReg(ScratchReg)
751 .addReg(ScratchReg)
752 .addImm((CallTarget >> 16) & 0xFFFF)
753 .addImm(16));
Tim Northover389a1e32016-06-15 20:33:36 +0000754 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi)
Tim Northover3b0846e2014-05-24 12:50:23 +0000755 .addReg(ScratchReg)
756 .addReg(ScratchReg)
757 .addImm(CallTarget & 0xFFFF)
758 .addImm(0));
759 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::BLR).addReg(ScratchReg));
760 }
761 // Emit padding.
Philip Reamese83c4b32016-08-23 23:33:29 +0000762 unsigned NumBytes = Opers.getNumPatchBytes();
Tim Northover3b0846e2014-05-24 12:50:23 +0000763 assert(NumBytes >= EncodedBytes &&
764 "Patchpoint can't request size less than the length of a call.");
765 assert((NumBytes - EncodedBytes) % 4 == 0 &&
766 "Invalid number of NOP bytes requested!");
767 for (unsigned i = EncodedBytes; i < NumBytes; i += 4)
768 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
769}
770
Matthias Braunad0032a2016-07-06 21:39:33 +0000771void AArch64AsmPrinter::EmitFMov0(const MachineInstr &MI) {
772 unsigned DestReg = MI.getOperand(0).getReg();
Evandro Menezesfc1852f2018-09-28 19:05:09 +0000773 if (STI->hasZeroCycleZeroingFP() && !STI->hasZeroCycleZeroingFPWorkaround()) {
Sjoerd Meijerb0eb5fb2017-08-24 14:47:06 +0000774 // Convert H/S/D register to corresponding Q register
775 if (AArch64::H0 <= DestReg && DestReg <= AArch64::H31)
776 DestReg = AArch64::Q0 + (DestReg - AArch64::H0);
777 else if (AArch64::S0 <= DestReg && DestReg <= AArch64::S31)
Matthias Braunad0032a2016-07-06 21:39:33 +0000778 DestReg = AArch64::Q0 + (DestReg - AArch64::S0);
Sjoerd Meijerb0eb5fb2017-08-24 14:47:06 +0000779 else {
Matthias Braunad0032a2016-07-06 21:39:33 +0000780 assert(AArch64::D0 <= DestReg && DestReg <= AArch64::D31);
781 DestReg = AArch64::Q0 + (DestReg - AArch64::D0);
782 }
783 MCInst MOVI;
784 MOVI.setOpcode(AArch64::MOVIv2d_ns);
785 MOVI.addOperand(MCOperand::createReg(DestReg));
786 MOVI.addOperand(MCOperand::createImm(0));
787 EmitToStreamer(*OutStreamer, MOVI);
788 } else {
789 MCInst FMov;
790 switch (MI.getOpcode()) {
791 default: llvm_unreachable("Unexpected opcode");
Sjoerd Meijerb0eb5fb2017-08-24 14:47:06 +0000792 case AArch64::FMOVH0:
793 FMov.setOpcode(AArch64::FMOVWHr);
794 FMov.addOperand(MCOperand::createReg(DestReg));
795 FMov.addOperand(MCOperand::createReg(AArch64::WZR));
796 break;
Matthias Braunad0032a2016-07-06 21:39:33 +0000797 case AArch64::FMOVS0:
798 FMov.setOpcode(AArch64::FMOVWSr);
799 FMov.addOperand(MCOperand::createReg(DestReg));
800 FMov.addOperand(MCOperand::createReg(AArch64::WZR));
801 break;
802 case AArch64::FMOVD0:
803 FMov.setOpcode(AArch64::FMOVXDr);
804 FMov.addOperand(MCOperand::createReg(DestReg));
805 FMov.addOperand(MCOperand::createReg(AArch64::XZR));
806 break;
807 }
808 EmitToStreamer(*OutStreamer, FMov);
809 }
810}
811
Tim Northover3b0846e2014-05-24 12:50:23 +0000812// Simple pseudo-instructions have their lowering (with expansion to real
813// instructions) auto-generated.
814#include "AArch64GenMCPseudoLowering.inc"
815
816void AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
817 // Do any auto-generated pseudo lowerings.
Lang Hames9ff69c82015-04-24 19:11:51 +0000818 if (emitPseudoExpansionLowering(*OutStreamer, MI))
Tim Northover3b0846e2014-05-24 12:50:23 +0000819 return;
820
821 if (AArch64FI->getLOHRelated().count(MI)) {
822 // Generate a label for LOH related instruction
Rafael Espindola9ab09232015-03-17 20:07:06 +0000823 MCSymbol *LOHLabel = createTempSymbol("loh");
Tim Northover3b0846e2014-05-24 12:50:23 +0000824 // Associate the instruction with the label
825 LOHInstToLabel[MI] = LOHLabel;
Lang Hames9ff69c82015-04-24 19:11:51 +0000826 OutStreamer->EmitLabel(LOHLabel);
Tim Northover3b0846e2014-05-24 12:50:23 +0000827 }
828
Sanjin Sijaric96f2ea32018-10-27 06:13:06 +0000829 AArch64TargetStreamer *TS =
830 static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
Tim Northover3b0846e2014-05-24 12:50:23 +0000831 // Do any manual lowerings.
832 switch (MI->getOpcode()) {
833 default:
834 break;
Mandeep Singh Grang33c49c02019-01-16 19:52:59 +0000835 case AArch64::MOVMCSym: {
836 unsigned DestReg = MI->getOperand(0).getReg();
837 const MachineOperand &MO_Sym = MI->getOperand(1);
838 MachineOperand Hi_MOSym(MO_Sym), Lo_MOSym(MO_Sym);
839 MCOperand Hi_MCSym, Lo_MCSym;
840
841 Hi_MOSym.setTargetFlags(AArch64II::MO_G1 | AArch64II::MO_S);
842 Lo_MOSym.setTargetFlags(AArch64II::MO_G0 | AArch64II::MO_NC);
843
844 MCInstLowering.lowerOperand(Hi_MOSym, Hi_MCSym);
845 MCInstLowering.lowerOperand(Lo_MOSym, Lo_MCSym);
846
847 MCInst MovZ;
848 MovZ.setOpcode(AArch64::MOVZXi);
849 MovZ.addOperand(MCOperand::createReg(DestReg));
850 MovZ.addOperand(Hi_MCSym);
851 MovZ.addOperand(MCOperand::createImm(16));
852 EmitToStreamer(*OutStreamer, MovZ);
853
854 MCInst MovK;
855 MovK.setOpcode(AArch64::MOVKXi);
856 MovK.addOperand(MCOperand::createReg(DestReg));
857 MovK.addOperand(MCOperand::createReg(DestReg));
858 MovK.addOperand(Lo_MCSym);
859 MovK.addOperand(MCOperand::createImm(0));
860 EmitToStreamer(*OutStreamer, MovK);
861 return;
862 }
Tim Northover6db5d022017-12-20 10:45:39 +0000863 case AArch64::MOVIv2d_ns:
864 // If the target has <rdar://problem/16473581>, lower this
865 // instruction to movi.16b instead.
866 if (STI->hasZeroCycleZeroingFPWorkaround() &&
867 MI->getOperand(1).getImm() == 0) {
868 MCInst TmpInst;
869 TmpInst.setOpcode(AArch64::MOVIv16b_ns);
870 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
871 TmpInst.addOperand(MCOperand::createImm(MI->getOperand(1).getImm()));
872 EmitToStreamer(*OutStreamer, TmpInst);
873 return;
874 }
875 break;
876
Tim Northover3b0846e2014-05-24 12:50:23 +0000877 case AArch64::DBG_VALUE: {
Lang Hames9ff69c82015-04-24 19:11:51 +0000878 if (isVerbose() && OutStreamer->hasRawTextSupport()) {
Tim Northover3b0846e2014-05-24 12:50:23 +0000879 SmallString<128> TmpStr;
880 raw_svector_ostream OS(TmpStr);
881 PrintDebugValueComment(MI, OS);
Lang Hames9ff69c82015-04-24 19:11:51 +0000882 OutStreamer->EmitRawText(StringRef(OS.str()));
Tim Northover3b0846e2014-05-24 12:50:23 +0000883 }
884 return;
Luke Cheeseman41a9e532018-12-21 10:45:08 +0000885
886 case AArch64::EMITBKEY: {
887 ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType();
888 if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
889 ExceptionHandlingType != ExceptionHandling::ARM)
890 return;
891
892 if (needsCFIMoves() == CFI_M_None)
893 return;
894
895 OutStreamer->EmitCFIBKeyFrame();
896 return;
897 }
Tim Northover3b0846e2014-05-24 12:50:23 +0000898 }
899
900 // Tail calls use pseudo instructions so they have the proper code-gen
901 // attributes (isCall, isReturn, etc.). We lower them to the real
902 // instruction here.
Oliver Stannard9ecdac82018-10-08 09:18:48 +0000903 case AArch64::TCRETURNri:
Oliver Stannardc9221162018-10-08 14:09:15 +0000904 case AArch64::TCRETURNriBTI:
Oliver Stannard9ecdac82018-10-08 09:18:48 +0000905 case AArch64::TCRETURNriALL: {
Tim Northover3b0846e2014-05-24 12:50:23 +0000906 MCInst TmpInst;
907 TmpInst.setOpcode(AArch64::BR);
Jim Grosbache9119e42015-05-13 18:37:00 +0000908 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
Lang Hames9ff69c82015-04-24 19:11:51 +0000909 EmitToStreamer(*OutStreamer, TmpInst);
Tim Northover3b0846e2014-05-24 12:50:23 +0000910 return;
911 }
912 case AArch64::TCRETURNdi: {
913 MCOperand Dest;
914 MCInstLowering.lowerOperand(MI->getOperand(0), Dest);
915 MCInst TmpInst;
916 TmpInst.setOpcode(AArch64::B);
917 TmpInst.addOperand(Dest);
Lang Hames9ff69c82015-04-24 19:11:51 +0000918 EmitToStreamer(*OutStreamer, TmpInst);
Tim Northover3b0846e2014-05-24 12:50:23 +0000919 return;
920 }
Kristof Beylsaea84612015-03-04 09:12:08 +0000921 case AArch64::TLSDESC_CALLSEQ: {
922 /// lower this to:
923 /// adrp x0, :tlsdesc:var
924 /// ldr x1, [x0, #:tlsdesc_lo12:var]
925 /// add x0, x0, #:tlsdesc_lo12:var
926 /// .tlsdesccall var
927 /// blr x1
928 /// (TPIDR_EL0 offset now in x0)
929 const MachineOperand &MO_Sym = MI->getOperand(0);
930 MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym);
931 MCOperand Sym, SymTLSDescLo12, SymTLSDesc;
Joel Jones65134052017-05-02 22:01:48 +0000932 MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF);
Kristof Beylsaea84612015-03-04 09:12:08 +0000933 MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE);
934 MCInstLowering.lowerOperand(MO_Sym, Sym);
935 MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12);
936 MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc);
Tim Northover3b0846e2014-05-24 12:50:23 +0000937
Kristof Beylsaea84612015-03-04 09:12:08 +0000938 MCInst Adrp;
939 Adrp.setOpcode(AArch64::ADRP);
Jim Grosbache9119e42015-05-13 18:37:00 +0000940 Adrp.addOperand(MCOperand::createReg(AArch64::X0));
Kristof Beylsaea84612015-03-04 09:12:08 +0000941 Adrp.addOperand(SymTLSDesc);
Lang Hames9ff69c82015-04-24 19:11:51 +0000942 EmitToStreamer(*OutStreamer, Adrp);
Kristof Beylsaea84612015-03-04 09:12:08 +0000943
944 MCInst Ldr;
945 Ldr.setOpcode(AArch64::LDRXui);
Jim Grosbache9119e42015-05-13 18:37:00 +0000946 Ldr.addOperand(MCOperand::createReg(AArch64::X1));
947 Ldr.addOperand(MCOperand::createReg(AArch64::X0));
Kristof Beylsaea84612015-03-04 09:12:08 +0000948 Ldr.addOperand(SymTLSDescLo12);
Jim Grosbache9119e42015-05-13 18:37:00 +0000949 Ldr.addOperand(MCOperand::createImm(0));
Lang Hames9ff69c82015-04-24 19:11:51 +0000950 EmitToStreamer(*OutStreamer, Ldr);
Kristof Beylsaea84612015-03-04 09:12:08 +0000951
952 MCInst Add;
953 Add.setOpcode(AArch64::ADDXri);
Jim Grosbache9119e42015-05-13 18:37:00 +0000954 Add.addOperand(MCOperand::createReg(AArch64::X0));
955 Add.addOperand(MCOperand::createReg(AArch64::X0));
Kristof Beylsaea84612015-03-04 09:12:08 +0000956 Add.addOperand(SymTLSDescLo12);
Jim Grosbache9119e42015-05-13 18:37:00 +0000957 Add.addOperand(MCOperand::createImm(AArch64_AM::getShiftValue(0)));
Lang Hames9ff69c82015-04-24 19:11:51 +0000958 EmitToStreamer(*OutStreamer, Add);
Kristof Beylsaea84612015-03-04 09:12:08 +0000959
960 // Emit a relocation-annotation. This expands to no code, but requests
Tim Northover3b0846e2014-05-24 12:50:23 +0000961 // the following instruction gets an R_AARCH64_TLSDESC_CALL.
962 MCInst TLSDescCall;
963 TLSDescCall.setOpcode(AArch64::TLSDESCCALL);
964 TLSDescCall.addOperand(Sym);
Lang Hames9ff69c82015-04-24 19:11:51 +0000965 EmitToStreamer(*OutStreamer, TLSDescCall);
Tim Northover3b0846e2014-05-24 12:50:23 +0000966
Kristof Beylsaea84612015-03-04 09:12:08 +0000967 MCInst Blr;
968 Blr.setOpcode(AArch64::BLR);
Jim Grosbache9119e42015-05-13 18:37:00 +0000969 Blr.addOperand(MCOperand::createReg(AArch64::X1));
Lang Hames9ff69c82015-04-24 19:11:51 +0000970 EmitToStreamer(*OutStreamer, Blr);
Tim Northover3b0846e2014-05-24 12:50:23 +0000971
972 return;
973 }
974
Tim Northover1c353412018-10-24 20:19:09 +0000975 case AArch64::JumpTableDest32: {
976 // We want:
977 // ldrsw xScratch, [xTable, xEntry, lsl #2]
978 // add xDest, xTable, xScratch
979 unsigned DestReg = MI->getOperand(0).getReg(),
980 ScratchReg = MI->getOperand(1).getReg(),
981 TableReg = MI->getOperand(2).getReg(),
982 EntryReg = MI->getOperand(3).getReg();
983 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRSWroX)
984 .addReg(ScratchReg)
985 .addReg(TableReg)
986 .addReg(EntryReg)
987 .addImm(0)
988 .addImm(1));
989 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXrs)
990 .addReg(DestReg)
991 .addReg(TableReg)
992 .addReg(ScratchReg)
993 .addImm(0));
994 return;
995 }
996 case AArch64::JumpTableDest16:
997 case AArch64::JumpTableDest8:
998 LowerJumpTableDestSmall(*OutStreamer, *MI);
999 return;
1000
Sjoerd Meijerb0eb5fb2017-08-24 14:47:06 +00001001 case AArch64::FMOVH0:
Matthias Braunad0032a2016-07-06 21:39:33 +00001002 case AArch64::FMOVS0:
1003 case AArch64::FMOVD0:
1004 EmitFMov0(*MI);
1005 return;
1006
Tim Northover3b0846e2014-05-24 12:50:23 +00001007 case TargetOpcode::STACKMAP:
Lang Hames9ff69c82015-04-24 19:11:51 +00001008 return LowerSTACKMAP(*OutStreamer, SM, *MI);
Tim Northover3b0846e2014-05-24 12:50:23 +00001009
1010 case TargetOpcode::PATCHPOINT:
Lang Hames9ff69c82015-04-24 19:11:51 +00001011 return LowerPATCHPOINT(*OutStreamer, SM, *MI);
Dean Michael Berris3234d3a2016-11-17 05:15:37 +00001012
1013 case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
1014 LowerPATCHABLE_FUNCTION_ENTER(*MI);
1015 return;
1016
1017 case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
1018 LowerPATCHABLE_FUNCTION_EXIT(*MI);
1019 return;
1020
1021 case TargetOpcode::PATCHABLE_TAIL_CALL:
1022 LowerPATCHABLE_TAIL_CALL(*MI);
1023 return;
Sanjin Sijaric96f2ea32018-10-27 06:13:06 +00001024
Peter Collingbourne73078ec2019-01-23 02:20:10 +00001025 case AArch64::HWASAN_CHECK_MEMACCESS:
1026 LowerHWASAN_CHECK_MEMACCESS(*MI);
1027 return;
1028
Sanjin Sijaric96f2ea32018-10-27 06:13:06 +00001029 case AArch64::SEH_StackAlloc:
1030 TS->EmitARM64WinCFIAllocStack(MI->getOperand(0).getImm());
1031 return;
1032
1033 case AArch64::SEH_SaveFPLR:
1034 TS->EmitARM64WinCFISaveFPLR(MI->getOperand(0).getImm());
1035 return;
1036
1037 case AArch64::SEH_SaveFPLR_X:
1038 assert(MI->getOperand(0).getImm() < 0 &&
1039 "Pre increment SEH opcode must have a negative offset");
1040 TS->EmitARM64WinCFISaveFPLRX(-MI->getOperand(0).getImm());
1041 return;
1042
1043 case AArch64::SEH_SaveReg:
1044 TS->EmitARM64WinCFISaveReg(MI->getOperand(0).getImm(),
1045 MI->getOperand(1).getImm());
1046 return;
1047
1048 case AArch64::SEH_SaveReg_X:
1049 assert(MI->getOperand(1).getImm() < 0 &&
1050 "Pre increment SEH opcode must have a negative offset");
1051 TS->EmitARM64WinCFISaveRegX(MI->getOperand(0).getImm(),
1052 -MI->getOperand(1).getImm());
1053 return;
1054
1055 case AArch64::SEH_SaveRegP:
1056 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
1057 "Non-consecutive registers not allowed for save_regp");
1058 TS->EmitARM64WinCFISaveRegP(MI->getOperand(0).getImm(),
1059 MI->getOperand(2).getImm());
1060 return;
1061
1062 case AArch64::SEH_SaveRegP_X:
1063 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
1064 "Non-consecutive registers not allowed for save_regp_x");
1065 assert(MI->getOperand(2).getImm() < 0 &&
1066 "Pre increment SEH opcode must have a negative offset");
1067 TS->EmitARM64WinCFISaveRegPX(MI->getOperand(0).getImm(),
1068 -MI->getOperand(2).getImm());
1069 return;
1070
1071 case AArch64::SEH_SaveFReg:
1072 TS->EmitARM64WinCFISaveFReg(MI->getOperand(0).getImm(),
1073 MI->getOperand(1).getImm());
1074 return;
1075
1076 case AArch64::SEH_SaveFReg_X:
1077 assert(MI->getOperand(1).getImm() < 0 &&
1078 "Pre increment SEH opcode must have a negative offset");
1079 TS->EmitARM64WinCFISaveFRegX(MI->getOperand(0).getImm(),
1080 -MI->getOperand(1).getImm());
1081 return;
1082
1083 case AArch64::SEH_SaveFRegP:
1084 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
1085 "Non-consecutive registers not allowed for save_regp");
1086 TS->EmitARM64WinCFISaveFRegP(MI->getOperand(0).getImm(),
1087 MI->getOperand(2).getImm());
1088 return;
1089
1090 case AArch64::SEH_SaveFRegP_X:
1091 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
1092 "Non-consecutive registers not allowed for save_regp_x");
1093 assert(MI->getOperand(2).getImm() < 0 &&
1094 "Pre increment SEH opcode must have a negative offset");
1095 TS->EmitARM64WinCFISaveFRegPX(MI->getOperand(0).getImm(),
1096 -MI->getOperand(2).getImm());
1097 return;
1098
1099 case AArch64::SEH_SetFP:
1100 TS->EmitARM64WinCFISetFP();
1101 return;
1102
1103 case AArch64::SEH_AddFP:
1104 TS->EmitARM64WinCFIAddFP(MI->getOperand(0).getImm());
1105 return;
1106
1107 case AArch64::SEH_Nop:
1108 TS->EmitARM64WinCFINop();
1109 return;
1110
1111 case AArch64::SEH_PrologEnd:
1112 TS->EmitARM64WinCFIPrologEnd();
1113 return;
1114
1115 case AArch64::SEH_EpilogStart:
1116 TS->EmitARM64WinCFIEpilogStart();
1117 return;
1118
1119 case AArch64::SEH_EpilogEnd:
1120 TS->EmitARM64WinCFIEpilogEnd();
1121 return;
Tim Northover3b0846e2014-05-24 12:50:23 +00001122 }
1123
1124 // Finally, do the automated lowerings for everything else.
1125 MCInst TmpInst;
1126 MCInstLowering.Lower(MI, TmpInst);
Lang Hames9ff69c82015-04-24 19:11:51 +00001127 EmitToStreamer(*OutStreamer, TmpInst);
Tim Northover3b0846e2014-05-24 12:50:23 +00001128}
1129
1130// Force static initialization.
1131extern "C" void LLVMInitializeAArch64AsmPrinter() {
Mehdi Aminif42454b2016-10-09 23:00:34 +00001132 RegisterAsmPrinter<AArch64AsmPrinter> X(getTheAArch64leTarget());
1133 RegisterAsmPrinter<AArch64AsmPrinter> Y(getTheAArch64beTarget());
1134 RegisterAsmPrinter<AArch64AsmPrinter> Z(getTheARM64Target());
Tim Northover3b0846e2014-05-24 12:50:23 +00001135}