xref: /llvm-project/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp (revision 3c661cf03a2b1f669710a93bf73b15c831171888)
1 //==-- AArch64MCInstLower.cpp - Convert AArch64 MachineInstr to an MCInst --==//
2 //
3 // 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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains code to lower AArch64 MachineInstrs to their corresponding
10 // MCInst records.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "AArch64MCInstLower.h"
15 #include "AArch64MachineFunctionInfo.h"
16 #include "MCTargetDesc/AArch64MCExpr.h"
17 #include "Utils/AArch64BaseInfo.h"
18 #include "llvm/CodeGen/AsmPrinter.h"
19 #include "llvm/CodeGen/MachineBasicBlock.h"
20 #include "llvm/CodeGen/MachineInstr.h"
21 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
22 #include "llvm/IR/Function.h"
23 #include "llvm/IR/Mangler.h"
24 #include "llvm/MC/MCContext.h"
25 #include "llvm/MC/MCExpr.h"
26 #include "llvm/MC/MCInst.h"
27 #include "llvm/MC/MCStreamer.h"
28 #include "llvm/Object/COFF.h"
29 #include "llvm/Support/CodeGen.h"
30 #include "llvm/Support/CommandLine.h"
31 #include "llvm/Target/TargetLoweringObjectFile.h"
32 #include "llvm/Target/TargetMachine.h"
33 using namespace llvm;
34 using namespace llvm::object;
35 
36 extern cl::opt<bool> EnableAArch64ELFLocalDynamicTLSGeneration;
37 
38 AArch64MCInstLower::AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer)
39     : Ctx(ctx), Printer(printer) {}
40 
41 MCSymbol *
42 AArch64MCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
43   return GetGlobalValueSymbol(MO.getGlobal(), MO.getTargetFlags());
44 }
45 
46 MCSymbol *AArch64MCInstLower::GetGlobalValueSymbol(const GlobalValue *GV,
47                                                    unsigned TargetFlags) const {
48   const Triple &TheTriple = Printer.TM.getTargetTriple();
49   if (!TheTriple.isOSBinFormatCOFF())
50     return Printer.getSymbolPreferLocal(*GV);
51 
52   assert(TheTriple.isOSWindows() &&
53          "Windows is the only supported COFF target");
54 
55   bool IsIndirect =
56       (TargetFlags & (AArch64II::MO_DLLIMPORT | AArch64II::MO_COFFSTUB));
57   if (!IsIndirect) {
58     // For ARM64EC, symbol lookup in the MSVC linker has limited awareness
59     // of ARM64EC mangling ("#"/"$$h"). So object files need to refer to both
60     // the mangled and unmangled names of ARM64EC symbols, even if they aren't
61     // actually used by any relocations. Emit the necessary references here.
62     if (!TheTriple.isWindowsArm64EC() || !isa<Function>(GV) ||
63         !GV->hasExternalLinkage())
64       return Printer.getSymbol(GV);
65 
66     StringRef Name = Printer.getSymbol(GV)->getName();
67     // Don't mangle ARM64EC runtime functions.
68     static constexpr StringLiteral ExcludedFns[] = {
69         "__os_arm64x_check_icall_cfg", "__os_arm64x_dispatch_call_no_redirect",
70         "__os_arm64x_check_icall"};
71     if (is_contained(ExcludedFns, Name))
72       return Printer.getSymbol(GV);
73 
74     if (std::optional<std::string> MangledName =
75             getArm64ECMangledFunctionName(Name.str())) {
76       MCSymbol *MangledSym = Ctx.getOrCreateSymbol(MangledName.value());
77       if (!cast<Function>(GV)->hasMetadata("arm64ec_hasguestexit")) {
78         Printer.OutStreamer->emitSymbolAttribute(Printer.getSymbol(GV),
79                                                  MCSA_WeakAntiDep);
80         Printer.OutStreamer->emitAssignment(
81             Printer.getSymbol(GV),
82             MCSymbolRefExpr::create(MangledSym, MCSymbolRefExpr::VK_WEAKREF,
83                                     Ctx));
84         Printer.OutStreamer->emitSymbolAttribute(MangledSym, MCSA_WeakAntiDep);
85         Printer.OutStreamer->emitAssignment(
86             MangledSym,
87             MCSymbolRefExpr::create(Printer.getSymbol(GV),
88                                     MCSymbolRefExpr::VK_WEAKREF, Ctx));
89       }
90 
91       if (TargetFlags & AArch64II::MO_ARM64EC_CALLMANGLE)
92         return MangledSym;
93     }
94 
95     return Printer.getSymbol(GV);
96   }
97 
98   SmallString<128> Name;
99 
100   if ((TargetFlags & AArch64II::MO_DLLIMPORT) &&
101       TheTriple.isWindowsArm64EC() &&
102       !(TargetFlags & AArch64II::MO_ARM64EC_CALLMANGLE) &&
103       isa<Function>(GV)) {
104     // __imp_aux is specific to arm64EC; it represents the actual address of
105     // an imported function without any thunks.
106     //
107     // If we see a reference to an "aux" symbol, also emit a reference to the
108     // corresponding non-aux symbol.  Otherwise, the Microsoft linker behaves
109     // strangely when linking against x64 import libararies.
110     //
111     // emitSymbolAttribute() doesn't have any real effect here; it just
112     // ensures the symbol name appears in the assembly without any
113     // side-effects. It might make sense to design a cleaner way to express
114     // this.
115     Name = "__imp_";
116     Printer.TM.getNameWithPrefix(Name, GV,
117                                  Printer.getObjFileLowering().getMangler());
118     MCSymbol *ExtraSym = Ctx.getOrCreateSymbol(Name);
119     Printer.OutStreamer->emitSymbolAttribute(ExtraSym, MCSA_Global);
120 
121     Name = "__imp_aux_";
122   } else if (TargetFlags & AArch64II::MO_DLLIMPORT) {
123     Name = "__imp_";
124   } else if (TargetFlags & AArch64II::MO_COFFSTUB) {
125     Name = ".refptr.";
126   }
127   Printer.TM.getNameWithPrefix(Name, GV,
128                                Printer.getObjFileLowering().getMangler());
129 
130   MCSymbol *MCSym = Ctx.getOrCreateSymbol(Name);
131 
132   if (TargetFlags & AArch64II::MO_COFFSTUB) {
133     MachineModuleInfoCOFF &MMICOFF =
134         Printer.MMI->getObjFileInfo<MachineModuleInfoCOFF>();
135     MachineModuleInfoImpl::StubValueTy &StubSym =
136         MMICOFF.getGVStubEntry(MCSym);
137 
138     if (!StubSym.getPointer())
139       StubSym = MachineModuleInfoImpl::StubValueTy(Printer.getSymbol(GV), true);
140   }
141 
142   return MCSym;
143 }
144 
145 MCSymbol *
146 AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {
147   return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
148 }
149 
150 MCOperand AArch64MCInstLower::lowerSymbolOperandMachO(const MachineOperand &MO,
151                                                       MCSymbol *Sym) const {
152   // FIXME: We would like an efficient form for this, so we don't have to do a
153   // lot of extra uniquing.
154   MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None;
155   if ((MO.getTargetFlags() & AArch64II::MO_GOT) != 0) {
156     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
157       RefKind = MCSymbolRefExpr::VK_GOTPAGE;
158     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
159              AArch64II::MO_PAGEOFF)
160       RefKind = MCSymbolRefExpr::VK_GOTPAGEOFF;
161     else
162       llvm_unreachable("Unexpected target flags with MO_GOT on GV operand");
163   } else if ((MO.getTargetFlags() & AArch64II::MO_TLS) != 0) {
164     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
165       RefKind = MCSymbolRefExpr::VK_TLVPPAGE;
166     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
167              AArch64II::MO_PAGEOFF)
168       RefKind = MCSymbolRefExpr::VK_TLVPPAGEOFF;
169     else
170       llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");
171   } else {
172     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
173       RefKind = MCSymbolRefExpr::VK_PAGE;
174     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
175              AArch64II::MO_PAGEOFF)
176       RefKind = MCSymbolRefExpr::VK_PAGEOFF;
177   }
178   const MCExpr *Expr = MCSymbolRefExpr::create(Sym, RefKind, Ctx);
179   if (!MO.isJTI() && MO.getOffset())
180     Expr = MCBinaryExpr::createAdd(
181         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
182   return MCOperand::createExpr(Expr);
183 }
184 
185 MCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO,
186                                                     MCSymbol *Sym) const {
187   uint32_t RefFlags = 0;
188 
189   if (MO.getTargetFlags() & AArch64II::MO_GOT) {
190     const MachineFunction *MF = MO.getParent()->getParent()->getParent();
191     RefFlags |= (MF->getInfo<AArch64FunctionInfo>()->hasELFSignedGOT()
192                      ? AArch64MCExpr::VK_GOT_AUTH
193                      : AArch64MCExpr::VK_GOT);
194   } else if (MO.getTargetFlags() & AArch64II::MO_TLS) {
195     TLSModel::Model Model;
196     if (MO.isGlobal()) {
197       const MachineFunction *MF = MO.getParent()->getParent()->getParent();
198       if (MF->getInfo<AArch64FunctionInfo>()->hasELFSignedGOT()) {
199         Model = TLSModel::GeneralDynamic;
200       } else {
201         const GlobalValue *GV = MO.getGlobal();
202         Model = Printer.TM.getTLSModel(GV);
203         if (!EnableAArch64ELFLocalDynamicTLSGeneration &&
204             Model == TLSModel::LocalDynamic)
205           Model = TLSModel::GeneralDynamic;
206       }
207     } else {
208       assert(MO.isSymbol() &&
209              StringRef(MO.getSymbolName()) == "_TLS_MODULE_BASE_" &&
210              "unexpected external TLS symbol");
211       // The general dynamic access sequence is used to get the
212       // address of _TLS_MODULE_BASE_.
213       Model = TLSModel::GeneralDynamic;
214     }
215     switch (Model) {
216     case TLSModel::InitialExec:
217       RefFlags |= AArch64MCExpr::VK_GOTTPREL;
218       break;
219     case TLSModel::LocalExec:
220       RefFlags |= AArch64MCExpr::VK_TPREL;
221       break;
222     case TLSModel::LocalDynamic:
223       RefFlags |= AArch64MCExpr::VK_DTPREL;
224       break;
225     case TLSModel::GeneralDynamic: {
226       // TODO: it's probably better to introduce MO_TLS_AUTH or smth and avoid
227       // running hasELFSignedGOT() every time, but existing flags already
228       // cover all 12 bits of SubReg_TargetFlags field in MachineOperand, and
229       // making the field wider breaks static assertions.
230       const MachineFunction *MF = MO.getParent()->getParent()->getParent();
231       RefFlags |= MF->getInfo<AArch64FunctionInfo>()->hasELFSignedGOT()
232                       ? AArch64MCExpr::VK_TLSDESC_AUTH
233                       : AArch64MCExpr::VK_TLSDESC;
234       break;
235     }
236     }
237   } else if (MO.getTargetFlags() & AArch64II::MO_PREL) {
238     RefFlags |= AArch64MCExpr::VK_PREL;
239   } else {
240     // No modifier means this is a generic reference, classified as absolute for
241     // the cases where it matters (:abs_g0: etc).
242     RefFlags |= AArch64MCExpr::VK_ABS;
243   }
244 
245   if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
246     RefFlags |= AArch64MCExpr::VK_PAGE;
247   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
248            AArch64II::MO_PAGEOFF)
249     RefFlags |= AArch64MCExpr::VK_PAGEOFF;
250   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
251     RefFlags |= AArch64MCExpr::VK_G3;
252   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
253     RefFlags |= AArch64MCExpr::VK_G2;
254   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
255     RefFlags |= AArch64MCExpr::VK_G1;
256   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
257     RefFlags |= AArch64MCExpr::VK_G0;
258   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_HI12)
259     RefFlags |= AArch64MCExpr::VK_HI12;
260 
261   if (MO.getTargetFlags() & AArch64II::MO_NC)
262     RefFlags |= AArch64MCExpr::VK_NC;
263 
264   const MCExpr *Expr =
265       MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
266   if (!MO.isJTI() && MO.getOffset())
267     Expr = MCBinaryExpr::createAdd(
268         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
269 
270   AArch64MCExpr::VariantKind RefKind;
271   RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);
272   Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
273 
274   return MCOperand::createExpr(Expr);
275 }
276 
277 MCOperand AArch64MCInstLower::lowerSymbolOperandCOFF(const MachineOperand &MO,
278                                                      MCSymbol *Sym) const {
279   uint32_t RefFlags = 0;
280 
281   if (MO.getTargetFlags() & AArch64II::MO_TLS) {
282     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGEOFF)
283       RefFlags |= AArch64MCExpr::VK_SECREL_LO12;
284     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
285              AArch64II::MO_HI12)
286       RefFlags |= AArch64MCExpr::VK_SECREL_HI12;
287 
288   } else if (MO.getTargetFlags() & AArch64II::MO_S) {
289     RefFlags |= AArch64MCExpr::VK_SABS;
290   } else {
291     RefFlags |= AArch64MCExpr::VK_ABS;
292 
293     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
294       RefFlags |= AArch64MCExpr::VK_PAGE;
295     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
296              AArch64II::MO_PAGEOFF)
297       RefFlags |= AArch64MCExpr::VK_PAGEOFF | AArch64MCExpr::VK_NC;
298   }
299 
300   if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
301     RefFlags |= AArch64MCExpr::VK_G3;
302   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
303     RefFlags |= AArch64MCExpr::VK_G2;
304   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
305     RefFlags |= AArch64MCExpr::VK_G1;
306   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
307     RefFlags |= AArch64MCExpr::VK_G0;
308 
309   // FIXME: Currently we only set VK_NC for MO_G3/MO_G2/MO_G1/MO_G0. This is
310   // because setting VK_NC for others would mean setting their respective
311   // RefFlags correctly.  We should do this in a separate patch.
312   if (MO.getTargetFlags() & AArch64II::MO_NC) {
313     auto MOFrag = (MO.getTargetFlags() & AArch64II::MO_FRAGMENT);
314     if (MOFrag == AArch64II::MO_G3 || MOFrag == AArch64II::MO_G2 ||
315         MOFrag == AArch64II::MO_G1 || MOFrag == AArch64II::MO_G0)
316       RefFlags |= AArch64MCExpr::VK_NC;
317   }
318 
319   const MCExpr *Expr =
320       MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
321   if (!MO.isJTI() && MO.getOffset())
322     Expr = MCBinaryExpr::createAdd(
323         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
324 
325   auto RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);
326   assert(RefKind != AArch64MCExpr::VK_INVALID &&
327          "Invalid relocation requested");
328   Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
329 
330   return MCOperand::createExpr(Expr);
331 }
332 
333 MCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO,
334                                                  MCSymbol *Sym) const {
335   if (Printer.TM.getTargetTriple().isOSBinFormatMachO())
336     return lowerSymbolOperandMachO(MO, Sym);
337   if (Printer.TM.getTargetTriple().isOSBinFormatCOFF())
338     return lowerSymbolOperandCOFF(MO, Sym);
339 
340   assert(Printer.TM.getTargetTriple().isOSBinFormatELF() && "Invalid target");
341   return lowerSymbolOperandELF(MO, Sym);
342 }
343 
344 bool AArch64MCInstLower::lowerOperand(const MachineOperand &MO,
345                                       MCOperand &MCOp) const {
346   switch (MO.getType()) {
347   default:
348     llvm_unreachable("unknown operand type");
349   case MachineOperand::MO_Register:
350     // Ignore all implicit register operands.
351     if (MO.isImplicit())
352       return false;
353     MCOp = MCOperand::createReg(MO.getReg());
354     break;
355   case MachineOperand::MO_RegisterMask:
356     // Regmasks are like implicit defs.
357     return false;
358   case MachineOperand::MO_Immediate:
359     MCOp = MCOperand::createImm(MO.getImm());
360     break;
361   case MachineOperand::MO_MachineBasicBlock:
362     MCOp = MCOperand::createExpr(
363         MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));
364     break;
365   case MachineOperand::MO_GlobalAddress:
366     MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
367     break;
368   case MachineOperand::MO_ExternalSymbol:
369     MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
370     break;
371   case MachineOperand::MO_MCSymbol:
372     MCOp = LowerSymbolOperand(MO, MO.getMCSymbol());
373     break;
374   case MachineOperand::MO_JumpTableIndex:
375     MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex()));
376     break;
377   case MachineOperand::MO_ConstantPoolIndex:
378     MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));
379     break;
380   case MachineOperand::MO_BlockAddress:
381     MCOp = LowerSymbolOperand(
382         MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress()));
383     break;
384   }
385   return true;
386 }
387 
388 void AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
389   OutMI.setOpcode(MI->getOpcode());
390 
391   for (const MachineOperand &MO : MI->operands()) {
392     MCOperand MCOp;
393     if (lowerOperand(MO, MCOp))
394       OutMI.addOperand(MCOp);
395   }
396 
397   switch (OutMI.getOpcode()) {
398   case AArch64::CATCHRET:
399     OutMI = MCInst();
400     OutMI.setOpcode(AArch64::RET);
401     OutMI.addOperand(MCOperand::createReg(AArch64::LR));
402     break;
403   case AArch64::CLEANUPRET:
404     OutMI = MCInst();
405     OutMI.setOpcode(AArch64::RET);
406     OutMI.addOperand(MCOperand::createReg(AArch64::LR));
407     break;
408   }
409 }
410