1 //==-- AArch64MCInstLower.cpp - Convert AArch64 MachineInstr to an MCInst --==//
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
7 //===----------------------------------------------------------------------===//
9 // This file contains code to lower AArch64 MachineInstrs to their corresponding
12 //===----------------------------------------------------------------------===//
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/Support/CodeGen.h"
26 #include "llvm/Support/CommandLine.h"
27 #include "llvm/Target/TargetLoweringObjectFile.h"
28 #include "llvm/Target/TargetMachine.h"
31 extern cl::opt
<bool> EnableAArch64ELFLocalDynamicTLSGeneration
;
33 AArch64MCInstLower::AArch64MCInstLower(MCContext
&ctx
, AsmPrinter
&printer
)
34 : Ctx(ctx
), Printer(printer
) {}
37 AArch64MCInstLower::GetGlobalAddressSymbol(const MachineOperand
&MO
) const {
38 const GlobalValue
*GV
= MO
.getGlobal();
39 unsigned TargetFlags
= MO
.getTargetFlags();
40 const Triple
&TheTriple
= Printer
.TM
.getTargetTriple();
41 if (!TheTriple
.isOSBinFormatCOFF())
42 return Printer
.getSymbol(GV
);
44 assert(TheTriple
.isOSWindows() &&
45 "Windows is the only supported COFF target");
47 bool IsIndirect
= (TargetFlags
& (AArch64II::MO_DLLIMPORT
| AArch64II::MO_COFFSTUB
));
49 return Printer
.getSymbol(GV
);
51 SmallString
<128> Name
;
52 if (TargetFlags
& AArch64II::MO_DLLIMPORT
)
54 else if (TargetFlags
& AArch64II::MO_COFFSTUB
)
56 Printer
.TM
.getNameWithPrefix(Name
, GV
,
57 Printer
.getObjFileLowering().getMangler());
59 MCSymbol
*MCSym
= Ctx
.getOrCreateSymbol(Name
);
61 if (TargetFlags
& AArch64II::MO_COFFSTUB
) {
62 MachineModuleInfoCOFF
&MMICOFF
=
63 Printer
.MMI
->getObjFileInfo
<MachineModuleInfoCOFF
>();
64 MachineModuleInfoImpl::StubValueTy
&StubSym
=
65 MMICOFF
.getGVStubEntry(MCSym
);
67 if (!StubSym
.getPointer())
68 StubSym
= MachineModuleInfoImpl::StubValueTy(Printer
.getSymbol(GV
), true);
75 AArch64MCInstLower::GetExternalSymbolSymbol(const MachineOperand
&MO
) const {
76 return Printer
.GetExternalSymbolSymbol(MO
.getSymbolName());
79 MCOperand
AArch64MCInstLower::lowerSymbolOperandDarwin(const MachineOperand
&MO
,
80 MCSymbol
*Sym
) const {
81 // FIXME: We would like an efficient form for this, so we don't have to do a
82 // lot of extra uniquing.
83 MCSymbolRefExpr::VariantKind RefKind
= MCSymbolRefExpr::VK_None
;
84 if ((MO
.getTargetFlags() & AArch64II::MO_GOT
) != 0) {
85 if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_PAGE
)
86 RefKind
= MCSymbolRefExpr::VK_GOTPAGE
;
87 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) ==
88 AArch64II::MO_PAGEOFF
)
89 RefKind
= MCSymbolRefExpr::VK_GOTPAGEOFF
;
91 llvm_unreachable("Unexpected target flags with MO_GOT on GV operand");
92 } else if ((MO
.getTargetFlags() & AArch64II::MO_TLS
) != 0) {
93 if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_PAGE
)
94 RefKind
= MCSymbolRefExpr::VK_TLVPPAGE
;
95 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) ==
96 AArch64II::MO_PAGEOFF
)
97 RefKind
= MCSymbolRefExpr::VK_TLVPPAGEOFF
;
99 llvm_unreachable("Unexpected target flags with MO_TLS on GV operand");
101 if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_PAGE
)
102 RefKind
= MCSymbolRefExpr::VK_PAGE
;
103 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) ==
104 AArch64II::MO_PAGEOFF
)
105 RefKind
= MCSymbolRefExpr::VK_PAGEOFF
;
107 const MCExpr
*Expr
= MCSymbolRefExpr::create(Sym
, RefKind
, Ctx
);
108 if (!MO
.isJTI() && MO
.getOffset())
109 Expr
= MCBinaryExpr::createAdd(
110 Expr
, MCConstantExpr::create(MO
.getOffset(), Ctx
), Ctx
);
111 return MCOperand::createExpr(Expr
);
114 MCOperand
AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand
&MO
,
115 MCSymbol
*Sym
) const {
116 uint32_t RefFlags
= 0;
118 if (MO
.getTargetFlags() & AArch64II::MO_GOT
)
119 RefFlags
|= AArch64MCExpr::VK_GOT
;
120 else if (MO
.getTargetFlags() & AArch64II::MO_TLS
) {
121 TLSModel::Model Model
;
123 const GlobalValue
*GV
= MO
.getGlobal();
124 Model
= Printer
.TM
.getTLSModel(GV
);
125 if (!EnableAArch64ELFLocalDynamicTLSGeneration
&&
126 Model
== TLSModel::LocalDynamic
)
127 Model
= TLSModel::GeneralDynamic
;
130 assert(MO
.isSymbol() &&
131 StringRef(MO
.getSymbolName()) == "_TLS_MODULE_BASE_" &&
132 "unexpected external TLS symbol");
133 // The general dynamic access sequence is used to get the
134 // address of _TLS_MODULE_BASE_.
135 Model
= TLSModel::GeneralDynamic
;
138 case TLSModel::InitialExec
:
139 RefFlags
|= AArch64MCExpr::VK_GOTTPREL
;
141 case TLSModel::LocalExec
:
142 RefFlags
|= AArch64MCExpr::VK_TPREL
;
144 case TLSModel::LocalDynamic
:
145 RefFlags
|= AArch64MCExpr::VK_DTPREL
;
147 case TLSModel::GeneralDynamic
:
148 RefFlags
|= AArch64MCExpr::VK_TLSDESC
;
151 } else if (MO
.getTargetFlags() & AArch64II::MO_PREL
) {
152 RefFlags
|= AArch64MCExpr::VK_PREL
;
154 // No modifier means this is a generic reference, classified as absolute for
155 // the cases where it matters (:abs_g0: etc).
156 RefFlags
|= AArch64MCExpr::VK_ABS
;
159 if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_PAGE
)
160 RefFlags
|= AArch64MCExpr::VK_PAGE
;
161 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) ==
162 AArch64II::MO_PAGEOFF
)
163 RefFlags
|= AArch64MCExpr::VK_PAGEOFF
;
164 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_G3
)
165 RefFlags
|= AArch64MCExpr::VK_G3
;
166 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_G2
)
167 RefFlags
|= AArch64MCExpr::VK_G2
;
168 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_G1
)
169 RefFlags
|= AArch64MCExpr::VK_G1
;
170 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_G0
)
171 RefFlags
|= AArch64MCExpr::VK_G0
;
172 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_HI12
)
173 RefFlags
|= AArch64MCExpr::VK_HI12
;
175 if (MO
.getTargetFlags() & AArch64II::MO_NC
)
176 RefFlags
|= AArch64MCExpr::VK_NC
;
179 MCSymbolRefExpr::create(Sym
, MCSymbolRefExpr::VK_None
, Ctx
);
180 if (!MO
.isJTI() && MO
.getOffset())
181 Expr
= MCBinaryExpr::createAdd(
182 Expr
, MCConstantExpr::create(MO
.getOffset(), Ctx
), Ctx
);
184 AArch64MCExpr::VariantKind RefKind
;
185 RefKind
= static_cast<AArch64MCExpr::VariantKind
>(RefFlags
);
186 Expr
= AArch64MCExpr::create(Expr
, RefKind
, Ctx
);
188 return MCOperand::createExpr(Expr
);
191 MCOperand
AArch64MCInstLower::lowerSymbolOperandCOFF(const MachineOperand
&MO
,
192 MCSymbol
*Sym
) const {
193 uint32_t RefFlags
= 0;
195 if (MO
.getTargetFlags() & AArch64II::MO_TLS
) {
196 if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_PAGEOFF
)
197 RefFlags
|= AArch64MCExpr::VK_SECREL_LO12
;
198 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) ==
200 RefFlags
|= AArch64MCExpr::VK_SECREL_HI12
;
202 } else if (MO
.getTargetFlags() & AArch64II::MO_S
) {
203 RefFlags
|= AArch64MCExpr::VK_SABS
;
205 RefFlags
|= AArch64MCExpr::VK_ABS
;
208 if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_G3
)
209 RefFlags
|= AArch64MCExpr::VK_G3
;
210 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_G2
)
211 RefFlags
|= AArch64MCExpr::VK_G2
;
212 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_G1
)
213 RefFlags
|= AArch64MCExpr::VK_G1
;
214 else if ((MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
) == AArch64II::MO_G0
)
215 RefFlags
|= AArch64MCExpr::VK_G0
;
217 // FIXME: Currently we only set VK_NC for MO_G3/MO_G2/MO_G1/MO_G0. This is
218 // because setting VK_NC for others would mean setting their respective
219 // RefFlags correctly. We should do this in a separate patch.
220 if (MO
.getTargetFlags() & AArch64II::MO_NC
) {
221 auto MOFrag
= (MO
.getTargetFlags() & AArch64II::MO_FRAGMENT
);
222 if (MOFrag
== AArch64II::MO_G3
|| MOFrag
== AArch64II::MO_G2
||
223 MOFrag
== AArch64II::MO_G1
|| MOFrag
== AArch64II::MO_G0
)
224 RefFlags
|= AArch64MCExpr::VK_NC
;
228 MCSymbolRefExpr::create(Sym
, MCSymbolRefExpr::VK_None
, Ctx
);
229 if (!MO
.isJTI() && MO
.getOffset())
230 Expr
= MCBinaryExpr::createAdd(
231 Expr
, MCConstantExpr::create(MO
.getOffset(), Ctx
), Ctx
);
233 auto RefKind
= static_cast<AArch64MCExpr::VariantKind
>(RefFlags
);
234 assert(RefKind
!= AArch64MCExpr::VK_INVALID
&&
235 "Invalid relocation requested");
236 Expr
= AArch64MCExpr::create(Expr
, RefKind
, Ctx
);
238 return MCOperand::createExpr(Expr
);
241 MCOperand
AArch64MCInstLower::LowerSymbolOperand(const MachineOperand
&MO
,
242 MCSymbol
*Sym
) const {
243 if (Printer
.TM
.getTargetTriple().isOSDarwin())
244 return lowerSymbolOperandDarwin(MO
, Sym
);
245 if (Printer
.TM
.getTargetTriple().isOSBinFormatCOFF())
246 return lowerSymbolOperandCOFF(MO
, Sym
);
248 assert(Printer
.TM
.getTargetTriple().isOSBinFormatELF() && "Invalid target");
249 return lowerSymbolOperandELF(MO
, Sym
);
252 bool AArch64MCInstLower::lowerOperand(const MachineOperand
&MO
,
253 MCOperand
&MCOp
) const {
254 switch (MO
.getType()) {
256 llvm_unreachable("unknown operand type");
257 case MachineOperand::MO_Register
:
258 // Ignore all implicit register operands.
261 MCOp
= MCOperand::createReg(MO
.getReg());
263 case MachineOperand::MO_RegisterMask
:
264 // Regmasks are like implicit defs.
266 case MachineOperand::MO_Immediate
:
267 MCOp
= MCOperand::createImm(MO
.getImm());
269 case MachineOperand::MO_MachineBasicBlock
:
270 MCOp
= MCOperand::createExpr(
271 MCSymbolRefExpr::create(MO
.getMBB()->getSymbol(), Ctx
));
273 case MachineOperand::MO_GlobalAddress
:
274 MCOp
= LowerSymbolOperand(MO
, GetGlobalAddressSymbol(MO
));
276 case MachineOperand::MO_ExternalSymbol
:
277 MCOp
= LowerSymbolOperand(MO
, GetExternalSymbolSymbol(MO
));
279 case MachineOperand::MO_MCSymbol
:
280 MCOp
= LowerSymbolOperand(MO
, MO
.getMCSymbol());
282 case MachineOperand::MO_JumpTableIndex
:
283 MCOp
= LowerSymbolOperand(MO
, Printer
.GetJTISymbol(MO
.getIndex()));
285 case MachineOperand::MO_ConstantPoolIndex
:
286 MCOp
= LowerSymbolOperand(MO
, Printer
.GetCPISymbol(MO
.getIndex()));
288 case MachineOperand::MO_BlockAddress
:
289 MCOp
= LowerSymbolOperand(
290 MO
, Printer
.GetBlockAddressSymbol(MO
.getBlockAddress()));
296 void AArch64MCInstLower::Lower(const MachineInstr
*MI
, MCInst
&OutMI
) const {
297 OutMI
.setOpcode(MI
->getOpcode());
299 for (const MachineOperand
&MO
: MI
->operands()) {
301 if (lowerOperand(MO
, MCOp
))
302 OutMI
.addOperand(MCOp
);
305 switch (OutMI
.getOpcode()) {
306 case AArch64::CATCHRET
:
308 OutMI
.setOpcode(AArch64::RET
);
309 OutMI
.addOperand(MCOperand::createReg(AArch64::LR
));
311 case AArch64::CLEANUPRET
:
313 OutMI
.setOpcode(AArch64::RET
);
314 OutMI
.addOperand(MCOperand::createReg(AArch64::LR
));