xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp (revision 9c77fb6aaa366cbabc80ee1b834bcfe4df135491)
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/AArch64MCAsmInfo.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), MCSymbolRefExpr::create(MangledSym, Ctx));
82         Printer.OutStreamer->emitSymbolAttribute(MangledSym, MCSA_WeakAntiDep);
83         Printer.OutStreamer->emitAssignment(
84             MangledSym, MCSymbolRefExpr::create(Printer.getSymbol(GV), Ctx));
85       }
86 
87       if (TargetFlags & AArch64II::MO_ARM64EC_CALLMANGLE)
88         return MangledSym;
89     }
90 
91     return Printer.getSymbol(GV);
92   }
93 
94   SmallString<128> Name;
95 
96   if ((TargetFlags & AArch64II::MO_DLLIMPORT) &&
97       TheTriple.isWindowsArm64EC() &&
98       !(TargetFlags & AArch64II::MO_ARM64EC_CALLMANGLE) &&
99       isa<Function>(GV)) {
100     // __imp_aux is specific to arm64EC; it represents the actual address of
101     // an imported function without any thunks.
102     //
103     // If we see a reference to an "aux" symbol, also emit a reference to the
104     // corresponding non-aux symbol.  Otherwise, the Microsoft linker behaves
105     // strangely when linking against x64 import libararies.
106     //
107     // emitSymbolAttribute() doesn't have any real effect here; it just
108     // ensures the symbol name appears in the assembly without any
109     // side-effects. It might make sense to design a cleaner way to express
110     // this.
111     Name = "__imp_";
112     Printer.TM.getNameWithPrefix(Name, GV,
113                                  Printer.getObjFileLowering().getMangler());
114     MCSymbol *ExtraSym = Ctx.getOrCreateSymbol(Name);
115     Printer.OutStreamer->emitSymbolAttribute(ExtraSym, MCSA_Global);
116 
117     Name = "__imp_aux_";
118   } else if (TargetFlags & AArch64II::MO_DLLIMPORT) {
119     Name = "__imp_";
120   } else if (TargetFlags & AArch64II::MO_COFFSTUB) {
121     Name = ".refptr.";
122   }
123   Printer.TM.getNameWithPrefix(Name, GV,
124                                Printer.getObjFileLowering().getMangler());
125 
126   MCSymbol *MCSym = Ctx.getOrCreateSymbol(Name);
127 
128   if (TargetFlags & AArch64II::MO_COFFSTUB) {
129     MachineModuleInfoCOFF &MMICOFF =
130         Printer.MMI->getObjFileInfo<MachineModuleInfoCOFF>();
131     MachineModuleInfoImpl::StubValueTy &StubSym =
132         MMICOFF.getGVStubEntry(MCSym);
133 
134     if (!StubSym.getPointer())
135       StubSym = MachineModuleInfoImpl::StubValueTy(Printer.getSymbol(GV), true);
136   }
137 
138   return MCSym;
139 }
140 
141 MCSymbol *
142 AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {
143   return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
144 }
145 
146 MCOperand AArch64MCInstLower::lowerSymbolOperandMachO(const MachineOperand &MO,
147                                                       MCSymbol *Sym) const {
148   // FIXME: We would like an efficient form for this, so we don't have to do a
149   // lot of extra uniquing.
150   auto Spec = AArch64::S_None;
151   if ((MO.getTargetFlags() & AArch64II::MO_GOT) != 0) {
152     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
153       Spec = AArch64::S_MACHO_GOTPAGE;
154     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
155              AArch64II::MO_PAGEOFF)
156       Spec = AArch64::S_MACHO_GOTPAGEOFF;
157     else
158       llvm_unreachable("Unexpected target flags with MO_GOT on GV operand");
159   } else if ((MO.getTargetFlags() & AArch64II::MO_TLS) != 0) {
160     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
161       Spec = AArch64::S_MACHO_TLVPPAGE;
162     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
163              AArch64II::MO_PAGEOFF)
164       Spec = AArch64::S_MACHO_TLVPPAGEOFF;
165     else
166       llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");
167   } else {
168     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
169       Spec = AArch64::S_MACHO_PAGE;
170     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
171              AArch64II::MO_PAGEOFF)
172       Spec = AArch64::S_MACHO_PAGEOFF;
173   }
174   // TODO: Migrate to MCSpecifierExpr::create like ELF.
175   const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Spec, Ctx);
176   if (!MO.isJTI() && MO.getOffset())
177     Expr = MCBinaryExpr::createAdd(
178         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
179   return MCOperand::createExpr(Expr);
180 }
181 
182 MCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO,
183                                                     MCSymbol *Sym) const {
184   uint32_t RefFlags = 0;
185 
186   if (MO.getTargetFlags() & AArch64II::MO_GOT) {
187     const MachineFunction *MF = MO.getParent()->getParent()->getParent();
188     RefFlags |= (MF->getInfo<AArch64FunctionInfo>()->hasELFSignedGOT()
189                      ? AArch64::S_GOT_AUTH
190                      : AArch64::S_GOT);
191   } else if (MO.getTargetFlags() & AArch64II::MO_TLS) {
192     TLSModel::Model Model;
193     if (MO.isGlobal()) {
194       const MachineFunction *MF = MO.getParent()->getParent()->getParent();
195       if (MF->getInfo<AArch64FunctionInfo>()->hasELFSignedGOT()) {
196         Model = TLSModel::GeneralDynamic;
197       } else {
198         const GlobalValue *GV = MO.getGlobal();
199         Model = Printer.TM.getTLSModel(GV);
200         if (!EnableAArch64ELFLocalDynamicTLSGeneration &&
201             Model == TLSModel::LocalDynamic)
202           Model = TLSModel::GeneralDynamic;
203       }
204     } else {
205       assert(MO.isSymbol() &&
206              StringRef(MO.getSymbolName()) == "_TLS_MODULE_BASE_" &&
207              "unexpected external TLS symbol");
208       // The general dynamic access sequence is used to get the
209       // address of _TLS_MODULE_BASE_.
210       Model = TLSModel::GeneralDynamic;
211     }
212     switch (Model) {
213     case TLSModel::InitialExec:
214       RefFlags |= AArch64::S_GOTTPREL;
215       break;
216     case TLSModel::LocalExec:
217       RefFlags |= AArch64::S_TPREL;
218       break;
219     case TLSModel::LocalDynamic:
220       RefFlags |= AArch64::S_DTPREL;
221       break;
222     case TLSModel::GeneralDynamic: {
223       // TODO: it's probably better to introduce MO_TLS_AUTH or smth and avoid
224       // running hasELFSignedGOT() every time, but existing flags already
225       // cover all 12 bits of SubReg_TargetFlags field in MachineOperand, and
226       // making the field wider breaks static assertions.
227       const MachineFunction *MF = MO.getParent()->getParent()->getParent();
228       RefFlags |= MF->getInfo<AArch64FunctionInfo>()->hasELFSignedGOT()
229                       ? AArch64::S_TLSDESC_AUTH
230                       : AArch64::S_TLSDESC;
231       break;
232     }
233     }
234   } else if (MO.getTargetFlags() & AArch64II::MO_PREL) {
235     RefFlags |= AArch64::S_PREL;
236   } else {
237     // No modifier means this is a generic reference, classified as absolute for
238     // the cases where it matters (:abs_g0: etc).
239     RefFlags |= AArch64::S_ABS;
240   }
241 
242   if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
243     RefFlags |= AArch64::S_PAGE;
244   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
245            AArch64II::MO_PAGEOFF)
246     RefFlags |= AArch64::S_PAGEOFF;
247   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
248     RefFlags |= AArch64::S_G3;
249   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
250     RefFlags |= AArch64::S_G2;
251   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
252     RefFlags |= AArch64::S_G1;
253   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
254     RefFlags |= AArch64::S_G0;
255   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_HI12)
256     RefFlags |= AArch64::S_HI12;
257 
258   if (MO.getTargetFlags() & AArch64II::MO_NC)
259     RefFlags |= AArch64::S_NC;
260 
261   const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx);
262   if (!MO.isJTI() && MO.getOffset())
263     Expr = MCBinaryExpr::createAdd(
264         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
265 
266   Expr = MCSpecifierExpr::create(Expr, RefFlags, Ctx);
267   return MCOperand::createExpr(Expr);
268 }
269 
270 MCOperand AArch64MCInstLower::lowerSymbolOperandCOFF(const MachineOperand &MO,
271                                                      MCSymbol *Sym) const {
272   uint32_t RefFlags = 0;
273 
274   if (MO.getTargetFlags() & AArch64II::MO_TLS) {
275     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGEOFF)
276       RefFlags |= AArch64::S_SECREL_LO12;
277     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
278              AArch64II::MO_HI12)
279       RefFlags |= AArch64::S_SECREL_HI12;
280 
281   } else if (MO.getTargetFlags() & AArch64II::MO_S) {
282     RefFlags |= AArch64::S_SABS;
283   } else {
284     RefFlags |= AArch64::S_ABS;
285 
286     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
287       RefFlags |= AArch64::S_PAGE;
288     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
289              AArch64II::MO_PAGEOFF)
290       RefFlags |= AArch64::S_PAGEOFF | AArch64::S_NC;
291   }
292 
293   if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
294     RefFlags |= AArch64::S_G3;
295   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
296     RefFlags |= AArch64::S_G2;
297   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
298     RefFlags |= AArch64::S_G1;
299   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
300     RefFlags |= AArch64::S_G0;
301 
302   // FIXME: Currently we only set VK_NC for MO_G3/MO_G2/MO_G1/MO_G0. This is
303   // because setting VK_NC for others would mean setting their respective
304   // RefFlags correctly.  We should do this in a separate patch.
305   if (MO.getTargetFlags() & AArch64II::MO_NC) {
306     auto MOFrag = (MO.getTargetFlags() & AArch64II::MO_FRAGMENT);
307     if (MOFrag == AArch64II::MO_G3 || MOFrag == AArch64II::MO_G2 ||
308         MOFrag == AArch64II::MO_G1 || MOFrag == AArch64II::MO_G0)
309       RefFlags |= AArch64::S_NC;
310   }
311 
312   const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx);
313   if (!MO.isJTI() && MO.getOffset())
314     Expr = MCBinaryExpr::createAdd(
315         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
316 
317   Expr = MCSpecifierExpr::create(Expr, RefFlags, Ctx);
318   return MCOperand::createExpr(Expr);
319 }
320 
321 MCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO,
322                                                  MCSymbol *Sym) const {
323   if (Printer.TM.getTargetTriple().isOSBinFormatMachO())
324     return lowerSymbolOperandMachO(MO, Sym);
325   if (Printer.TM.getTargetTriple().isOSBinFormatCOFF())
326     return lowerSymbolOperandCOFF(MO, Sym);
327 
328   assert(Printer.TM.getTargetTriple().isOSBinFormatELF() && "Invalid target");
329   return lowerSymbolOperandELF(MO, Sym);
330 }
331 
332 bool AArch64MCInstLower::lowerOperand(const MachineOperand &MO,
333                                       MCOperand &MCOp) const {
334   switch (MO.getType()) {
335   default:
336     llvm_unreachable("unknown operand type");
337   case MachineOperand::MO_Register:
338     // Ignore all implicit register operands.
339     if (MO.isImplicit())
340       return false;
341     MCOp = MCOperand::createReg(MO.getReg());
342     break;
343   case MachineOperand::MO_RegisterMask:
344     // Regmasks are like implicit defs.
345     return false;
346   case MachineOperand::MO_Immediate:
347     MCOp = MCOperand::createImm(MO.getImm());
348     break;
349   case MachineOperand::MO_MachineBasicBlock:
350     MCOp = MCOperand::createExpr(
351         MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));
352     break;
353   case MachineOperand::MO_GlobalAddress:
354     MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
355     break;
356   case MachineOperand::MO_ExternalSymbol:
357     MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
358     break;
359   case MachineOperand::MO_MCSymbol:
360     MCOp = LowerSymbolOperand(MO, MO.getMCSymbol());
361     break;
362   case MachineOperand::MO_JumpTableIndex:
363     MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex()));
364     break;
365   case MachineOperand::MO_ConstantPoolIndex:
366     MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));
367     break;
368   case MachineOperand::MO_BlockAddress:
369     MCOp = LowerSymbolOperand(
370         MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress()));
371     break;
372   }
373   return true;
374 }
375 
376 void AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
377   OutMI.setOpcode(MI->getOpcode());
378 
379   for (const MachineOperand &MO : MI->operands()) {
380     MCOperand MCOp;
381     if (lowerOperand(MO, MCOp))
382       OutMI.addOperand(MCOp);
383   }
384 
385   switch (OutMI.getOpcode()) {
386   case AArch64::CATCHRET:
387     OutMI = MCInst();
388     OutMI.setOpcode(AArch64::RET);
389     OutMI.addOperand(MCOperand::createReg(AArch64::LR));
390     break;
391   case AArch64::CLEANUPRET:
392     OutMI = MCInst();
393     OutMI.setOpcode(AArch64::RET);
394     OutMI.addOperand(MCOperand::createReg(AArch64::LR));
395     break;
396   }
397 }
398