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