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