1 //==-- AArch64MCInstLower.cpp - Convert AArch64 MachineInstr to an MCInst --==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file contains code to lower AArch64 MachineInstrs to their corresponding
11 // MCInst records.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "AArch64MCInstLower.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/Mangler.h"
23 #include "llvm/MC/MCContext.h"
24 #include "llvm/MC/MCExpr.h"
25 #include "llvm/MC/MCInst.h"
26 #include "llvm/Support/CodeGen.h"
27 #include "llvm/Support/CommandLine.h"
28 #include "llvm/Target/TargetLoweringObjectFile.h"
29 #include "llvm/Target/TargetMachine.h"
30 using namespace llvm;
31 
32 extern cl::opt<bool> EnableAArch64ELFLocalDynamicTLSGeneration;
33 
AArch64MCInstLower(MCContext & ctx,AsmPrinter & printer)34 AArch64MCInstLower::AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer)
35     : Ctx(ctx), Printer(printer) {}
36 
37 MCSymbol *
GetGlobalAddressSymbol(const MachineOperand & MO) const38 AArch64MCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
39   const GlobalValue *GV = MO.getGlobal();
40   unsigned TargetFlags = MO.getTargetFlags();
41   const Triple &TheTriple = Printer.TM.getTargetTriple();
42   if (!TheTriple.isOSBinFormatCOFF())
43     return Printer.getSymbol(GV);
44 
45   assert(TheTriple.isOSWindows() &&
46          "Windows is the only supported COFF target");
47 
48   bool IsIndirect = (TargetFlags & (AArch64II::MO_DLLIMPORT | AArch64II::MO_COFFSTUB));
49   if (!IsIndirect)
50     return Printer.getSymbol(GV);
51 
52   SmallString<128> Name;
53   if (TargetFlags & AArch64II::MO_DLLIMPORT)
54     Name = "__imp_";
55   else if (TargetFlags & AArch64II::MO_COFFSTUB)
56     Name = ".refptr.";
57   Printer.TM.getNameWithPrefix(Name, GV,
58                                Printer.getObjFileLowering().getMangler());
59 
60   MCSymbol *MCSym = Ctx.getOrCreateSymbol(Name);
61 
62   if (TargetFlags & AArch64II::MO_COFFSTUB) {
63     MachineModuleInfoCOFF &MMICOFF =
64         Printer.MMI->getObjFileInfo<MachineModuleInfoCOFF>();
65     MachineModuleInfoImpl::StubValueTy &StubSym =
66         MMICOFF.getGVStubEntry(MCSym);
67 
68     if (!StubSym.getPointer())
69       StubSym = MachineModuleInfoImpl::StubValueTy(Printer.getSymbol(GV), true);
70   }
71 
72   return MCSym;
73 }
74 
75 MCSymbol *
GetExternalSymbolSymbol(const MachineOperand & MO) const76 AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {
77   return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
78 }
79 
lowerSymbolOperandDarwin(const MachineOperand & MO,MCSymbol * Sym) const80 MCOperand AArch64MCInstLower::lowerSymbolOperandDarwin(const MachineOperand &MO,
81                                                        MCSymbol *Sym) const {
82   // FIXME: We would like an efficient form for this, so we don't have to do a
83   // lot of extra uniquing.
84   MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None;
85   if ((MO.getTargetFlags() & AArch64II::MO_GOT) != 0) {
86     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
87       RefKind = MCSymbolRefExpr::VK_GOTPAGE;
88     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
89              AArch64II::MO_PAGEOFF)
90       RefKind = MCSymbolRefExpr::VK_GOTPAGEOFF;
91     else
92       llvm_unreachable("Unexpected target flags with MO_GOT on GV operand");
93   } else if ((MO.getTargetFlags() & AArch64II::MO_TLS) != 0) {
94     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
95       RefKind = MCSymbolRefExpr::VK_TLVPPAGE;
96     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
97              AArch64II::MO_PAGEOFF)
98       RefKind = MCSymbolRefExpr::VK_TLVPPAGEOFF;
99     else
100       llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");
101   } else {
102     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
103       RefKind = MCSymbolRefExpr::VK_PAGE;
104     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
105              AArch64II::MO_PAGEOFF)
106       RefKind = MCSymbolRefExpr::VK_PAGEOFF;
107   }
108   const MCExpr *Expr = MCSymbolRefExpr::create(Sym, RefKind, Ctx);
109   if (!MO.isJTI() && MO.getOffset())
110     Expr = MCBinaryExpr::createAdd(
111         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
112   return MCOperand::createExpr(Expr);
113 }
114 
lowerSymbolOperandELF(const MachineOperand & MO,MCSymbol * Sym) const115 MCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO,
116                                                     MCSymbol *Sym) const {
117   uint32_t RefFlags = 0;
118 
119   if (MO.getTargetFlags() & AArch64II::MO_GOT)
120     RefFlags |= AArch64MCExpr::VK_GOT;
121   else if (MO.getTargetFlags() & AArch64II::MO_TLS) {
122     TLSModel::Model Model;
123     if (MO.isGlobal()) {
124       const GlobalValue *GV = MO.getGlobal();
125       Model = Printer.TM.getTLSModel(GV);
126       if (!EnableAArch64ELFLocalDynamicTLSGeneration &&
127           Model == TLSModel::LocalDynamic)
128         Model = TLSModel::GeneralDynamic;
129 
130     } else {
131       assert(MO.isSymbol() &&
132              StringRef(MO.getSymbolName()) == "_TLS_MODULE_BASE_" &&
133              "unexpected external TLS symbol");
134       // The general dynamic access sequence is used to get the
135       // address of _TLS_MODULE_BASE_.
136       Model = TLSModel::GeneralDynamic;
137     }
138     switch (Model) {
139     case TLSModel::InitialExec:
140       RefFlags |= AArch64MCExpr::VK_GOTTPREL;
141       break;
142     case TLSModel::LocalExec:
143       RefFlags |= AArch64MCExpr::VK_TPREL;
144       break;
145     case TLSModel::LocalDynamic:
146       RefFlags |= AArch64MCExpr::VK_DTPREL;
147       break;
148     case TLSModel::GeneralDynamic:
149       RefFlags |= AArch64MCExpr::VK_TLSDESC;
150       break;
151     }
152   } else {
153     // No modifier means this is a generic reference, classified as absolute for
154     // the cases where it matters (:abs_g0: etc).
155     RefFlags |= AArch64MCExpr::VK_ABS;
156   }
157 
158   if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGE)
159     RefFlags |= AArch64MCExpr::VK_PAGE;
160   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
161            AArch64II::MO_PAGEOFF)
162     RefFlags |= AArch64MCExpr::VK_PAGEOFF;
163   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
164     RefFlags |= AArch64MCExpr::VK_G3;
165   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
166     RefFlags |= AArch64MCExpr::VK_G2;
167   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
168     RefFlags |= AArch64MCExpr::VK_G1;
169   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
170     RefFlags |= AArch64MCExpr::VK_G0;
171   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_HI12)
172     RefFlags |= AArch64MCExpr::VK_HI12;
173 
174   if (MO.getTargetFlags() & AArch64II::MO_NC)
175     RefFlags |= AArch64MCExpr::VK_NC;
176 
177   const MCExpr *Expr =
178       MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
179   if (!MO.isJTI() && MO.getOffset())
180     Expr = MCBinaryExpr::createAdd(
181         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
182 
183   AArch64MCExpr::VariantKind RefKind;
184   RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);
185   Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
186 
187   return MCOperand::createExpr(Expr);
188 }
189 
lowerSymbolOperandCOFF(const MachineOperand & MO,MCSymbol * Sym) const190 MCOperand AArch64MCInstLower::lowerSymbolOperandCOFF(const MachineOperand &MO,
191                                                      MCSymbol *Sym) const {
192   uint32_t RefFlags = 0;
193 
194   if (MO.getTargetFlags() & AArch64II::MO_TLS) {
195     if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGEOFF)
196       RefFlags |= AArch64MCExpr::VK_SECREL_LO12;
197     else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
198              AArch64II::MO_HI12)
199       RefFlags |= AArch64MCExpr::VK_SECREL_HI12;
200 
201   } else if (MO.getTargetFlags() & AArch64II::MO_S) {
202     RefFlags |= AArch64MCExpr::VK_SABS;
203   } else {
204     RefFlags |= AArch64MCExpr::VK_ABS;
205   }
206 
207   if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G3)
208     RefFlags |= AArch64MCExpr::VK_G3;
209   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G2)
210     RefFlags |= AArch64MCExpr::VK_G2;
211   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G1)
212     RefFlags |= AArch64MCExpr::VK_G1;
213   else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_G0)
214     RefFlags |= AArch64MCExpr::VK_G0;
215 
216   // FIXME: Currently we only set VK_NC for MO_G3/MO_G2/MO_G1/MO_G0. This is
217   // because setting VK_NC for others would mean setting their respective
218   // RefFlags correctly.  We should do this in a separate patch.
219   if (MO.getTargetFlags() & AArch64II::MO_NC) {
220     auto MOFrag = (MO.getTargetFlags() & AArch64II::MO_FRAGMENT);
221     if (MOFrag == AArch64II::MO_G3 || MOFrag == AArch64II::MO_G2 ||
222         MOFrag == AArch64II::MO_G1 || MOFrag == AArch64II::MO_G0)
223       RefFlags |= AArch64MCExpr::VK_NC;
224   }
225 
226   const MCExpr *Expr =
227       MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
228   if (!MO.isJTI() && MO.getOffset())
229     Expr = MCBinaryExpr::createAdd(
230         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
231 
232   auto RefKind = static_cast<AArch64MCExpr::VariantKind>(RefFlags);
233   assert(RefKind != AArch64MCExpr::VK_INVALID &&
234          "Invalid relocation requested");
235   Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
236 
237   return MCOperand::createExpr(Expr);
238 }
239 
LowerSymbolOperand(const MachineOperand & MO,MCSymbol * Sym) const240 MCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO,
241                                                  MCSymbol *Sym) const {
242   if (Printer.TM.getTargetTriple().isOSDarwin())
243     return lowerSymbolOperandDarwin(MO, Sym);
244   if (Printer.TM.getTargetTriple().isOSBinFormatCOFF())
245     return lowerSymbolOperandCOFF(MO, Sym);
246 
247   assert(Printer.TM.getTargetTriple().isOSBinFormatELF() && "Invalid target");
248   return lowerSymbolOperandELF(MO, Sym);
249 }
250 
lowerOperand(const MachineOperand & MO,MCOperand & MCOp) const251 bool AArch64MCInstLower::lowerOperand(const MachineOperand &MO,
252                                       MCOperand &MCOp) const {
253   switch (MO.getType()) {
254   default:
255     llvm_unreachable("unknown operand type");
256   case MachineOperand::MO_Register:
257     // Ignore all implicit register operands.
258     if (MO.isImplicit())
259       return false;
260     MCOp = MCOperand::createReg(MO.getReg());
261     break;
262   case MachineOperand::MO_RegisterMask:
263     // Regmasks are like implicit defs.
264     return false;
265   case MachineOperand::MO_Immediate:
266     MCOp = MCOperand::createImm(MO.getImm());
267     break;
268   case MachineOperand::MO_MachineBasicBlock:
269     MCOp = MCOperand::createExpr(
270         MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));
271     break;
272   case MachineOperand::MO_GlobalAddress:
273     MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
274     break;
275   case MachineOperand::MO_ExternalSymbol:
276     MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
277     break;
278   case MachineOperand::MO_MCSymbol:
279     MCOp = LowerSymbolOperand(MO, MO.getMCSymbol());
280     break;
281   case MachineOperand::MO_JumpTableIndex:
282     MCOp = LowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex()));
283     break;
284   case MachineOperand::MO_ConstantPoolIndex:
285     MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));
286     break;
287   case MachineOperand::MO_BlockAddress:
288     MCOp = LowerSymbolOperand(
289         MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress()));
290     break;
291   }
292   return true;
293 }
294 
Lower(const MachineInstr * MI,MCInst & OutMI) const295 void AArch64MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
296   OutMI.setOpcode(MI->getOpcode());
297 
298   for (const MachineOperand &MO : MI->operands()) {
299     MCOperand MCOp;
300     if (lowerOperand(MO, MCOp))
301       OutMI.addOperand(MCOp);
302   }
303 
304   switch (OutMI.getOpcode()) {
305   case AArch64::CATCHRET:
306     OutMI = MCInst();
307     OutMI.setOpcode(AArch64::RET);
308     OutMI.addOperand(MCOperand::createReg(AArch64::LR));
309     break;
310   case AArch64::CLEANUPRET:
311     OutMI = MCInst();
312     OutMI.setOpcode(AArch64::RET);
313     OutMI.addOperand(MCOperand::createReg(AArch64::LR));
314     break;
315   }
316 }
317