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