blob: 77a2cdce5dfdfdad40aa3bacde89dc92ffd145d9 [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"
Tim Northover3b0846e2014-05-24 12:50:23 +000020#include "InstPrinter/AArch64InstPrinter.h"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000021#include "MCTargetDesc/AArch64AddressingModes.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,
156 unsigned AsmVariant, const char *ExtraCode,
157 raw_ostream &O) override;
158 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
159 unsigned AsmVariant, const char *ExtraCode,
160 raw_ostream &O) override;
161
162 void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
163
164 void EmitFunctionBodyEnd() override;
165
166 MCSymbol *GetCPISymbol(unsigned CPID) const override;
167 void EmitEndOfAsmFile(Module &M) override;
Eugene Zelenko96d933d2017-07-25 23:51:02 +0000168
169 AArch64FunctionInfo *AArch64FI = nullptr;
Tim Northover3b0846e2014-05-24 12:50:23 +0000170
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000171 /// Emit the LOHs contained in AArch64FI.
Tim Northover3b0846e2014-05-24 12:50:23 +0000172 void EmitLOHs();
173
Matthias Braunad0032a2016-07-06 21:39:33 +0000174 /// Emit instruction to set float register to zero.
175 void EmitFMov0(const MachineInstr &MI);
176
Eugene Zelenko96d933d2017-07-25 23:51:02 +0000177 using MInstToMCSymbol = std::map<const MachineInstr *, MCSymbol *>;
178
Tim Northover3b0846e2014-05-24 12:50:23 +0000179 MInstToMCSymbol LOHInstToLabel;
Tim Northover3b0846e2014-05-24 12:50:23 +0000180};
181
Eugene Zelenko96d933d2017-07-25 23:51:02 +0000182} // end anonymous namespace
Tim Northover3b0846e2014-05-24 12:50:23 +0000183
Dean Michael Berris3234d3a2016-11-17 05:15:37 +0000184void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
185{
186 EmitSled(MI, SledKind::FUNCTION_ENTER);
187}
188
189void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI)
190{
191 EmitSled(MI, SledKind::FUNCTION_EXIT);
192}
193
194void AArch64AsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI)
195{
196 EmitSled(MI, SledKind::TAIL_CALL);
197}
198
Dean Michael Berris3234d3a2016-11-17 05:15:37 +0000199void AArch64AsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind)
200{
201 static const int8_t NoopsInSledCount = 7;
202 // We want to emit the following pattern:
203 //
204 // .Lxray_sled_N:
205 // ALIGN
206 // B #32
207 // ; 7 NOP instructions (28 bytes)
208 // .tmpN
209 //
210 // We need the 28 bytes (7 instructions) because at runtime, we'd be patching
211 // over the full 32 bytes (8 instructions) with the following pattern:
212 //
213 // STP X0, X30, [SP, #-16]! ; push X0 and the link register to the stack
214 // LDR W0, #12 ; W0 := function ID
215 // LDR X16,#12 ; X16 := addr of __xray_FunctionEntry or __xray_FunctionExit
216 // BLR X16 ; call the tracing trampoline
217 // ;DATA: 32 bits of function ID
218 // ;DATA: lower 32 bits of the address of the trampoline
219 // ;DATA: higher 32 bits of the address of the trampoline
220 // LDP X0, X30, [SP], #16 ; pop X0 and the link register from the stack
221 //
222 OutStreamer->EmitCodeAlignment(4);
223 auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
224 OutStreamer->EmitLabel(CurSled);
225 auto Target = OutContext.createTempSymbol();
226
227 // Emit "B #32" instruction, which jumps over the next 28 bytes.
Dean Michael Berris31761f32016-11-21 03:01:43 +0000228 // The operand has to be the number of 4-byte instructions to jump over,
229 // including the current instruction.
230 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::B).addImm(8));
Dean Michael Berris3234d3a2016-11-17 05:15:37 +0000231
232 for (int8_t I = 0; I < NoopsInSledCount; I++)
233 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
234
235 OutStreamer->EmitLabel(Target);
236 recordSled(CurSled, MI, Kind);
237}
238
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000239void AArch64AsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
240 unsigned Reg = MI.getOperand(0).getReg();
241 uint32_t AccessInfo = MI.getOperand(1).getImm();
242 MCSymbol *&Sym = HwasanMemaccessSymbols[{Reg, AccessInfo}];
243 if (!Sym) {
244 // FIXME: Make this work on non-ELF.
245 if (!TM.getTargetTriple().isOSBinFormatELF())
246 report_fatal_error("llvm.hwasan.check.memaccess only supported on ELF");
247
248 std::string SymName = "__hwasan_check_x" + utostr(Reg - AArch64::X0) + "_" +
249 utostr(AccessInfo);
250 Sym = OutContext.getOrCreateSymbol(SymName);
251 }
252
253 EmitToStreamer(*OutStreamer,
254 MCInstBuilder(AArch64::BL)
255 .addExpr(MCSymbolRefExpr::create(Sym, OutContext)));
256}
257
258void AArch64AsmPrinter::EmitHwasanMemaccessSymbols(Module &M) {
259 if (HwasanMemaccessSymbols.empty())
260 return;
261
262 const Triple &TT = TM.getTargetTriple();
263 assert(TT.isOSBinFormatELF());
264 std::unique_ptr<MCSubtargetInfo> STI(
265 TM.getTarget().createMCSubtargetInfo(TT.str(), "", ""));
266
267 MCSymbol *HwasanTagMismatchSym =
268 OutContext.getOrCreateSymbol("__hwasan_tag_mismatch");
269
Mitch Phillips790edbc2019-03-08 21:22:35 +0000270 const MCSymbolRefExpr *HwasanTagMismatchRef =
271 MCSymbolRefExpr::create(HwasanTagMismatchSym, OutContext);
272
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000273 for (auto &P : HwasanMemaccessSymbols) {
274 unsigned Reg = P.first.first;
275 uint32_t AccessInfo = P.first.second;
276 MCSymbol *Sym = P.second;
277
278 OutStreamer->SwitchSection(OutContext.getELFSection(
279 ".text.hot", ELF::SHT_PROGBITS,
280 ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_GROUP, 0,
281 Sym->getName()));
282
283 OutStreamer->EmitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
284 OutStreamer->EmitSymbolAttribute(Sym, MCSA_Weak);
285 OutStreamer->EmitSymbolAttribute(Sym, MCSA_Hidden);
286 OutStreamer->EmitLabel(Sym);
287
288 OutStreamer->EmitInstruction(MCInstBuilder(AArch64::UBFMXri)
289 .addReg(AArch64::X16)
290 .addReg(Reg)
291 .addImm(4)
292 .addImm(55),
293 *STI);
294 OutStreamer->EmitInstruction(MCInstBuilder(AArch64::LDRBBroX)
295 .addReg(AArch64::W16)
296 .addReg(AArch64::X9)
297 .addReg(AArch64::X16)
298 .addImm(0)
299 .addImm(0),
300 *STI);
301 OutStreamer->EmitInstruction(MCInstBuilder(AArch64::UBFMXri)
302 .addReg(AArch64::X17)
303 .addReg(Reg)
304 .addImm(56)
305 .addImm(63),
306 *STI);
307 OutStreamer->EmitInstruction(MCInstBuilder(AArch64::SUBSWrs)
308 .addReg(AArch64::WZR)
309 .addReg(AArch64::W16)
310 .addReg(AArch64::W17)
311 .addImm(0),
312 *STI);
313 MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
314 OutStreamer->EmitInstruction(
315 MCInstBuilder(AArch64::Bcc)
316 .addImm(AArch64CC::NE)
317 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
318 *STI);
319 OutStreamer->EmitInstruction(
320 MCInstBuilder(AArch64::RET).addReg(AArch64::LR), *STI);
321
322 OutStreamer->EmitLabel(HandleMismatchSym);
Mitch Phillips790edbc2019-03-08 21:22:35 +0000323
324 OutStreamer->EmitInstruction(MCInstBuilder(AArch64::STPXpre)
325 .addReg(AArch64::SP)
326 .addReg(AArch64::X0)
327 .addReg(AArch64::X1)
328 .addReg(AArch64::SP)
329 .addImm(-32),
330 *STI);
331 OutStreamer->EmitInstruction(MCInstBuilder(AArch64::STPXi)
332 .addReg(AArch64::FP)
333 .addReg(AArch64::LR)
334 .addReg(AArch64::SP)
335 .addImm(29),
336 *STI);
337
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000338 if (Reg != AArch64::X0)
339 OutStreamer->EmitInstruction(MCInstBuilder(AArch64::ORRXrs)
340 .addReg(AArch64::X0)
341 .addReg(AArch64::XZR)
342 .addReg(Reg)
343 .addImm(0),
344 *STI);
345 OutStreamer->EmitInstruction(MCInstBuilder(AArch64::MOVZXi)
346 .addReg(AArch64::X1)
347 .addImm(AccessInfo)
348 .addImm(0),
349 *STI);
Mitch Phillips790edbc2019-03-08 21:22:35 +0000350
351 // Intentionally load the GOT entry and branch to it, rather than possibly
352 // late binding the function, which may clobber the registers before we have
353 // a chance to save them.
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000354 OutStreamer->EmitInstruction(
Mitch Phillips790edbc2019-03-08 21:22:35 +0000355 MCInstBuilder(AArch64::ADRP)
356 .addReg(AArch64::X16)
357 .addExpr(AArch64MCExpr::create(
358 HwasanTagMismatchRef,
359 AArch64MCExpr::VariantKind::VK_GOT_PAGE, OutContext)),
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000360 *STI);
Mitch Phillips790edbc2019-03-08 21:22:35 +0000361 OutStreamer->EmitInstruction(
362 MCInstBuilder(AArch64::LDRXui)
363 .addReg(AArch64::X16)
364 .addReg(AArch64::X16)
365 .addExpr(AArch64MCExpr::create(
366 HwasanTagMismatchRef,
367 AArch64MCExpr::VariantKind::VK_GOT_LO12, OutContext)),
368 *STI);
369 OutStreamer->EmitInstruction(
370 MCInstBuilder(AArch64::BR).addReg(AArch64::X16), *STI);
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000371 }
372}
373
Tim Northover3b0846e2014-05-24 12:50:23 +0000374void AArch64AsmPrinter::EmitEndOfAsmFile(Module &M) {
Peter Collingbourne73078ec2019-01-23 02:20:10 +0000375 EmitHwasanMemaccessSymbols(M);
376
Daniel Sandersc81f4502015-06-16 15:44:21 +0000377 const Triple &TT = TM.getTargetTriple();
Eric Christopherbb1ae662015-02-03 06:40:19 +0000378 if (TT.isOSBinFormatMachO()) {
Tim Northover3b0846e2014-05-24 12:50:23 +0000379 // Funny Darwin hack: This flag tells the linker that no global symbols
380 // contain code that falls through to other global symbols (e.g. the obvious
381 // implementation of multiple entry points). If this doesn't occur, the
382 // linker can safely perform dead code stripping. Since LLVM never
383 // generates code that does this, it is always safe to set.
Lang Hames9ff69c82015-04-24 19:11:51 +0000384 OutStreamer->EmitAssemblerFlag(MCAF_SubsectionsViaSymbols);
Than McIntosh30c804b2018-11-26 18:43:48 +0000385 emitStackMaps(SM);
Tim Northover3b0846e2014-05-24 12:50:23 +0000386 }
Tim Northover3b0846e2014-05-24 12:50:23 +0000387}
388
Tim Northover3b0846e2014-05-24 12:50:23 +0000389void AArch64AsmPrinter::EmitLOHs() {
390 SmallVector<MCSymbol *, 3> MCArgs;
391
392 for (const auto &D : AArch64FI->getLOHContainer()) {
393 for (const MachineInstr *MI : D.getArgs()) {
394 MInstToMCSymbol::iterator LabelIt = LOHInstToLabel.find(MI);
395 assert(LabelIt != LOHInstToLabel.end() &&
396 "Label hasn't been inserted for LOH related instruction");
397 MCArgs.push_back(LabelIt->second);
398 }
Lang Hames9ff69c82015-04-24 19:11:51 +0000399 OutStreamer->EmitLOHDirective(D.getKind(), MCArgs);
Tim Northover3b0846e2014-05-24 12:50:23 +0000400 MCArgs.clear();
401 }
402}
403
404void AArch64AsmPrinter::EmitFunctionBodyEnd() {
405 if (!AArch64FI->getLOHRelated().empty())
406 EmitLOHs();
407}
408
409/// GetCPISymbol - Return the symbol for the specified constant pool entry.
410MCSymbol *AArch64AsmPrinter::GetCPISymbol(unsigned CPID) const {
411 // Darwin uses a linker-private symbol name for constant-pools (to
412 // avoid addends on the relocation?), ELF has no such concept and
413 // uses a normal private symbol.
Mehdi Amini48878ae2016-10-01 05:57:55 +0000414 if (!getDataLayout().getLinkerPrivateGlobalPrefix().empty())
Jim Grosbach6f482002015-05-18 18:43:14 +0000415 return OutContext.getOrCreateSymbol(
Tim Northover3b0846e2014-05-24 12:50:23 +0000416 Twine(getDataLayout().getLinkerPrivateGlobalPrefix()) + "CPI" +
417 Twine(getFunctionNumber()) + "_" + Twine(CPID));
418
Martin Storsjod2662c32018-07-25 18:35:31 +0000419 return AsmPrinter::GetCPISymbol(CPID);
Tim Northover3b0846e2014-05-24 12:50:23 +0000420}
421
422void AArch64AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNum,
423 raw_ostream &O) {
424 const MachineOperand &MO = MI->getOperand(OpNum);
425 switch (MO.getType()) {
426 default:
Craig Topper2a30d782014-06-18 05:05:13 +0000427 llvm_unreachable("<unknown operand type>");
Tim Northover3b0846e2014-05-24 12:50:23 +0000428 case MachineOperand::MO_Register: {
429 unsigned Reg = MO.getReg();
430 assert(TargetRegisterInfo::isPhysicalRegister(Reg));
431 assert(!MO.getSubReg() && "Subregs should be eliminated!");
432 O << AArch64InstPrinter::getRegisterName(Reg);
433 break;
434 }
435 case MachineOperand::MO_Immediate: {
436 int64_t Imm = MO.getImm();
437 O << '#' << Imm;
438 break;
439 }
Ahmed Bougacha1b676302015-03-05 20:04:21 +0000440 case MachineOperand::MO_GlobalAddress: {
441 const GlobalValue *GV = MO.getGlobal();
442 MCSymbol *Sym = getSymbol(GV);
443
444 // FIXME: Can we get anything other than a plain symbol here?
445 assert(!MO.getTargetFlags() && "Unknown operand target flag!");
446
Matt Arsenault8b643552015-06-09 00:31:39 +0000447 Sym->print(O, MAI);
Ahmed Bougacha1b676302015-03-05 20:04:21 +0000448 printOffset(MO.getOffset(), O);
449 break;
450 }
Peter Smithc8117582018-05-16 09:33:25 +0000451 case MachineOperand::MO_BlockAddress: {
452 MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());
453 Sym->print(O, MAI);
454 break;
455 }
Tim Northover3b0846e2014-05-24 12:50:23 +0000456 }
457}
458
459bool AArch64AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode,
460 raw_ostream &O) {
461 unsigned Reg = MO.getReg();
462 switch (Mode) {
463 default:
464 return true; // Unknown mode.
465 case 'w':
466 Reg = getWRegFromXReg(Reg);
467 break;
468 case 'x':
469 Reg = getXRegFromWReg(Reg);
470 break;
471 }
472
473 O << AArch64InstPrinter::getRegisterName(Reg);
474 return false;
475}
476
477// Prints the register in MO using class RC using the offset in the
478// new register class. This should not be used for cross class
479// printing.
480bool AArch64AsmPrinter::printAsmRegInClass(const MachineOperand &MO,
481 const TargetRegisterClass *RC,
482 bool isVector, raw_ostream &O) {
483 assert(MO.isReg() && "Should only get here with a register!");
Matthias Braunad0032a2016-07-06 21:39:33 +0000484 const TargetRegisterInfo *RI = STI->getRegisterInfo();
Tim Northover3b0846e2014-05-24 12:50:23 +0000485 unsigned Reg = MO.getReg();
486 unsigned RegToPrint = RC->getRegister(RI->getEncodingValue(Reg));
487 assert(RI->regsOverlap(RegToPrint, Reg));
488 O << AArch64InstPrinter::getRegisterName(
489 RegToPrint, isVector ? AArch64::vreg : AArch64::NoRegAltName);
490 return false;
491}
492
493bool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
494 unsigned AsmVariant,
495 const char *ExtraCode, raw_ostream &O) {
496 const MachineOperand &MO = MI->getOperand(OpNum);
Tim Northover47190412014-05-27 07:37:21 +0000497
498 // First try the generic code, which knows about modifiers like 'c' and 'n'.
499 if (!AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O))
500 return false;
501
Tim Northover3b0846e2014-05-24 12:50:23 +0000502 // Does this asm operand have a single letter operand modifier?
503 if (ExtraCode && ExtraCode[0]) {
504 if (ExtraCode[1] != 0)
505 return true; // Unknown modifier.
506
507 switch (ExtraCode[0]) {
508 default:
509 return true; // Unknown modifier.
Manoj Guptad5361802017-05-25 19:07:57 +0000510 case 'a': // Print 'a' modifier
511 PrintAsmMemoryOperand(MI, OpNum, AsmVariant, ExtraCode, O);
512 return false;
Tim Northover3b0846e2014-05-24 12:50:23 +0000513 case 'w': // Print W register
514 case 'x': // Print X register
515 if (MO.isReg())
516 return printAsmMRegister(MO, ExtraCode[0], O);
517 if (MO.isImm() && MO.getImm() == 0) {
518 unsigned Reg = ExtraCode[0] == 'w' ? AArch64::WZR : AArch64::XZR;
519 O << AArch64InstPrinter::getRegisterName(Reg);
520 return false;
521 }
522 printOperand(MI, OpNum, O);
523 return false;
524 case 'b': // Print B register.
525 case 'h': // Print H register.
526 case 's': // Print S register.
527 case 'd': // Print D register.
528 case 'q': // Print Q register.
529 if (MO.isReg()) {
530 const TargetRegisterClass *RC;
531 switch (ExtraCode[0]) {
532 case 'b':
533 RC = &AArch64::FPR8RegClass;
534 break;
535 case 'h':
536 RC = &AArch64::FPR16RegClass;
537 break;
538 case 's':
539 RC = &AArch64::FPR32RegClass;
540 break;
541 case 'd':
542 RC = &AArch64::FPR64RegClass;
543 break;
544 case 'q':
545 RC = &AArch64::FPR128RegClass;
546 break;
547 default:
548 return true;
549 }
550 return printAsmRegInClass(MO, RC, false /* vector */, O);
551 }
552 printOperand(MI, OpNum, O);
553 return false;
554 }
555 }
556
557 // According to ARM, we should emit x and v registers unless we have a
558 // modifier.
559 if (MO.isReg()) {
560 unsigned Reg = MO.getReg();
561
562 // If this is a w or x register, print an x register.
563 if (AArch64::GPR32allRegClass.contains(Reg) ||
564 AArch64::GPR64allRegClass.contains(Reg))
565 return printAsmMRegister(MO, 'x', O);
566
567 // If this is a b, h, s, d, or q register, print it as a v register.
568 return printAsmRegInClass(MO, &AArch64::FPR128RegClass, true /* vector */,
569 O);
570 }
571
572 printOperand(MI, OpNum, O);
573 return false;
574}
575
576bool AArch64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
577 unsigned OpNum,
578 unsigned AsmVariant,
579 const char *ExtraCode,
580 raw_ostream &O) {
Manoj Guptad5361802017-05-25 19:07:57 +0000581 if (ExtraCode && ExtraCode[0] && ExtraCode[0] != 'a')
Tim Northover3b0846e2014-05-24 12:50:23 +0000582 return true; // Unknown modifier.
583
584 const MachineOperand &MO = MI->getOperand(OpNum);
585 assert(MO.isReg() && "unexpected inline asm memory operand");
586 O << "[" << AArch64InstPrinter::getRegisterName(MO.getReg()) << "]";
587 return false;
588}
589
590void AArch64AsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
591 raw_ostream &OS) {
592 unsigned NOps = MI->getNumOperands();
593 assert(NOps == 4);
594 OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: ";
595 // cast away const; DIetc do not take const operands for some reason.
Duncan P. N. Exon Smitha9308c42015-04-29 16:38:44 +0000596 OS << cast<DILocalVariable>(MI->getOperand(NOps - 2).getMetadata())
Duncan P. N. Exon Smith7348dda2015-04-14 02:22:36 +0000597 ->getName();
Tim Northover3b0846e2014-05-24 12:50:23 +0000598 OS << " <- ";
599 // Frame address. Currently handles register +- offset only.
600 assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm());
601 OS << '[';
602 printOperand(MI, 0, OS);
603 OS << '+';
604 printOperand(MI, 1, OS);
605 OS << ']';
606 OS << "+";
607 printOperand(MI, NOps - 2, OS);
608}
609
Tim Northover1c353412018-10-24 20:19:09 +0000610void AArch64AsmPrinter::EmitJumpTableInfo() {
611 const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
612 if (!MJTI) return;
613
614 const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
615 if (JT.empty()) return;
616
Martin Storsjof5884d22019-01-29 09:36:48 +0000617 const Function &F = MF->getFunction();
Tim Northover1c353412018-10-24 20:19:09 +0000618 const TargetLoweringObjectFile &TLOF = getObjFileLowering();
Martin Storsjof5884d22019-01-29 09:36:48 +0000619 bool JTInDiffSection =
620 !STI->isTargetCOFF() ||
621 !TLOF.shouldPutJumpTableInFunctionSection(
622 MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32,
623 F);
624 if (JTInDiffSection) {
625 // Drop it in the readonly section.
626 MCSection *ReadOnlySec = TLOF.getSectionForJumpTable(F, TM);
627 OutStreamer->SwitchSection(ReadOnlySec);
628 }
Tim Northover1c353412018-10-24 20:19:09 +0000629
630 auto AFI = MF->getInfo<AArch64FunctionInfo>();
631 for (unsigned JTI = 0, e = JT.size(); JTI != e; ++JTI) {
632 const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
633
634 // If this jump table was deleted, ignore it.
635 if (JTBBs.empty()) continue;
636
637 unsigned Size = AFI->getJumpTableEntrySize(JTI);
638 EmitAlignment(Log2_32(Size));
639 OutStreamer->EmitLabel(GetJTISymbol(JTI));
640
641 for (auto *JTBB : JTBBs)
642 emitJumpTableEntry(MJTI, JTBB, JTI);
643 }
644}
645
646void AArch64AsmPrinter::emitJumpTableEntry(const MachineJumpTableInfo *MJTI,
647 const MachineBasicBlock *MBB,
648 unsigned JTI) {
649 const MCExpr *Value = MCSymbolRefExpr::create(MBB->getSymbol(), OutContext);
650 auto AFI = MF->getInfo<AArch64FunctionInfo>();
651 unsigned Size = AFI->getJumpTableEntrySize(JTI);
652
653 if (Size == 4) {
654 // .word LBB - LJTI
655 const TargetLowering *TLI = MF->getSubtarget().getTargetLowering();
656 const MCExpr *Base = TLI->getPICJumpTableRelocBaseExpr(MF, JTI, OutContext);
657 Value = MCBinaryExpr::createSub(Value, Base, OutContext);
658 } else {
659 // .byte (LBB - LBB) >> 2 (or .hword)
660 const MCSymbol *BaseSym = AFI->getJumpTableEntryPCRelSymbol(JTI);
661 const MCExpr *Base = MCSymbolRefExpr::create(BaseSym, OutContext);
662 Value = MCBinaryExpr::createSub(Value, Base, OutContext);
663 Value = MCBinaryExpr::createLShr(
664 Value, MCConstantExpr::create(2, OutContext), OutContext);
665 }
666
667 OutStreamer->EmitValue(Value, Size);
668}
669
670/// Small jump tables contain an unsigned byte or half, representing the offset
671/// from the lowest-addressed possible destination to the desired basic
672/// block. Since all instructions are 4-byte aligned, this is further compressed
673/// by counting in instructions rather than bytes (i.e. divided by 4). So, to
674/// materialize the correct destination we need:
675///
676/// adr xDest, .LBB0_0
677/// ldrb wScratch, [xTable, xEntry] (with "lsl #1" for ldrh).
678/// add xDest, xDest, xScratch, lsl #2
679void AArch64AsmPrinter::LowerJumpTableDestSmall(llvm::MCStreamer &OutStreamer,
680 const llvm::MachineInstr &MI) {
681 unsigned DestReg = MI.getOperand(0).getReg();
682 unsigned ScratchReg = MI.getOperand(1).getReg();
683 unsigned ScratchRegW =
684 STI->getRegisterInfo()->getSubReg(ScratchReg, AArch64::sub_32);
685 unsigned TableReg = MI.getOperand(2).getReg();
686 unsigned EntryReg = MI.getOperand(3).getReg();
687 int JTIdx = MI.getOperand(4).getIndex();
688 bool IsByteEntry = MI.getOpcode() == AArch64::JumpTableDest8;
689
690 // This has to be first because the compression pass based its reachability
691 // calculations on the start of the JumpTableDest instruction.
692 auto Label =
693 MF->getInfo<AArch64FunctionInfo>()->getJumpTableEntryPCRelSymbol(JTIdx);
694 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADR)
695 .addReg(DestReg)
696 .addExpr(MCSymbolRefExpr::create(
697 Label, MF->getContext())));
698
699 // Load the number of instruction-steps to offset from the label.
700 unsigned LdrOpcode = IsByteEntry ? AArch64::LDRBBroX : AArch64::LDRHHroX;
701 EmitToStreamer(OutStreamer, MCInstBuilder(LdrOpcode)
702 .addReg(ScratchRegW)
703 .addReg(TableReg)
704 .addReg(EntryReg)
705 .addImm(0)
706 .addImm(IsByteEntry ? 0 : 1));
707
708 // Multiply the steps by 4 and add to the already materialized base label
709 // address.
710 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADDXrs)
711 .addReg(DestReg)
712 .addReg(DestReg)
713 .addReg(ScratchReg)
714 .addImm(2));
715}
716
Tim Northover3b0846e2014-05-24 12:50:23 +0000717void AArch64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
718 const MachineInstr &MI) {
Diana Picus760c7572016-08-31 12:43:49 +0000719 unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes();
Tim Northover3b0846e2014-05-24 12:50:23 +0000720
721 SM.recordStackMap(MI);
Tim Northover3b0846e2014-05-24 12:50:23 +0000722 assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
Lang Hamesa7395bf2014-12-02 21:36:24 +0000723
724 // Scan ahead to trim the shadow.
725 const MachineBasicBlock &MBB = *MI.getParent();
726 MachineBasicBlock::const_iterator MII(MI);
727 ++MII;
728 while (NumNOPBytes > 0) {
729 if (MII == MBB.end() || MII->isCall() ||
730 MII->getOpcode() == AArch64::DBG_VALUE ||
731 MII->getOpcode() == TargetOpcode::PATCHPOINT ||
732 MII->getOpcode() == TargetOpcode::STACKMAP)
733 break;
734 ++MII;
735 NumNOPBytes -= 4;
736 }
737
738 // Emit nops.
Tim Northover3b0846e2014-05-24 12:50:23 +0000739 for (unsigned i = 0; i < NumNOPBytes; i += 4)
740 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
741}
742
743// Lower a patchpoint of the form:
744// [<def>], <id>, <numBytes>, <target>, <numArgs>
745void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
746 const MachineInstr &MI) {
747 SM.recordPatchPoint(MI);
748
749 PatchPointOpers Opers(&MI);
750
Philip Reamese83c4b32016-08-23 23:33:29 +0000751 int64_t CallTarget = Opers.getCallTarget().getImm();
Tim Northover3b0846e2014-05-24 12:50:23 +0000752 unsigned EncodedBytes = 0;
753 if (CallTarget) {
754 assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget &&
755 "High 16 bits of call target should be zero.");
756 unsigned ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg();
757 EncodedBytes = 16;
758 // Materialize the jump address:
Tim Northover389a1e32016-06-15 20:33:36 +0000759 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVZXi)
Tim Northover3b0846e2014-05-24 12:50:23 +0000760 .addReg(ScratchReg)
761 .addImm((CallTarget >> 32) & 0xFFFF)
762 .addImm(32));
Tim Northover389a1e32016-06-15 20:33:36 +0000763 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi)
Tim Northover3b0846e2014-05-24 12:50:23 +0000764 .addReg(ScratchReg)
765 .addReg(ScratchReg)
766 .addImm((CallTarget >> 16) & 0xFFFF)
767 .addImm(16));
Tim Northover389a1e32016-06-15 20:33:36 +0000768 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi)
Tim Northover3b0846e2014-05-24 12:50:23 +0000769 .addReg(ScratchReg)
770 .addReg(ScratchReg)
771 .addImm(CallTarget & 0xFFFF)
772 .addImm(0));
773 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::BLR).addReg(ScratchReg));
774 }
775 // Emit padding.
Philip Reamese83c4b32016-08-23 23:33:29 +0000776 unsigned NumBytes = Opers.getNumPatchBytes();
Tim Northover3b0846e2014-05-24 12:50:23 +0000777 assert(NumBytes >= EncodedBytes &&
778 "Patchpoint can't request size less than the length of a call.");
779 assert((NumBytes - EncodedBytes) % 4 == 0 &&
780 "Invalid number of NOP bytes requested!");
781 for (unsigned i = EncodedBytes; i < NumBytes; i += 4)
782 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
783}
784
Matthias Braunad0032a2016-07-06 21:39:33 +0000785void AArch64AsmPrinter::EmitFMov0(const MachineInstr &MI) {
786 unsigned DestReg = MI.getOperand(0).getReg();
Evandro Menezesfc1852f2018-09-28 19:05:09 +0000787 if (STI->hasZeroCycleZeroingFP() && !STI->hasZeroCycleZeroingFPWorkaround()) {
Sjoerd Meijerb0eb5fb2017-08-24 14:47:06 +0000788 // Convert H/S/D register to corresponding Q register
789 if (AArch64::H0 <= DestReg && DestReg <= AArch64::H31)
790 DestReg = AArch64::Q0 + (DestReg - AArch64::H0);
791 else if (AArch64::S0 <= DestReg && DestReg <= AArch64::S31)
Matthias Braunad0032a2016-07-06 21:39:33 +0000792 DestReg = AArch64::Q0 + (DestReg - AArch64::S0);
Sjoerd Meijerb0eb5fb2017-08-24 14:47:06 +0000793 else {
Matthias Braunad0032a2016-07-06 21:39:33 +0000794 assert(AArch64::D0 <= DestReg && DestReg <= AArch64::D31);
795 DestReg = AArch64::Q0 + (DestReg - AArch64::D0);
796 }
797 MCInst MOVI;
798 MOVI.setOpcode(AArch64::MOVIv2d_ns);
799 MOVI.addOperand(MCOperand::createReg(DestReg));
800 MOVI.addOperand(MCOperand::createImm(0));
801 EmitToStreamer(*OutStreamer, MOVI);
802 } else {
803 MCInst FMov;
804 switch (MI.getOpcode()) {
805 default: llvm_unreachable("Unexpected opcode");
Sjoerd Meijerb0eb5fb2017-08-24 14:47:06 +0000806 case AArch64::FMOVH0:
807 FMov.setOpcode(AArch64::FMOVWHr);
808 FMov.addOperand(MCOperand::createReg(DestReg));
809 FMov.addOperand(MCOperand::createReg(AArch64::WZR));
810 break;
Matthias Braunad0032a2016-07-06 21:39:33 +0000811 case AArch64::FMOVS0:
812 FMov.setOpcode(AArch64::FMOVWSr);
813 FMov.addOperand(MCOperand::createReg(DestReg));
814 FMov.addOperand(MCOperand::createReg(AArch64::WZR));
815 break;
816 case AArch64::FMOVD0:
817 FMov.setOpcode(AArch64::FMOVXDr);
818 FMov.addOperand(MCOperand::createReg(DestReg));
819 FMov.addOperand(MCOperand::createReg(AArch64::XZR));
820 break;
821 }
822 EmitToStreamer(*OutStreamer, FMov);
823 }
824}
825
Tim Northover3b0846e2014-05-24 12:50:23 +0000826// Simple pseudo-instructions have their lowering (with expansion to real
827// instructions) auto-generated.
828#include "AArch64GenMCPseudoLowering.inc"
829
830void AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
831 // Do any auto-generated pseudo lowerings.
Lang Hames9ff69c82015-04-24 19:11:51 +0000832 if (emitPseudoExpansionLowering(*OutStreamer, MI))
Tim Northover3b0846e2014-05-24 12:50:23 +0000833 return;
834
835 if (AArch64FI->getLOHRelated().count(MI)) {
836 // Generate a label for LOH related instruction
Rafael Espindola9ab09232015-03-17 20:07:06 +0000837 MCSymbol *LOHLabel = createTempSymbol("loh");
Tim Northover3b0846e2014-05-24 12:50:23 +0000838 // Associate the instruction with the label
839 LOHInstToLabel[MI] = LOHLabel;
Lang Hames9ff69c82015-04-24 19:11:51 +0000840 OutStreamer->EmitLabel(LOHLabel);
Tim Northover3b0846e2014-05-24 12:50:23 +0000841 }
842
Sanjin Sijaric96f2ea32018-10-27 06:13:06 +0000843 AArch64TargetStreamer *TS =
844 static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
Tim Northover3b0846e2014-05-24 12:50:23 +0000845 // Do any manual lowerings.
846 switch (MI->getOpcode()) {
847 default:
848 break;
Mandeep Singh Grang33c49c02019-01-16 19:52:59 +0000849 case AArch64::MOVMCSym: {
850 unsigned DestReg = MI->getOperand(0).getReg();
851 const MachineOperand &MO_Sym = MI->getOperand(1);
852 MachineOperand Hi_MOSym(MO_Sym), Lo_MOSym(MO_Sym);
853 MCOperand Hi_MCSym, Lo_MCSym;
854
855 Hi_MOSym.setTargetFlags(AArch64II::MO_G1 | AArch64II::MO_S);
856 Lo_MOSym.setTargetFlags(AArch64II::MO_G0 | AArch64II::MO_NC);
857
858 MCInstLowering.lowerOperand(Hi_MOSym, Hi_MCSym);
859 MCInstLowering.lowerOperand(Lo_MOSym, Lo_MCSym);
860
861 MCInst MovZ;
862 MovZ.setOpcode(AArch64::MOVZXi);
863 MovZ.addOperand(MCOperand::createReg(DestReg));
864 MovZ.addOperand(Hi_MCSym);
865 MovZ.addOperand(MCOperand::createImm(16));
866 EmitToStreamer(*OutStreamer, MovZ);
867
868 MCInst MovK;
869 MovK.setOpcode(AArch64::MOVKXi);
870 MovK.addOperand(MCOperand::createReg(DestReg));
871 MovK.addOperand(MCOperand::createReg(DestReg));
872 MovK.addOperand(Lo_MCSym);
873 MovK.addOperand(MCOperand::createImm(0));
874 EmitToStreamer(*OutStreamer, MovK);
875 return;
876 }
Tim Northover6db5d022017-12-20 10:45:39 +0000877 case AArch64::MOVIv2d_ns:
878 // If the target has <rdar://problem/16473581>, lower this
879 // instruction to movi.16b instead.
880 if (STI->hasZeroCycleZeroingFPWorkaround() &&
881 MI->getOperand(1).getImm() == 0) {
882 MCInst TmpInst;
883 TmpInst.setOpcode(AArch64::MOVIv16b_ns);
884 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
885 TmpInst.addOperand(MCOperand::createImm(MI->getOperand(1).getImm()));
886 EmitToStreamer(*OutStreamer, TmpInst);
887 return;
888 }
889 break;
890
Tim Northover3b0846e2014-05-24 12:50:23 +0000891 case AArch64::DBG_VALUE: {
Lang Hames9ff69c82015-04-24 19:11:51 +0000892 if (isVerbose() && OutStreamer->hasRawTextSupport()) {
Tim Northover3b0846e2014-05-24 12:50:23 +0000893 SmallString<128> TmpStr;
894 raw_svector_ostream OS(TmpStr);
895 PrintDebugValueComment(MI, OS);
Lang Hames9ff69c82015-04-24 19:11:51 +0000896 OutStreamer->EmitRawText(StringRef(OS.str()));
Tim Northover3b0846e2014-05-24 12:50:23 +0000897 }
898 return;
Luke Cheeseman41a9e532018-12-21 10:45:08 +0000899
900 case AArch64::EMITBKEY: {
901 ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType();
902 if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
903 ExceptionHandlingType != ExceptionHandling::ARM)
904 return;
905
906 if (needsCFIMoves() == CFI_M_None)
907 return;
908
909 OutStreamer->EmitCFIBKeyFrame();
910 return;
911 }
Tim Northover3b0846e2014-05-24 12:50:23 +0000912 }
913
914 // Tail calls use pseudo instructions so they have the proper code-gen
915 // attributes (isCall, isReturn, etc.). We lower them to the real
916 // instruction here.
Oliver Stannard9ecdac82018-10-08 09:18:48 +0000917 case AArch64::TCRETURNri:
Oliver Stannardc9221162018-10-08 14:09:15 +0000918 case AArch64::TCRETURNriBTI:
Oliver Stannard9ecdac82018-10-08 09:18:48 +0000919 case AArch64::TCRETURNriALL: {
Tim Northover3b0846e2014-05-24 12:50:23 +0000920 MCInst TmpInst;
921 TmpInst.setOpcode(AArch64::BR);
Jim Grosbache9119e42015-05-13 18:37:00 +0000922 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
Lang Hames9ff69c82015-04-24 19:11:51 +0000923 EmitToStreamer(*OutStreamer, TmpInst);
Tim Northover3b0846e2014-05-24 12:50:23 +0000924 return;
925 }
926 case AArch64::TCRETURNdi: {
927 MCOperand Dest;
928 MCInstLowering.lowerOperand(MI->getOperand(0), Dest);
929 MCInst TmpInst;
930 TmpInst.setOpcode(AArch64::B);
931 TmpInst.addOperand(Dest);
Lang Hames9ff69c82015-04-24 19:11:51 +0000932 EmitToStreamer(*OutStreamer, TmpInst);
Tim Northover3b0846e2014-05-24 12:50:23 +0000933 return;
934 }
Kristof Beylsaea84612015-03-04 09:12:08 +0000935 case AArch64::TLSDESC_CALLSEQ: {
936 /// lower this to:
937 /// adrp x0, :tlsdesc:var
938 /// ldr x1, [x0, #:tlsdesc_lo12:var]
939 /// add x0, x0, #:tlsdesc_lo12:var
940 /// .tlsdesccall var
941 /// blr x1
942 /// (TPIDR_EL0 offset now in x0)
943 const MachineOperand &MO_Sym = MI->getOperand(0);
944 MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym);
945 MCOperand Sym, SymTLSDescLo12, SymTLSDesc;
Joel Jones65134052017-05-02 22:01:48 +0000946 MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF);
Kristof Beylsaea84612015-03-04 09:12:08 +0000947 MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE);
948 MCInstLowering.lowerOperand(MO_Sym, Sym);
949 MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12);
950 MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc);
Tim Northover3b0846e2014-05-24 12:50:23 +0000951
Kristof Beylsaea84612015-03-04 09:12:08 +0000952 MCInst Adrp;
953 Adrp.setOpcode(AArch64::ADRP);
Jim Grosbache9119e42015-05-13 18:37:00 +0000954 Adrp.addOperand(MCOperand::createReg(AArch64::X0));
Kristof Beylsaea84612015-03-04 09:12:08 +0000955 Adrp.addOperand(SymTLSDesc);
Lang Hames9ff69c82015-04-24 19:11:51 +0000956 EmitToStreamer(*OutStreamer, Adrp);
Kristof Beylsaea84612015-03-04 09:12:08 +0000957
958 MCInst Ldr;
959 Ldr.setOpcode(AArch64::LDRXui);
Jim Grosbache9119e42015-05-13 18:37:00 +0000960 Ldr.addOperand(MCOperand::createReg(AArch64::X1));
961 Ldr.addOperand(MCOperand::createReg(AArch64::X0));
Kristof Beylsaea84612015-03-04 09:12:08 +0000962 Ldr.addOperand(SymTLSDescLo12);
Jim Grosbache9119e42015-05-13 18:37:00 +0000963 Ldr.addOperand(MCOperand::createImm(0));
Lang Hames9ff69c82015-04-24 19:11:51 +0000964 EmitToStreamer(*OutStreamer, Ldr);
Kristof Beylsaea84612015-03-04 09:12:08 +0000965
966 MCInst Add;
967 Add.setOpcode(AArch64::ADDXri);
Jim Grosbache9119e42015-05-13 18:37:00 +0000968 Add.addOperand(MCOperand::createReg(AArch64::X0));
969 Add.addOperand(MCOperand::createReg(AArch64::X0));
Kristof Beylsaea84612015-03-04 09:12:08 +0000970 Add.addOperand(SymTLSDescLo12);
Jim Grosbache9119e42015-05-13 18:37:00 +0000971 Add.addOperand(MCOperand::createImm(AArch64_AM::getShiftValue(0)));
Lang Hames9ff69c82015-04-24 19:11:51 +0000972 EmitToStreamer(*OutStreamer, Add);
Kristof Beylsaea84612015-03-04 09:12:08 +0000973
974 // Emit a relocation-annotation. This expands to no code, but requests
Tim Northover3b0846e2014-05-24 12:50:23 +0000975 // the following instruction gets an R_AARCH64_TLSDESC_CALL.
976 MCInst TLSDescCall;
977 TLSDescCall.setOpcode(AArch64::TLSDESCCALL);
978 TLSDescCall.addOperand(Sym);
Lang Hames9ff69c82015-04-24 19:11:51 +0000979 EmitToStreamer(*OutStreamer, TLSDescCall);
Tim Northover3b0846e2014-05-24 12:50:23 +0000980
Kristof Beylsaea84612015-03-04 09:12:08 +0000981 MCInst Blr;
982 Blr.setOpcode(AArch64::BLR);
Jim Grosbache9119e42015-05-13 18:37:00 +0000983 Blr.addOperand(MCOperand::createReg(AArch64::X1));
Lang Hames9ff69c82015-04-24 19:11:51 +0000984 EmitToStreamer(*OutStreamer, Blr);
Tim Northover3b0846e2014-05-24 12:50:23 +0000985
986 return;
987 }
988
Tim Northover1c353412018-10-24 20:19:09 +0000989 case AArch64::JumpTableDest32: {
990 // We want:
991 // ldrsw xScratch, [xTable, xEntry, lsl #2]
992 // add xDest, xTable, xScratch
993 unsigned DestReg = MI->getOperand(0).getReg(),
994 ScratchReg = MI->getOperand(1).getReg(),
995 TableReg = MI->getOperand(2).getReg(),
996 EntryReg = MI->getOperand(3).getReg();
997 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRSWroX)
998 .addReg(ScratchReg)
999 .addReg(TableReg)
1000 .addReg(EntryReg)
1001 .addImm(0)
1002 .addImm(1));
1003 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXrs)
1004 .addReg(DestReg)
1005 .addReg(TableReg)
1006 .addReg(ScratchReg)
1007 .addImm(0));
1008 return;
1009 }
1010 case AArch64::JumpTableDest16:
1011 case AArch64::JumpTableDest8:
1012 LowerJumpTableDestSmall(*OutStreamer, *MI);
1013 return;
1014
Sjoerd Meijerb0eb5fb2017-08-24 14:47:06 +00001015 case AArch64::FMOVH0:
Matthias Braunad0032a2016-07-06 21:39:33 +00001016 case AArch64::FMOVS0:
1017 case AArch64::FMOVD0:
1018 EmitFMov0(*MI);
1019 return;
1020
Tim Northover3b0846e2014-05-24 12:50:23 +00001021 case TargetOpcode::STACKMAP:
Lang Hames9ff69c82015-04-24 19:11:51 +00001022 return LowerSTACKMAP(*OutStreamer, SM, *MI);
Tim Northover3b0846e2014-05-24 12:50:23 +00001023
1024 case TargetOpcode::PATCHPOINT:
Lang Hames9ff69c82015-04-24 19:11:51 +00001025 return LowerPATCHPOINT(*OutStreamer, SM, *MI);
Dean Michael Berris3234d3a2016-11-17 05:15:37 +00001026
1027 case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
1028 LowerPATCHABLE_FUNCTION_ENTER(*MI);
1029 return;
1030
1031 case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
1032 LowerPATCHABLE_FUNCTION_EXIT(*MI);
1033 return;
1034
1035 case TargetOpcode::PATCHABLE_TAIL_CALL:
1036 LowerPATCHABLE_TAIL_CALL(*MI);
1037 return;
Sanjin Sijaric96f2ea32018-10-27 06:13:06 +00001038
Peter Collingbourne73078ec2019-01-23 02:20:10 +00001039 case AArch64::HWASAN_CHECK_MEMACCESS:
1040 LowerHWASAN_CHECK_MEMACCESS(*MI);
1041 return;
1042
Sanjin Sijaric96f2ea32018-10-27 06:13:06 +00001043 case AArch64::SEH_StackAlloc:
1044 TS->EmitARM64WinCFIAllocStack(MI->getOperand(0).getImm());
1045 return;
1046
1047 case AArch64::SEH_SaveFPLR:
1048 TS->EmitARM64WinCFISaveFPLR(MI->getOperand(0).getImm());
1049 return;
1050
1051 case AArch64::SEH_SaveFPLR_X:
1052 assert(MI->getOperand(0).getImm() < 0 &&
1053 "Pre increment SEH opcode must have a negative offset");
1054 TS->EmitARM64WinCFISaveFPLRX(-MI->getOperand(0).getImm());
1055 return;
1056
1057 case AArch64::SEH_SaveReg:
1058 TS->EmitARM64WinCFISaveReg(MI->getOperand(0).getImm(),
1059 MI->getOperand(1).getImm());
1060 return;
1061
1062 case AArch64::SEH_SaveReg_X:
1063 assert(MI->getOperand(1).getImm() < 0 &&
1064 "Pre increment SEH opcode must have a negative offset");
1065 TS->EmitARM64WinCFISaveRegX(MI->getOperand(0).getImm(),
1066 -MI->getOperand(1).getImm());
1067 return;
1068
1069 case AArch64::SEH_SaveRegP:
1070 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
1071 "Non-consecutive registers not allowed for save_regp");
1072 TS->EmitARM64WinCFISaveRegP(MI->getOperand(0).getImm(),
1073 MI->getOperand(2).getImm());
1074 return;
1075
1076 case AArch64::SEH_SaveRegP_X:
1077 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
1078 "Non-consecutive registers not allowed for save_regp_x");
1079 assert(MI->getOperand(2).getImm() < 0 &&
1080 "Pre increment SEH opcode must have a negative offset");
1081 TS->EmitARM64WinCFISaveRegPX(MI->getOperand(0).getImm(),
1082 -MI->getOperand(2).getImm());
1083 return;
1084
1085 case AArch64::SEH_SaveFReg:
1086 TS->EmitARM64WinCFISaveFReg(MI->getOperand(0).getImm(),
1087 MI->getOperand(1).getImm());
1088 return;
1089
1090 case AArch64::SEH_SaveFReg_X:
1091 assert(MI->getOperand(1).getImm() < 0 &&
1092 "Pre increment SEH opcode must have a negative offset");
1093 TS->EmitARM64WinCFISaveFRegX(MI->getOperand(0).getImm(),
1094 -MI->getOperand(1).getImm());
1095 return;
1096
1097 case AArch64::SEH_SaveFRegP:
1098 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
1099 "Non-consecutive registers not allowed for save_regp");
1100 TS->EmitARM64WinCFISaveFRegP(MI->getOperand(0).getImm(),
1101 MI->getOperand(2).getImm());
1102 return;
1103
1104 case AArch64::SEH_SaveFRegP_X:
1105 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
1106 "Non-consecutive registers not allowed for save_regp_x");
1107 assert(MI->getOperand(2).getImm() < 0 &&
1108 "Pre increment SEH opcode must have a negative offset");
1109 TS->EmitARM64WinCFISaveFRegPX(MI->getOperand(0).getImm(),
1110 -MI->getOperand(2).getImm());
1111 return;
1112
1113 case AArch64::SEH_SetFP:
1114 TS->EmitARM64WinCFISetFP();
1115 return;
1116
1117 case AArch64::SEH_AddFP:
1118 TS->EmitARM64WinCFIAddFP(MI->getOperand(0).getImm());
1119 return;
1120
1121 case AArch64::SEH_Nop:
1122 TS->EmitARM64WinCFINop();
1123 return;
1124
1125 case AArch64::SEH_PrologEnd:
1126 TS->EmitARM64WinCFIPrologEnd();
1127 return;
1128
1129 case AArch64::SEH_EpilogStart:
1130 TS->EmitARM64WinCFIEpilogStart();
1131 return;
1132
1133 case AArch64::SEH_EpilogEnd:
1134 TS->EmitARM64WinCFIEpilogEnd();
1135 return;
Tim Northover3b0846e2014-05-24 12:50:23 +00001136 }
1137
1138 // Finally, do the automated lowerings for everything else.
1139 MCInst TmpInst;
1140 MCInstLowering.Lower(MI, TmpInst);
Lang Hames9ff69c82015-04-24 19:11:51 +00001141 EmitToStreamer(*OutStreamer, TmpInst);
Tim Northover3b0846e2014-05-24 12:50:23 +00001142}
1143
1144// Force static initialization.
1145extern "C" void LLVMInitializeAArch64AsmPrinter() {
Mehdi Aminif42454b2016-10-09 23:00:34 +00001146 RegisterAsmPrinter<AArch64AsmPrinter> X(getTheAArch64leTarget());
1147 RegisterAsmPrinter<AArch64AsmPrinter> Y(getTheAArch64beTarget());
1148 RegisterAsmPrinter<AArch64AsmPrinter> Z(getTheARM64Target());
Tim Northover3b0846e2014-05-24 12:50:23 +00001149}