1 | //===-- PPCAsmPrinter.cpp - Print machine instrs to PowerPC assembly ------===// |
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 a printer that converts from our internal representation |
10 | // of machine-dependent LLVM code to PowerPC assembly language. This printer is |
11 | // the output mechanism used by `llc'. |
12 | // |
13 | // Documentation at http://developer.apple.com/documentation/DeveloperTools/ |
14 | // Reference/Assembler/ASMIntroduction/chapter_1_section_1.html |
15 | // |
16 | //===----------------------------------------------------------------------===// |
17 | |
18 | #include "MCTargetDesc/PPCInstPrinter.h" |
19 | #include "MCTargetDesc/PPCMCExpr.h" |
20 | #include "MCTargetDesc/PPCMCTargetDesc.h" |
21 | #include "MCTargetDesc/PPCPredicates.h" |
22 | #include "PPC.h" |
23 | #include "PPCInstrInfo.h" |
24 | #include "PPCMachineFunctionInfo.h" |
25 | #include "PPCSubtarget.h" |
26 | #include "PPCTargetMachine.h" |
27 | #include "PPCTargetStreamer.h" |
28 | #include "TargetInfo/PowerPCTargetInfo.h" |
29 | #include "llvm/ADT/MapVector.h" |
30 | #include "llvm/ADT/SetVector.h" |
31 | #include "llvm/ADT/Statistic.h" |
32 | #include "llvm/ADT/StringExtras.h" |
33 | #include "llvm/ADT/StringRef.h" |
34 | #include "llvm/ADT/Twine.h" |
35 | #include "llvm/BinaryFormat/ELF.h" |
36 | #include "llvm/CodeGen/AsmPrinter.h" |
37 | #include "llvm/CodeGen/MachineBasicBlock.h" |
38 | #include "llvm/CodeGen/MachineFrameInfo.h" |
39 | #include "llvm/CodeGen/MachineFunction.h" |
40 | #include "llvm/CodeGen/MachineInstr.h" |
41 | #include "llvm/CodeGen/MachineModuleInfoImpls.h" |
42 | #include "llvm/CodeGen/MachineOperand.h" |
43 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
44 | #include "llvm/CodeGen/StackMaps.h" |
45 | #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" |
46 | #include "llvm/IR/DataLayout.h" |
47 | #include "llvm/IR/GlobalValue.h" |
48 | #include "llvm/IR/GlobalVariable.h" |
49 | #include "llvm/IR/Module.h" |
50 | #include "llvm/MC/MCAsmInfo.h" |
51 | #include "llvm/MC/MCContext.h" |
52 | #include "llvm/MC/MCDirectives.h" |
53 | #include "llvm/MC/MCExpr.h" |
54 | #include "llvm/MC/MCInst.h" |
55 | #include "llvm/MC/MCInstBuilder.h" |
56 | #include "llvm/MC/MCSectionELF.h" |
57 | #include "llvm/MC/MCSectionXCOFF.h" |
58 | #include "llvm/MC/MCStreamer.h" |
59 | #include "llvm/MC/MCSymbol.h" |
60 | #include "llvm/MC/MCSymbolELF.h" |
61 | #include "llvm/MC/MCSymbolXCOFF.h" |
62 | #include "llvm/MC/SectionKind.h" |
63 | #include "llvm/MC/TargetRegistry.h" |
64 | #include "llvm/Support/Casting.h" |
65 | #include "llvm/Support/CodeGen.h" |
66 | #include "llvm/Support/Debug.h" |
67 | #include "llvm/Support/Error.h" |
68 | #include "llvm/Support/ErrorHandling.h" |
69 | #include "llvm/Support/MathExtras.h" |
70 | #include "llvm/Support/Process.h" |
71 | #include "llvm/Support/Threading.h" |
72 | #include "llvm/Support/raw_ostream.h" |
73 | #include "llvm/Target/TargetMachine.h" |
74 | #include "llvm/TargetParser/Triple.h" |
75 | #include "llvm/Transforms/Utils/ModuleUtils.h" |
76 | #include <algorithm> |
77 | #include <cassert> |
78 | #include <cstdint> |
79 | #include <memory> |
80 | #include <new> |
81 | |
82 | using namespace llvm; |
83 | using namespace llvm::XCOFF; |
84 | |
85 | #define DEBUG_TYPE "asmprinter" |
86 | |
87 | STATISTIC(NumTOCEntries, "Number of Total TOC Entries Emitted." ); |
88 | STATISTIC(NumTOCConstPool, "Number of Constant Pool TOC Entries." ); |
89 | STATISTIC(NumTOCGlobalInternal, |
90 | "Number of Internal Linkage Global TOC Entries." ); |
91 | STATISTIC(NumTOCGlobalExternal, |
92 | "Number of External Linkage Global TOC Entries." ); |
93 | STATISTIC(NumTOCJumpTable, "Number of Jump Table TOC Entries." ); |
94 | STATISTIC(NumTOCThreadLocal, "Number of Thread Local TOC Entries." ); |
95 | STATISTIC(NumTOCBlockAddress, "Number of Block Address TOC Entries." ); |
96 | STATISTIC(NumTOCEHBlock, "Number of EH Block TOC Entries." ); |
97 | |
98 | static cl::opt<bool> EnableSSPCanaryBitInTB( |
99 | "aix-ssp-tb-bit" , cl::init(Val: false), |
100 | cl::desc("Enable Passing SSP Canary info in Trackback on AIX" ), cl::Hidden); |
101 | |
102 | // Specialize DenseMapInfo to allow |
103 | // std::pair<const MCSymbol *, MCSymbolRefExpr::VariantKind> in DenseMap. |
104 | // This specialization is needed here because that type is used as keys in the |
105 | // map representing TOC entries. |
106 | namespace llvm { |
107 | template <> |
108 | struct DenseMapInfo<std::pair<const MCSymbol *, MCSymbolRefExpr::VariantKind>> { |
109 | using TOCKey = std::pair<const MCSymbol *, MCSymbolRefExpr::VariantKind>; |
110 | |
111 | static inline TOCKey getEmptyKey() { |
112 | return {nullptr, MCSymbolRefExpr::VariantKind::VK_None}; |
113 | } |
114 | static inline TOCKey getTombstoneKey() { |
115 | return {nullptr, MCSymbolRefExpr::VariantKind::VK_Invalid}; |
116 | } |
117 | static unsigned getHashValue(const TOCKey &PairVal) { |
118 | return detail::combineHashValue( |
119 | a: DenseMapInfo<const MCSymbol *>::getHashValue(PtrVal: PairVal.first), |
120 | b: DenseMapInfo<int>::getHashValue(Val: PairVal.second)); |
121 | } |
122 | static bool isEqual(const TOCKey &A, const TOCKey &B) { return A == B; } |
123 | }; |
124 | } // end namespace llvm |
125 | |
126 | namespace { |
127 | |
128 | enum { |
129 | // GNU attribute tags for PowerPC ABI |
130 | Tag_GNU_Power_ABI_FP = 4, |
131 | Tag_GNU_Power_ABI_Vector = 8, |
132 | Tag_GNU_Power_ABI_Struct_Return = 12, |
133 | |
134 | // GNU attribute values for PowerPC float ABI, as combination of two parts |
135 | Val_GNU_Power_ABI_NoFloat = 0b00, |
136 | Val_GNU_Power_ABI_HardFloat_DP = 0b01, |
137 | Val_GNU_Power_ABI_SoftFloat_DP = 0b10, |
138 | Val_GNU_Power_ABI_HardFloat_SP = 0b11, |
139 | |
140 | Val_GNU_Power_ABI_LDBL_IBM128 = 0b0100, |
141 | Val_GNU_Power_ABI_LDBL_64 = 0b1000, |
142 | Val_GNU_Power_ABI_LDBL_IEEE128 = 0b1100, |
143 | }; |
144 | |
145 | class PPCAsmPrinter : public AsmPrinter { |
146 | protected: |
147 | // For TLS on AIX, we need to be able to identify TOC entries of specific |
148 | // VariantKind so we can add the right relocations when we generate the |
149 | // entries. So each entry is represented by a pair of MCSymbol and |
150 | // VariantKind. For example, we need to be able to identify the following |
151 | // entry as a TLSGD entry so we can add the @m relocation: |
152 | // .tc .i[TC],i[TL]@m |
153 | // By default, VK_None is used for the VariantKind. |
154 | MapVector<std::pair<const MCSymbol *, MCSymbolRefExpr::VariantKind>, |
155 | MCSymbol *> |
156 | TOC; |
157 | const PPCSubtarget *Subtarget = nullptr; |
158 | |
159 | // Keep track of the number of TLS variables and their corresponding |
160 | // addresses, which is then used for the assembly printing of |
161 | // non-TOC-based local-exec variables. |
162 | MapVector<const GlobalValue *, uint64_t> TLSVarsToAddressMapping; |
163 | |
164 | public: |
165 | explicit PPCAsmPrinter(TargetMachine &TM, |
166 | std::unique_ptr<MCStreamer> Streamer) |
167 | : AsmPrinter(TM, std::move(Streamer)) {} |
168 | |
169 | StringRef getPassName() const override { return "PowerPC Assembly Printer" ; } |
170 | |
171 | enum TOCEntryType { |
172 | TOCType_ConstantPool, |
173 | TOCType_GlobalExternal, |
174 | TOCType_GlobalInternal, |
175 | TOCType_JumpTable, |
176 | TOCType_ThreadLocal, |
177 | TOCType_BlockAddress, |
178 | TOCType_EHBlock |
179 | }; |
180 | |
181 | MCSymbol *lookUpOrCreateTOCEntry(const MCSymbol *Sym, TOCEntryType Type, |
182 | MCSymbolRefExpr::VariantKind Kind = |
183 | MCSymbolRefExpr::VariantKind::VK_None); |
184 | |
185 | bool doInitialization(Module &M) override { |
186 | if (!TOC.empty()) |
187 | TOC.clear(); |
188 | return AsmPrinter::doInitialization(M); |
189 | } |
190 | |
191 | void emitInstruction(const MachineInstr *MI) override; |
192 | |
193 | /// This function is for PrintAsmOperand and PrintAsmMemoryOperand, |
194 | /// invoked by EmitMSInlineAsmStr and EmitGCCInlineAsmStr only. |
195 | /// The \p MI would be INLINEASM ONLY. |
196 | void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O); |
197 | |
198 | void PrintSymbolOperand(const MachineOperand &MO, raw_ostream &O) override; |
199 | bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
200 | const char *, raw_ostream &O) override; |
201 | bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, |
202 | const char *, raw_ostream &O) override; |
203 | |
204 | void LowerSTACKMAP(StackMaps &SM, const MachineInstr &MI); |
205 | void LowerPATCHPOINT(StackMaps &SM, const MachineInstr &MI); |
206 | void EmitTlsCall(const MachineInstr *MI, MCSymbolRefExpr::VariantKind VK); |
207 | void EmitAIXTlsCallHelper(const MachineInstr *MI); |
208 | const MCExpr *getAdjustedFasterLocalExpr(const MachineOperand &MO, |
209 | int64_t Offset); |
210 | bool runOnMachineFunction(MachineFunction &MF) override { |
211 | Subtarget = &MF.getSubtarget<PPCSubtarget>(); |
212 | bool Changed = AsmPrinter::runOnMachineFunction(MF); |
213 | emitXRayTable(); |
214 | return Changed; |
215 | } |
216 | }; |
217 | |
218 | /// PPCLinuxAsmPrinter - PowerPC assembly printer, customized for Linux |
219 | class PPCLinuxAsmPrinter : public PPCAsmPrinter { |
220 | public: |
221 | explicit PPCLinuxAsmPrinter(TargetMachine &TM, |
222 | std::unique_ptr<MCStreamer> Streamer) |
223 | : PPCAsmPrinter(TM, std::move(Streamer)) {} |
224 | |
225 | StringRef getPassName() const override { |
226 | return "Linux PPC Assembly Printer" ; |
227 | } |
228 | |
229 | void emitGNUAttributes(Module &M); |
230 | |
231 | void emitStartOfAsmFile(Module &M) override; |
232 | void emitEndOfAsmFile(Module &) override; |
233 | |
234 | void emitFunctionEntryLabel() override; |
235 | |
236 | void emitFunctionBodyStart() override; |
237 | void emitFunctionBodyEnd() override; |
238 | void emitInstruction(const MachineInstr *MI) override; |
239 | }; |
240 | |
241 | class PPCAIXAsmPrinter : public PPCAsmPrinter { |
242 | private: |
243 | /// Symbols lowered from ExternalSymbolSDNodes, we will need to emit extern |
244 | /// linkage for them in AIX. |
245 | SmallSetVector<MCSymbol *, 8> ExtSymSDNodeSymbols; |
246 | |
247 | /// A format indicator and unique trailing identifier to form part of the |
248 | /// sinit/sterm function names. |
249 | std::string FormatIndicatorAndUniqueModId; |
250 | |
251 | // Record a list of GlobalAlias associated with a GlobalObject. |
252 | // This is used for AIX's extra-label-at-definition aliasing strategy. |
253 | DenseMap<const GlobalObject *, SmallVector<const GlobalAlias *, 1>> |
254 | GOAliasMap; |
255 | |
256 | uint16_t getNumberOfVRSaved(); |
257 | void emitTracebackTable(); |
258 | |
259 | SmallVector<const GlobalVariable *, 8> TOCDataGlobalVars; |
260 | |
261 | void emitGlobalVariableHelper(const GlobalVariable *); |
262 | |
263 | // Get the offset of an alias based on its AliaseeObject. |
264 | uint64_t getAliasOffset(const Constant *C); |
265 | |
266 | public: |
267 | PPCAIXAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer) |
268 | : PPCAsmPrinter(TM, std::move(Streamer)) { |
269 | if (MAI->isLittleEndian()) |
270 | report_fatal_error( |
271 | reason: "cannot create AIX PPC Assembly Printer for a little-endian target" ); |
272 | } |
273 | |
274 | StringRef getPassName() const override { return "AIX PPC Assembly Printer" ; } |
275 | |
276 | bool doInitialization(Module &M) override; |
277 | |
278 | void emitXXStructorList(const DataLayout &DL, const Constant *List, |
279 | bool IsCtor) override; |
280 | |
281 | void SetupMachineFunction(MachineFunction &MF) override; |
282 | |
283 | void emitGlobalVariable(const GlobalVariable *GV) override; |
284 | |
285 | void emitFunctionDescriptor() override; |
286 | |
287 | void emitFunctionEntryLabel() override; |
288 | |
289 | void emitFunctionBodyEnd() override; |
290 | |
291 | void emitPGORefs(Module &M); |
292 | |
293 | void emitEndOfAsmFile(Module &) override; |
294 | |
295 | void emitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const override; |
296 | |
297 | void emitInstruction(const MachineInstr *MI) override; |
298 | |
299 | bool doFinalization(Module &M) override; |
300 | |
301 | void emitTTypeReference(const GlobalValue *GV, unsigned Encoding) override; |
302 | |
303 | void emitModuleCommandLines(Module &M) override; |
304 | }; |
305 | |
306 | } // end anonymous namespace |
307 | |
308 | void PPCAsmPrinter::PrintSymbolOperand(const MachineOperand &MO, |
309 | raw_ostream &O) { |
310 | // Computing the address of a global symbol, not calling it. |
311 | const GlobalValue *GV = MO.getGlobal(); |
312 | getSymbol(GV)->print(OS&: O, MAI); |
313 | printOffset(Offset: MO.getOffset(), OS&: O); |
314 | } |
315 | |
316 | void PPCAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, |
317 | raw_ostream &O) { |
318 | const DataLayout &DL = getDataLayout(); |
319 | const MachineOperand &MO = MI->getOperand(i: OpNo); |
320 | |
321 | switch (MO.getType()) { |
322 | case MachineOperand::MO_Register: { |
323 | // The MI is INLINEASM ONLY and UseVSXReg is always false. |
324 | const char *RegName = PPCInstPrinter::getRegisterName(Reg: MO.getReg()); |
325 | |
326 | // Linux assembler (Others?) does not take register mnemonics. |
327 | // FIXME - What about special registers used in mfspr/mtspr? |
328 | O << PPC::stripRegisterPrefix(RegName); |
329 | return; |
330 | } |
331 | case MachineOperand::MO_Immediate: |
332 | O << MO.getImm(); |
333 | return; |
334 | |
335 | case MachineOperand::MO_MachineBasicBlock: |
336 | MO.getMBB()->getSymbol()->print(OS&: O, MAI); |
337 | return; |
338 | case MachineOperand::MO_ConstantPoolIndex: |
339 | O << DL.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_' |
340 | << MO.getIndex(); |
341 | return; |
342 | case MachineOperand::MO_BlockAddress: |
343 | GetBlockAddressSymbol(BA: MO.getBlockAddress())->print(OS&: O, MAI); |
344 | return; |
345 | case MachineOperand::MO_GlobalAddress: { |
346 | PrintSymbolOperand(MO, O); |
347 | return; |
348 | } |
349 | |
350 | default: |
351 | O << "<unknown operand type: " << (unsigned)MO.getType() << ">" ; |
352 | return; |
353 | } |
354 | } |
355 | |
356 | /// PrintAsmOperand - Print out an operand for an inline asm expression. |
357 | /// |
358 | bool PPCAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
359 | const char *, raw_ostream &O) { |
360 | // Does this asm operand have a single letter operand modifier? |
361 | if (ExtraCode && ExtraCode[0]) { |
362 | if (ExtraCode[1] != 0) return true; // Unknown modifier. |
363 | |
364 | switch (ExtraCode[0]) { |
365 | default: |
366 | // See if this is a generic print operand |
367 | return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS&: O); |
368 | case 'L': // Write second word of DImode reference. |
369 | // Verify that this operand has two consecutive registers. |
370 | if (!MI->getOperand(i: OpNo).isReg() || |
371 | OpNo+1 == MI->getNumOperands() || |
372 | !MI->getOperand(i: OpNo+1).isReg()) |
373 | return true; |
374 | ++OpNo; // Return the high-part. |
375 | break; |
376 | case 'I': |
377 | // Write 'i' if an integer constant, otherwise nothing. Used to print |
378 | // addi vs add, etc. |
379 | if (MI->getOperand(i: OpNo).isImm()) |
380 | O << "i" ; |
381 | return false; |
382 | case 'x': |
383 | if(!MI->getOperand(i: OpNo).isReg()) |
384 | return true; |
385 | // This operand uses VSX numbering. |
386 | // If the operand is a VMX register, convert it to a VSX register. |
387 | Register Reg = MI->getOperand(i: OpNo).getReg(); |
388 | if (PPC::isVRRegister(Reg)) |
389 | Reg = PPC::VSX32 + (Reg - PPC::V0); |
390 | else if (PPC::isVFRegister(Reg)) |
391 | Reg = PPC::VSX32 + (Reg - PPC::VF0); |
392 | const char *RegName; |
393 | RegName = PPCInstPrinter::getRegisterName(Reg); |
394 | RegName = PPC::stripRegisterPrefix(RegName); |
395 | O << RegName; |
396 | return false; |
397 | } |
398 | } |
399 | |
400 | printOperand(MI, OpNo, O); |
401 | return false; |
402 | } |
403 | |
404 | // At the moment, all inline asm memory operands are a single register. |
405 | // In any case, the output of this routine should always be just one |
406 | // assembler operand. |
407 | bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, |
408 | const char *, |
409 | raw_ostream &O) { |
410 | if (ExtraCode && ExtraCode[0]) { |
411 | if (ExtraCode[1] != 0) return true; // Unknown modifier. |
412 | |
413 | switch (ExtraCode[0]) { |
414 | default: return true; // Unknown modifier. |
415 | case 'L': // A memory reference to the upper word of a double word op. |
416 | O << getDataLayout().getPointerSize() << "(" ; |
417 | printOperand(MI, OpNo, O); |
418 | O << ")" ; |
419 | return false; |
420 | case 'y': // A memory reference for an X-form instruction |
421 | O << "0, " ; |
422 | printOperand(MI, OpNo, O); |
423 | return false; |
424 | case 'I': |
425 | // Write 'i' if an integer constant, otherwise nothing. Used to print |
426 | // addi vs add, etc. |
427 | if (MI->getOperand(i: OpNo).isImm()) |
428 | O << "i" ; |
429 | return false; |
430 | case 'U': // Print 'u' for update form. |
431 | case 'X': // Print 'x' for indexed form. |
432 | // FIXME: Currently for PowerPC memory operands are always loaded |
433 | // into a register, so we never get an update or indexed form. |
434 | // This is bad even for offset forms, since even if we know we |
435 | // have a value in -16(r1), we will generate a load into r<n> |
436 | // and then load from 0(r<n>). Until that issue is fixed, |
437 | // tolerate 'U' and 'X' but don't output anything. |
438 | assert(MI->getOperand(OpNo).isReg()); |
439 | return false; |
440 | } |
441 | } |
442 | |
443 | assert(MI->getOperand(OpNo).isReg()); |
444 | O << "0(" ; |
445 | printOperand(MI, OpNo, O); |
446 | O << ")" ; |
447 | return false; |
448 | } |
449 | |
450 | static void collectTOCStats(PPCAsmPrinter::TOCEntryType Type) { |
451 | ++NumTOCEntries; |
452 | switch (Type) { |
453 | case PPCAsmPrinter::TOCType_ConstantPool: |
454 | ++NumTOCConstPool; |
455 | break; |
456 | case PPCAsmPrinter::TOCType_GlobalInternal: |
457 | ++NumTOCGlobalInternal; |
458 | break; |
459 | case PPCAsmPrinter::TOCType_GlobalExternal: |
460 | ++NumTOCGlobalExternal; |
461 | break; |
462 | case PPCAsmPrinter::TOCType_JumpTable: |
463 | ++NumTOCJumpTable; |
464 | break; |
465 | case PPCAsmPrinter::TOCType_ThreadLocal: |
466 | ++NumTOCThreadLocal; |
467 | break; |
468 | case PPCAsmPrinter::TOCType_BlockAddress: |
469 | ++NumTOCBlockAddress; |
470 | break; |
471 | case PPCAsmPrinter::TOCType_EHBlock: |
472 | ++NumTOCEHBlock; |
473 | break; |
474 | } |
475 | } |
476 | |
477 | static CodeModel::Model getCodeModel(const PPCSubtarget &S, |
478 | const TargetMachine &TM, |
479 | const MachineOperand &MO) { |
480 | CodeModel::Model ModuleModel = TM.getCodeModel(); |
481 | |
482 | // If the operand is not a global address then there is no |
483 | // global variable to carry an attribute. |
484 | if (!(MO.getType() == MachineOperand::MO_GlobalAddress)) |
485 | return ModuleModel; |
486 | |
487 | const GlobalValue *GV = MO.getGlobal(); |
488 | assert(GV && "expected global for MO_GlobalAddress" ); |
489 | |
490 | return S.getCodeModel(TM, GV); |
491 | } |
492 | |
493 | static void setOptionalCodeModel(MCSymbolXCOFF *XSym, CodeModel::Model CM) { |
494 | switch (CM) { |
495 | case CodeModel::Large: |
496 | XSym->setPerSymbolCodeModel(MCSymbolXCOFF::CM_Large); |
497 | return; |
498 | case CodeModel::Small: |
499 | XSym->setPerSymbolCodeModel(MCSymbolXCOFF::CM_Small); |
500 | return; |
501 | default: |
502 | report_fatal_error(reason: "Invalid code model for AIX" ); |
503 | } |
504 | } |
505 | |
506 | /// lookUpOrCreateTOCEntry -- Given a symbol, look up whether a TOC entry |
507 | /// exists for it. If not, create one. Then return a symbol that references |
508 | /// the TOC entry. |
509 | MCSymbol * |
510 | PPCAsmPrinter::lookUpOrCreateTOCEntry(const MCSymbol *Sym, TOCEntryType Type, |
511 | MCSymbolRefExpr::VariantKind Kind) { |
512 | // If this is a new TOC entry add statistics about it. |
513 | if (!TOC.contains(Key: {Sym, Kind})) |
514 | collectTOCStats(Type); |
515 | |
516 | MCSymbol *&TOCEntry = TOC[{Sym, Kind}]; |
517 | if (!TOCEntry) |
518 | TOCEntry = createTempSymbol(Name: "C" ); |
519 | return TOCEntry; |
520 | } |
521 | |
522 | void PPCAsmPrinter::LowerSTACKMAP(StackMaps &SM, const MachineInstr &MI) { |
523 | unsigned NumNOPBytes = MI.getOperand(i: 1).getImm(); |
524 | |
525 | auto &Ctx = OutStreamer->getContext(); |
526 | MCSymbol *MILabel = Ctx.createTempSymbol(); |
527 | OutStreamer->emitLabel(Symbol: MILabel); |
528 | |
529 | SM.recordStackMap(L: *MILabel, MI); |
530 | assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!" ); |
531 | |
532 | // Scan ahead to trim the shadow. |
533 | const MachineBasicBlock &MBB = *MI.getParent(); |
534 | MachineBasicBlock::const_iterator MII(MI); |
535 | ++MII; |
536 | while (NumNOPBytes > 0) { |
537 | if (MII == MBB.end() || MII->isCall() || |
538 | MII->getOpcode() == PPC::DBG_VALUE || |
539 | MII->getOpcode() == TargetOpcode::PATCHPOINT || |
540 | MII->getOpcode() == TargetOpcode::STACKMAP) |
541 | break; |
542 | ++MII; |
543 | NumNOPBytes -= 4; |
544 | } |
545 | |
546 | // Emit nops. |
547 | for (unsigned i = 0; i < NumNOPBytes; i += 4) |
548 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::NOP)); |
549 | } |
550 | |
551 | // Lower a patchpoint of the form: |
552 | // [<def>], <id>, <numBytes>, <target>, <numArgs> |
553 | void PPCAsmPrinter::LowerPATCHPOINT(StackMaps &SM, const MachineInstr &MI) { |
554 | auto &Ctx = OutStreamer->getContext(); |
555 | MCSymbol *MILabel = Ctx.createTempSymbol(); |
556 | OutStreamer->emitLabel(Symbol: MILabel); |
557 | |
558 | SM.recordPatchPoint(L: *MILabel, MI); |
559 | PatchPointOpers Opers(&MI); |
560 | |
561 | unsigned EncodedBytes = 0; |
562 | const MachineOperand &CalleeMO = Opers.getCallTarget(); |
563 | |
564 | if (CalleeMO.isImm()) { |
565 | int64_t CallTarget = CalleeMO.getImm(); |
566 | if (CallTarget) { |
567 | assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget && |
568 | "High 16 bits of call target should be zero." ); |
569 | Register ScratchReg = MI.getOperand(i: Opers.getNextScratchIdx()).getReg(); |
570 | EncodedBytes = 0; |
571 | // Materialize the jump address: |
572 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::LI8) |
573 | .addReg(Reg: ScratchReg) |
574 | .addImm(Val: (CallTarget >> 32) & 0xFFFF)); |
575 | ++EncodedBytes; |
576 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::RLDIC) |
577 | .addReg(Reg: ScratchReg) |
578 | .addReg(Reg: ScratchReg) |
579 | .addImm(Val: 32).addImm(Val: 16)); |
580 | ++EncodedBytes; |
581 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::ORIS8) |
582 | .addReg(Reg: ScratchReg) |
583 | .addReg(Reg: ScratchReg) |
584 | .addImm(Val: (CallTarget >> 16) & 0xFFFF)); |
585 | ++EncodedBytes; |
586 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::ORI8) |
587 | .addReg(Reg: ScratchReg) |
588 | .addReg(Reg: ScratchReg) |
589 | .addImm(Val: CallTarget & 0xFFFF)); |
590 | |
591 | // Save the current TOC pointer before the remote call. |
592 | int TOCSaveOffset = Subtarget->getFrameLowering()->getTOCSaveOffset(); |
593 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::STD) |
594 | .addReg(Reg: PPC::X2) |
595 | .addImm(Val: TOCSaveOffset) |
596 | .addReg(Reg: PPC::X1)); |
597 | ++EncodedBytes; |
598 | |
599 | // If we're on ELFv1, then we need to load the actual function pointer |
600 | // from the function descriptor. |
601 | if (!Subtarget->isELFv2ABI()) { |
602 | // Load the new TOC pointer and the function address, but not r11 |
603 | // (needing this is rare, and loading it here would prevent passing it |
604 | // via a 'nest' parameter. |
605 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::LD) |
606 | .addReg(Reg: PPC::X2) |
607 | .addImm(Val: 8) |
608 | .addReg(Reg: ScratchReg)); |
609 | ++EncodedBytes; |
610 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::LD) |
611 | .addReg(Reg: ScratchReg) |
612 | .addImm(Val: 0) |
613 | .addReg(Reg: ScratchReg)); |
614 | ++EncodedBytes; |
615 | } |
616 | |
617 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::MTCTR8) |
618 | .addReg(Reg: ScratchReg)); |
619 | ++EncodedBytes; |
620 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::BCTRL8)); |
621 | ++EncodedBytes; |
622 | |
623 | // Restore the TOC pointer after the call. |
624 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::LD) |
625 | .addReg(Reg: PPC::X2) |
626 | .addImm(Val: TOCSaveOffset) |
627 | .addReg(Reg: PPC::X1)); |
628 | ++EncodedBytes; |
629 | } |
630 | } else if (CalleeMO.isGlobal()) { |
631 | const GlobalValue *GValue = CalleeMO.getGlobal(); |
632 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
633 | const MCExpr *SymVar = MCSymbolRefExpr::create(Symbol: MOSymbol, Ctx&: OutContext); |
634 | |
635 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::BL8_NOP) |
636 | .addExpr(Val: SymVar)); |
637 | EncodedBytes += 2; |
638 | } |
639 | |
640 | // Each instruction is 4 bytes. |
641 | EncodedBytes *= 4; |
642 | |
643 | // Emit padding. |
644 | unsigned NumBytes = Opers.getNumPatchBytes(); |
645 | assert(NumBytes >= EncodedBytes && |
646 | "Patchpoint can't request size less than the length of a call." ); |
647 | assert((NumBytes - EncodedBytes) % 4 == 0 && |
648 | "Invalid number of NOP bytes requested!" ); |
649 | for (unsigned i = EncodedBytes; i < NumBytes; i += 4) |
650 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::NOP)); |
651 | } |
652 | |
653 | /// This helper function creates the TlsGetAddr/TlsGetMod MCSymbol for AIX. We |
654 | /// will create the csect and use the qual-name symbol instead of creating just |
655 | /// the external symbol. |
656 | static MCSymbol *createMCSymbolForTlsGetAddr(MCContext &Ctx, unsigned MIOpc) { |
657 | StringRef SymName; |
658 | switch (MIOpc) { |
659 | default: |
660 | SymName = ".__tls_get_addr" ; |
661 | break; |
662 | case PPC::GETtlsTpointer32AIX: |
663 | SymName = ".__get_tpointer" ; |
664 | break; |
665 | case PPC::GETtlsMOD32AIX: |
666 | case PPC::GETtlsMOD64AIX: |
667 | SymName = ".__tls_get_mod" ; |
668 | break; |
669 | } |
670 | return Ctx |
671 | .getXCOFFSection(Section: SymName, K: SectionKind::getText(), |
672 | CsectProp: XCOFF::CsectProperties(XCOFF::XMC_PR, XCOFF::XTY_ER)) |
673 | ->getQualNameSymbol(); |
674 | } |
675 | |
676 | void PPCAsmPrinter::EmitAIXTlsCallHelper(const MachineInstr *MI) { |
677 | assert(Subtarget->isAIXABI() && |
678 | "Only expecting to emit calls to get the thread pointer on AIX!" ); |
679 | |
680 | MCSymbol *TlsCall = createMCSymbolForTlsGetAddr(Ctx&: OutContext, MIOpc: MI->getOpcode()); |
681 | const MCExpr *TlsRef = |
682 | MCSymbolRefExpr::create(Symbol: TlsCall, Kind: MCSymbolRefExpr::VK_None, Ctx&: OutContext); |
683 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::BLA).addExpr(Val: TlsRef)); |
684 | } |
685 | |
686 | /// EmitTlsCall -- Given a GETtls[ld]ADDR[32] instruction, print a |
687 | /// call to __tls_get_addr to the current output stream. |
688 | void PPCAsmPrinter::EmitTlsCall(const MachineInstr *MI, |
689 | MCSymbolRefExpr::VariantKind VK) { |
690 | MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VK_None; |
691 | unsigned Opcode = PPC::BL8_NOP_TLS; |
692 | |
693 | assert(MI->getNumOperands() >= 3 && "Expecting at least 3 operands from MI" ); |
694 | if (MI->getOperand(i: 2).getTargetFlags() == PPCII::MO_GOT_TLSGD_PCREL_FLAG || |
695 | MI->getOperand(i: 2).getTargetFlags() == PPCII::MO_GOT_TLSLD_PCREL_FLAG) { |
696 | Kind = MCSymbolRefExpr::VK_PPC_NOTOC; |
697 | Opcode = PPC::BL8_NOTOC_TLS; |
698 | } |
699 | const Module *M = MF->getFunction().getParent(); |
700 | |
701 | assert(MI->getOperand(0).isReg() && |
702 | ((Subtarget->isPPC64() && MI->getOperand(0).getReg() == PPC::X3) || |
703 | (!Subtarget->isPPC64() && MI->getOperand(0).getReg() == PPC::R3)) && |
704 | "GETtls[ld]ADDR[32] must define GPR3" ); |
705 | assert(MI->getOperand(1).isReg() && |
706 | ((Subtarget->isPPC64() && MI->getOperand(1).getReg() == PPC::X3) || |
707 | (!Subtarget->isPPC64() && MI->getOperand(1).getReg() == PPC::R3)) && |
708 | "GETtls[ld]ADDR[32] must read GPR3" ); |
709 | |
710 | if (Subtarget->isAIXABI()) { |
711 | // For TLSGD, the variable offset should already be in R4 and the region |
712 | // handle should already be in R3. We generate an absolute branch to |
713 | // .__tls_get_addr. For TLSLD, the module handle should already be in R3. |
714 | // We generate an absolute branch to .__tls_get_mod. |
715 | Register VarOffsetReg = Subtarget->isPPC64() ? PPC::X4 : PPC::R4; |
716 | (void)VarOffsetReg; |
717 | assert((MI->getOpcode() == PPC::GETtlsMOD32AIX || |
718 | MI->getOpcode() == PPC::GETtlsMOD64AIX || |
719 | (MI->getOperand(2).isReg() && |
720 | MI->getOperand(2).getReg() == VarOffsetReg)) && |
721 | "GETtls[ld]ADDR[32] must read GPR4" ); |
722 | EmitAIXTlsCallHelper(MI); |
723 | return; |
724 | } |
725 | |
726 | MCSymbol *TlsGetAddr = OutContext.getOrCreateSymbol(Name: "__tls_get_addr" ); |
727 | |
728 | if (Subtarget->is32BitELFABI() && isPositionIndependent()) |
729 | Kind = MCSymbolRefExpr::VK_PLT; |
730 | |
731 | const MCExpr *TlsRef = |
732 | MCSymbolRefExpr::create(Symbol: TlsGetAddr, Kind, Ctx&: OutContext); |
733 | |
734 | // Add 32768 offset to the symbol so we follow up the latest GOT/PLT ABI. |
735 | if (Kind == MCSymbolRefExpr::VK_PLT && Subtarget->isSecurePlt() && |
736 | M->getPICLevel() == PICLevel::BigPIC) |
737 | TlsRef = MCBinaryExpr::createAdd( |
738 | LHS: TlsRef, RHS: MCConstantExpr::create(Value: 32768, Ctx&: OutContext), Ctx&: OutContext); |
739 | const MachineOperand &MO = MI->getOperand(i: 2); |
740 | const GlobalValue *GValue = MO.getGlobal(); |
741 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
742 | const MCExpr *SymVar = MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: VK, Ctx&: OutContext); |
743 | EmitToStreamer(S&: *OutStreamer, |
744 | Inst: MCInstBuilder(Subtarget->isPPC64() ? Opcode |
745 | : (unsigned)PPC::BL_TLS) |
746 | .addExpr(Val: TlsRef) |
747 | .addExpr(Val: SymVar)); |
748 | } |
749 | |
750 | /// Map a machine operand for a TOC pseudo-machine instruction to its |
751 | /// corresponding MCSymbol. |
752 | static MCSymbol *getMCSymbolForTOCPseudoMO(const MachineOperand &MO, |
753 | AsmPrinter &AP) { |
754 | switch (MO.getType()) { |
755 | case MachineOperand::MO_GlobalAddress: |
756 | return AP.getSymbol(GV: MO.getGlobal()); |
757 | case MachineOperand::MO_ConstantPoolIndex: |
758 | return AP.GetCPISymbol(CPID: MO.getIndex()); |
759 | case MachineOperand::MO_JumpTableIndex: |
760 | return AP.GetJTISymbol(JTID: MO.getIndex()); |
761 | case MachineOperand::MO_BlockAddress: |
762 | return AP.GetBlockAddressSymbol(BA: MO.getBlockAddress()); |
763 | default: |
764 | llvm_unreachable("Unexpected operand type to get symbol." ); |
765 | } |
766 | } |
767 | |
768 | static PPCAsmPrinter::TOCEntryType |
769 | getTOCEntryTypeForMO(const MachineOperand &MO) { |
770 | // Use the target flags to determine if this MO is Thread Local. |
771 | // If we don't do this it comes out as Global. |
772 | if (PPCInstrInfo::hasTLSFlag(TF: MO.getTargetFlags())) |
773 | return PPCAsmPrinter::TOCType_ThreadLocal; |
774 | |
775 | switch (MO.getType()) { |
776 | case MachineOperand::MO_GlobalAddress: { |
777 | const GlobalValue *GlobalV = MO.getGlobal(); |
778 | GlobalValue::LinkageTypes Linkage = GlobalV->getLinkage(); |
779 | if (Linkage == GlobalValue::ExternalLinkage || |
780 | Linkage == GlobalValue::AvailableExternallyLinkage || |
781 | Linkage == GlobalValue::ExternalWeakLinkage) |
782 | return PPCAsmPrinter::TOCType_GlobalExternal; |
783 | |
784 | return PPCAsmPrinter::TOCType_GlobalInternal; |
785 | } |
786 | case MachineOperand::MO_ConstantPoolIndex: |
787 | return PPCAsmPrinter::TOCType_ConstantPool; |
788 | case MachineOperand::MO_JumpTableIndex: |
789 | return PPCAsmPrinter::TOCType_JumpTable; |
790 | case MachineOperand::MO_BlockAddress: |
791 | return PPCAsmPrinter::TOCType_BlockAddress; |
792 | default: |
793 | llvm_unreachable("Unexpected operand type to get TOC type." ); |
794 | } |
795 | } |
796 | /// EmitInstruction -- Print out a single PowerPC MI in Darwin syntax to |
797 | /// the current output stream. |
798 | /// |
799 | void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) { |
800 | PPC_MC::verifyInstructionPredicates(Opcode: MI->getOpcode(), |
801 | Features: getSubtargetInfo().getFeatureBits()); |
802 | |
803 | MCInst TmpInst; |
804 | const bool IsPPC64 = Subtarget->isPPC64(); |
805 | const bool IsAIX = Subtarget->isAIXABI(); |
806 | const bool HasAIXSmallLocalTLS = Subtarget->hasAIXSmallLocalExecTLS() || |
807 | Subtarget->hasAIXSmallLocalDynamicTLS(); |
808 | const Module *M = MF->getFunction().getParent(); |
809 | PICLevel::Level PL = M->getPICLevel(); |
810 | |
811 | #ifndef NDEBUG |
812 | // Validate that SPE and FPU are mutually exclusive in codegen |
813 | if (!MI->isInlineAsm()) { |
814 | for (const MachineOperand &MO: MI->operands()) { |
815 | if (MO.isReg()) { |
816 | Register Reg = MO.getReg(); |
817 | if (Subtarget->hasSPE()) { |
818 | if (PPC::F4RCRegClass.contains(Reg) || |
819 | PPC::F8RCRegClass.contains(Reg) || |
820 | PPC::VFRCRegClass.contains(Reg) || |
821 | PPC::VRRCRegClass.contains(Reg) || |
822 | PPC::VSFRCRegClass.contains(Reg) || |
823 | PPC::VSSRCRegClass.contains(Reg) |
824 | ) |
825 | llvm_unreachable("SPE targets cannot have FPRegs!" ); |
826 | } else { |
827 | if (PPC::SPERCRegClass.contains(Reg)) |
828 | llvm_unreachable("SPE register found in FPU-targeted code!" ); |
829 | } |
830 | } |
831 | } |
832 | } |
833 | #endif |
834 | |
835 | auto getTOCRelocAdjustedExprForXCOFF = [this](const MCExpr *Expr, |
836 | ptrdiff_t OriginalOffset) { |
837 | // Apply an offset to the TOC-based expression such that the adjusted |
838 | // notional offset from the TOC base (to be encoded into the instruction's D |
839 | // or DS field) is the signed 16-bit truncation of the original notional |
840 | // offset from the TOC base. |
841 | // This is consistent with the treatment used both by XL C/C++ and |
842 | // by AIX ld -r. |
843 | ptrdiff_t Adjustment = |
844 | OriginalOffset - llvm::SignExtend32<16>(X: OriginalOffset); |
845 | return MCBinaryExpr::createAdd( |
846 | LHS: Expr, RHS: MCConstantExpr::create(Value: -Adjustment, Ctx&: OutContext), Ctx&: OutContext); |
847 | }; |
848 | |
849 | auto getTOCEntryLoadingExprForXCOFF = |
850 | [IsPPC64, getTOCRelocAdjustedExprForXCOFF, |
851 | this](const MCSymbol *MOSymbol, const MCExpr *Expr, |
852 | MCSymbolRefExpr::VariantKind VK = |
853 | MCSymbolRefExpr::VariantKind::VK_None) -> const MCExpr * { |
854 | const unsigned EntryByteSize = IsPPC64 ? 8 : 4; |
855 | const auto TOCEntryIter = TOC.find(Key: {MOSymbol, VK}); |
856 | assert(TOCEntryIter != TOC.end() && |
857 | "Could not find the TOC entry for this symbol." ); |
858 | const ptrdiff_t EntryDistanceFromTOCBase = |
859 | (TOCEntryIter - TOC.begin()) * EntryByteSize; |
860 | constexpr int16_t PositiveTOCRange = INT16_MAX; |
861 | |
862 | if (EntryDistanceFromTOCBase > PositiveTOCRange) |
863 | return getTOCRelocAdjustedExprForXCOFF(Expr, EntryDistanceFromTOCBase); |
864 | |
865 | return Expr; |
866 | }; |
867 | auto GetVKForMO = [&](const MachineOperand &MO) { |
868 | // For TLS initial-exec and local-exec accesses on AIX, we have one TOC |
869 | // entry for the symbol (with the variable offset), which is differentiated |
870 | // by MO_TPREL_FLAG. |
871 | unsigned Flag = MO.getTargetFlags(); |
872 | if (Flag == PPCII::MO_TPREL_FLAG || |
873 | Flag == PPCII::MO_GOT_TPREL_PCREL_FLAG || |
874 | Flag == PPCII::MO_TPREL_PCREL_FLAG) { |
875 | assert(MO.isGlobal() && "Only expecting a global MachineOperand here!\n" ); |
876 | TLSModel::Model Model = TM.getTLSModel(GV: MO.getGlobal()); |
877 | if (Model == TLSModel::LocalExec) |
878 | return MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSLE; |
879 | if (Model == TLSModel::InitialExec) |
880 | return MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSIE; |
881 | // On AIX, TLS model opt may have turned local-dynamic accesses into |
882 | // initial-exec accesses. |
883 | PPCFunctionInfo *FuncInfo = MF->getInfo<PPCFunctionInfo>(); |
884 | if (Model == TLSModel::LocalDynamic && |
885 | FuncInfo->isAIXFuncUseTLSIEForLD()) { |
886 | LLVM_DEBUG( |
887 | dbgs() << "Current function uses IE access for default LD vars.\n" ); |
888 | return MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSIE; |
889 | } |
890 | llvm_unreachable("Only expecting local-exec or initial-exec accesses!" ); |
891 | } |
892 | // For GD TLS access on AIX, we have two TOC entries for the symbol (one for |
893 | // the variable offset and the other for the region handle). They are |
894 | // differentiated by MO_TLSGD_FLAG and MO_TLSGDM_FLAG. |
895 | if (Flag == PPCII::MO_TLSGDM_FLAG) |
896 | return MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSGDM; |
897 | if (Flag == PPCII::MO_TLSGD_FLAG || Flag == PPCII::MO_GOT_TLSGD_PCREL_FLAG) |
898 | return MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSGD; |
899 | // For local-dynamic TLS access on AIX, we have one TOC entry for the symbol |
900 | // (the variable offset) and one shared TOC entry for the module handle. |
901 | // They are differentiated by MO_TLSLD_FLAG and MO_TLSLDM_FLAG. |
902 | if (Flag == PPCII::MO_TLSLD_FLAG && IsAIX) |
903 | return MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSLD; |
904 | if (Flag == PPCII::MO_TLSLDM_FLAG && IsAIX) |
905 | return MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSML; |
906 | return MCSymbolRefExpr::VariantKind::VK_None; |
907 | }; |
908 | |
909 | // Lower multi-instruction pseudo operations. |
910 | switch (MI->getOpcode()) { |
911 | default: break; |
912 | case TargetOpcode::PATCHABLE_FUNCTION_ENTER: { |
913 | assert(!Subtarget->isAIXABI() && |
914 | "AIX does not support patchable function entry!" ); |
915 | // PATCHABLE_FUNCTION_ENTER on little endian is for XRAY support which is |
916 | // handled in PPCLinuxAsmPrinter. |
917 | if (MAI->isLittleEndian()) |
918 | return; |
919 | const Function &F = MF->getFunction(); |
920 | unsigned Num = 0; |
921 | (void)F.getFnAttribute(Kind: "patchable-function-entry" ) |
922 | .getValueAsString() |
923 | .getAsInteger(Radix: 10, Result&: Num); |
924 | if (!Num) |
925 | return; |
926 | emitNops(N: Num); |
927 | return; |
928 | } |
929 | case TargetOpcode::DBG_VALUE: |
930 | llvm_unreachable("Should be handled target independently" ); |
931 | case TargetOpcode::STACKMAP: |
932 | return LowerSTACKMAP(SM, MI: *MI); |
933 | case TargetOpcode::PATCHPOINT: |
934 | return LowerPATCHPOINT(SM, MI: *MI); |
935 | |
936 | case PPC::MoveGOTtoLR: { |
937 | // Transform %lr = MoveGOTtoLR |
938 | // Into this: bl _GLOBAL_OFFSET_TABLE_@local-4 |
939 | // _GLOBAL_OFFSET_TABLE_@local-4 (instruction preceding |
940 | // _GLOBAL_OFFSET_TABLE_) has exactly one instruction: |
941 | // blrl |
942 | // This will return the pointer to _GLOBAL_OFFSET_TABLE_@local |
943 | MCSymbol *GOTSymbol = |
944 | OutContext.getOrCreateSymbol(Name: StringRef("_GLOBAL_OFFSET_TABLE_" )); |
945 | const MCExpr *OffsExpr = |
946 | MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: GOTSymbol, |
947 | Kind: MCSymbolRefExpr::VK_PPC_LOCAL, |
948 | Ctx&: OutContext), |
949 | RHS: MCConstantExpr::create(Value: 4, Ctx&: OutContext), |
950 | Ctx&: OutContext); |
951 | |
952 | // Emit the 'bl'. |
953 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::BL).addExpr(Val: OffsExpr)); |
954 | return; |
955 | } |
956 | case PPC::MovePCtoLR: |
957 | case PPC::MovePCtoLR8: { |
958 | // Transform %lr = MovePCtoLR |
959 | // Into this, where the label is the PIC base: |
960 | // bl L1$pb |
961 | // L1$pb: |
962 | MCSymbol *PICBase = MF->getPICBaseSymbol(); |
963 | |
964 | // Emit the 'bl'. |
965 | EmitToStreamer(S&: *OutStreamer, |
966 | Inst: MCInstBuilder(PPC::BL) |
967 | // FIXME: We would like an efficient form for this, so we |
968 | // don't have to do a lot of extra uniquing. |
969 | .addExpr(Val: MCSymbolRefExpr::create(Symbol: PICBase, Ctx&: OutContext))); |
970 | |
971 | // Emit the label. |
972 | OutStreamer->emitLabel(Symbol: PICBase); |
973 | return; |
974 | } |
975 | case PPC::UpdateGBR: { |
976 | // Transform %rd = UpdateGBR(%rt, %ri) |
977 | // Into: lwz %rt, .L0$poff - .L0$pb(%ri) |
978 | // add %rd, %rt, %ri |
979 | // or into (if secure plt mode is on): |
980 | // addis r30, r30, {.LTOC,_GLOBAL_OFFSET_TABLE} - .L0$pb@ha |
981 | // addi r30, r30, {.LTOC,_GLOBAL_OFFSET_TABLE} - .L0$pb@l |
982 | // Get the offset from the GOT Base Register to the GOT |
983 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
984 | if (Subtarget->isSecurePlt() && isPositionIndependent() ) { |
985 | unsigned PICR = TmpInst.getOperand(i: 0).getReg(); |
986 | MCSymbol *BaseSymbol = OutContext.getOrCreateSymbol( |
987 | Name: M->getPICLevel() == PICLevel::SmallPIC ? "_GLOBAL_OFFSET_TABLE_" |
988 | : ".LTOC" ); |
989 | const MCExpr *PB = |
990 | MCSymbolRefExpr::create(Symbol: MF->getPICBaseSymbol(), Ctx&: OutContext); |
991 | |
992 | const MCExpr *DeltaExpr = MCBinaryExpr::createSub( |
993 | LHS: MCSymbolRefExpr::create(Symbol: BaseSymbol, Ctx&: OutContext), RHS: PB, Ctx&: OutContext); |
994 | |
995 | const MCExpr *DeltaHi = PPCMCExpr::createHa(Expr: DeltaExpr, Ctx&: OutContext); |
996 | EmitToStreamer( |
997 | S&: *OutStreamer, |
998 | Inst: MCInstBuilder(PPC::ADDIS).addReg(Reg: PICR).addReg(Reg: PICR).addExpr(Val: DeltaHi)); |
999 | |
1000 | const MCExpr *DeltaLo = PPCMCExpr::createLo(Expr: DeltaExpr, Ctx&: OutContext); |
1001 | EmitToStreamer( |
1002 | S&: *OutStreamer, |
1003 | Inst: MCInstBuilder(PPC::ADDI).addReg(Reg: PICR).addReg(Reg: PICR).addExpr(Val: DeltaLo)); |
1004 | return; |
1005 | } else { |
1006 | MCSymbol *PICOffset = |
1007 | MF->getInfo<PPCFunctionInfo>()->getPICOffsetSymbol(MF&: *MF); |
1008 | TmpInst.setOpcode(PPC::LWZ); |
1009 | const MCExpr *Exp = |
1010 | MCSymbolRefExpr::create(Symbol: PICOffset, Kind: MCSymbolRefExpr::VK_None, Ctx&: OutContext); |
1011 | const MCExpr *PB = |
1012 | MCSymbolRefExpr::create(Symbol: MF->getPICBaseSymbol(), |
1013 | Kind: MCSymbolRefExpr::VK_None, |
1014 | Ctx&: OutContext); |
1015 | const MCOperand TR = TmpInst.getOperand(i: 1); |
1016 | const MCOperand PICR = TmpInst.getOperand(i: 0); |
1017 | |
1018 | // Step 1: lwz %rt, .L$poff - .L$pb(%ri) |
1019 | TmpInst.getOperand(i: 1) = |
1020 | MCOperand::createExpr(Val: MCBinaryExpr::createSub(LHS: Exp, RHS: PB, Ctx&: OutContext)); |
1021 | TmpInst.getOperand(i: 0) = TR; |
1022 | TmpInst.getOperand(i: 2) = PICR; |
1023 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1024 | |
1025 | TmpInst.setOpcode(PPC::ADD4); |
1026 | TmpInst.getOperand(i: 0) = PICR; |
1027 | TmpInst.getOperand(i: 1) = TR; |
1028 | TmpInst.getOperand(i: 2) = PICR; |
1029 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1030 | return; |
1031 | } |
1032 | } |
1033 | case PPC::LWZtoc: { |
1034 | // Transform %rN = LWZtoc @op1, %r2 |
1035 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1036 | |
1037 | // Change the opcode to LWZ. |
1038 | TmpInst.setOpcode(PPC::LWZ); |
1039 | |
1040 | const MachineOperand &MO = MI->getOperand(i: 1); |
1041 | assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && |
1042 | "Invalid operand for LWZtoc." ); |
1043 | |
1044 | // Map the operand to its corresponding MCSymbol. |
1045 | const MCSymbol *const MOSymbol = getMCSymbolForTOCPseudoMO(MO, AP&: *this); |
1046 | |
1047 | // Create a reference to the GOT entry for the symbol. The GOT entry will be |
1048 | // synthesized later. |
1049 | if (PL == PICLevel::SmallPIC && !IsAIX) { |
1050 | const MCExpr *Exp = |
1051 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_GOT, |
1052 | Ctx&: OutContext); |
1053 | TmpInst.getOperand(i: 1) = MCOperand::createExpr(Val: Exp); |
1054 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1055 | return; |
1056 | } |
1057 | |
1058 | MCSymbolRefExpr::VariantKind VK = GetVKForMO(MO); |
1059 | |
1060 | // Otherwise, use the TOC. 'TOCEntry' is a label used to reference the |
1061 | // storage allocated in the TOC which contains the address of |
1062 | // 'MOSymbol'. Said TOC entry will be synthesized later. |
1063 | MCSymbol *TOCEntry = |
1064 | lookUpOrCreateTOCEntry(Sym: MOSymbol, Type: getTOCEntryTypeForMO(MO), Kind: VK); |
1065 | const MCExpr *Exp = |
1066 | MCSymbolRefExpr::create(Symbol: TOCEntry, Kind: MCSymbolRefExpr::VK_None, Ctx&: OutContext); |
1067 | |
1068 | // AIX uses the label directly as the lwz displacement operand for |
1069 | // references into the toc section. The displacement value will be generated |
1070 | // relative to the toc-base. |
1071 | if (IsAIX) { |
1072 | assert( |
1073 | getCodeModel(*Subtarget, TM, MO) == CodeModel::Small && |
1074 | "This pseudo should only be selected for 32-bit small code model." ); |
1075 | Exp = getTOCEntryLoadingExprForXCOFF(MOSymbol, Exp, VK); |
1076 | TmpInst.getOperand(i: 1) = MCOperand::createExpr(Val: Exp); |
1077 | |
1078 | // Print MO for better readability |
1079 | if (isVerbose()) |
1080 | OutStreamer->getCommentOS() << MO << '\n'; |
1081 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1082 | return; |
1083 | } |
1084 | |
1085 | // Create an explicit subtract expression between the local symbol and |
1086 | // '.LTOC' to manifest the toc-relative offset. |
1087 | const MCExpr *PB = MCSymbolRefExpr::create( |
1088 | Symbol: OutContext.getOrCreateSymbol(Name: Twine(".LTOC" )), Ctx&: OutContext); |
1089 | Exp = MCBinaryExpr::createSub(LHS: Exp, RHS: PB, Ctx&: OutContext); |
1090 | TmpInst.getOperand(i: 1) = MCOperand::createExpr(Val: Exp); |
1091 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1092 | return; |
1093 | } |
1094 | case PPC::ADDItoc: |
1095 | case PPC::ADDItoc8: { |
1096 | assert(IsAIX && TM.getCodeModel() == CodeModel::Small && |
1097 | "PseudoOp only valid for small code model AIX" ); |
1098 | |
1099 | // Transform %rN = ADDItoc/8 %r2, @op1. |
1100 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1101 | |
1102 | // Change the opcode to load address. |
1103 | TmpInst.setOpcode((!IsPPC64) ? (PPC::LA) : (PPC::LA8)); |
1104 | |
1105 | const MachineOperand &MO = MI->getOperand(i: 2); |
1106 | assert(MO.isGlobal() && "Invalid operand for ADDItoc[8]." ); |
1107 | |
1108 | // Map the operand to its corresponding MCSymbol. |
1109 | const MCSymbol *const MOSymbol = getMCSymbolForTOCPseudoMO(MO, AP&: *this); |
1110 | |
1111 | const MCExpr *Exp = |
1112 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_None, Ctx&: OutContext); |
1113 | |
1114 | TmpInst.getOperand(i: 2) = MCOperand::createExpr(Val: Exp); |
1115 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1116 | return; |
1117 | } |
1118 | case PPC::LDtocJTI: |
1119 | case PPC::LDtocCPT: |
1120 | case PPC::LDtocBA: |
1121 | case PPC::LDtoc: { |
1122 | // Transform %x3 = LDtoc @min1, %x2 |
1123 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1124 | |
1125 | // Change the opcode to LD. |
1126 | TmpInst.setOpcode(PPC::LD); |
1127 | |
1128 | const MachineOperand &MO = MI->getOperand(i: 1); |
1129 | assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && |
1130 | "Invalid operand!" ); |
1131 | |
1132 | // Map the operand to its corresponding MCSymbol. |
1133 | const MCSymbol *const MOSymbol = getMCSymbolForTOCPseudoMO(MO, AP&: *this); |
1134 | |
1135 | MCSymbolRefExpr::VariantKind VK = GetVKForMO(MO); |
1136 | |
1137 | // Map the machine operand to its corresponding MCSymbol, then map the |
1138 | // global address operand to be a reference to the TOC entry we will |
1139 | // synthesize later. |
1140 | MCSymbol *TOCEntry = |
1141 | lookUpOrCreateTOCEntry(Sym: MOSymbol, Type: getTOCEntryTypeForMO(MO), Kind: VK); |
1142 | |
1143 | MCSymbolRefExpr::VariantKind VKExpr = |
1144 | IsAIX ? MCSymbolRefExpr::VK_None : MCSymbolRefExpr::VK_PPC_TOC; |
1145 | const MCExpr *Exp = MCSymbolRefExpr::create(Symbol: TOCEntry, Kind: VKExpr, Ctx&: OutContext); |
1146 | TmpInst.getOperand(i: 1) = MCOperand::createExpr( |
1147 | Val: IsAIX ? getTOCEntryLoadingExprForXCOFF(MOSymbol, Exp, VK) : Exp); |
1148 | |
1149 | // Print MO for better readability |
1150 | if (isVerbose() && IsAIX) |
1151 | OutStreamer->getCommentOS() << MO << '\n'; |
1152 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1153 | return; |
1154 | } |
1155 | case PPC::ADDIStocHA: { |
1156 | const MachineOperand &MO = MI->getOperand(i: 2); |
1157 | |
1158 | assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && |
1159 | "Invalid operand for ADDIStocHA." ); |
1160 | assert((IsAIX && !IsPPC64 && |
1161 | getCodeModel(*Subtarget, TM, MO) == CodeModel::Large) && |
1162 | "This pseudo should only be selected for 32-bit large code model on" |
1163 | " AIX." ); |
1164 | |
1165 | // Transform %rd = ADDIStocHA %rA, @sym(%r2) |
1166 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1167 | |
1168 | // Change the opcode to ADDIS. |
1169 | TmpInst.setOpcode(PPC::ADDIS); |
1170 | |
1171 | // Map the machine operand to its corresponding MCSymbol. |
1172 | MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, AP&: *this); |
1173 | |
1174 | MCSymbolRefExpr::VariantKind VK = GetVKForMO(MO); |
1175 | |
1176 | // Map the global address operand to be a reference to the TOC entry we |
1177 | // will synthesize later. 'TOCEntry' is a label used to reference the |
1178 | // storage allocated in the TOC which contains the address of 'MOSymbol'. |
1179 | // If the symbol does not have the toc-data attribute, then we create the |
1180 | // TOC entry on AIX. If the toc-data attribute is used, the TOC entry |
1181 | // contains the data rather than the address of the MOSymbol. |
1182 | if (![](const MachineOperand &MO) { |
1183 | if (!MO.isGlobal()) |
1184 | return false; |
1185 | |
1186 | const GlobalVariable *GV = dyn_cast<GlobalVariable>(Val: MO.getGlobal()); |
1187 | if (!GV) |
1188 | return false; |
1189 | return GV->hasAttribute(Kind: "toc-data" ); |
1190 | }(MO)) { |
1191 | MOSymbol = lookUpOrCreateTOCEntry(Sym: MOSymbol, Type: getTOCEntryTypeForMO(MO), Kind: VK); |
1192 | } |
1193 | |
1194 | const MCExpr *Exp = MCSymbolRefExpr::create( |
1195 | Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_PPC_U, Ctx&: OutContext); |
1196 | TmpInst.getOperand(i: 2) = MCOperand::createExpr(Val: Exp); |
1197 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1198 | return; |
1199 | } |
1200 | case PPC::LWZtocL: { |
1201 | const MachineOperand &MO = MI->getOperand(i: 1); |
1202 | |
1203 | assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && |
1204 | "Invalid operand for LWZtocL." ); |
1205 | assert(IsAIX && !IsPPC64 && |
1206 | getCodeModel(*Subtarget, TM, MO) == CodeModel::Large && |
1207 | "This pseudo should only be selected for 32-bit large code model on" |
1208 | " AIX." ); |
1209 | |
1210 | // Transform %rd = LWZtocL @sym, %rs. |
1211 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1212 | |
1213 | // Change the opcode to lwz. |
1214 | TmpInst.setOpcode(PPC::LWZ); |
1215 | |
1216 | // Map the machine operand to its corresponding MCSymbol. |
1217 | MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, AP&: *this); |
1218 | |
1219 | MCSymbolRefExpr::VariantKind VK = GetVKForMO(MO); |
1220 | |
1221 | // Always use TOC on AIX. Map the global address operand to be a reference |
1222 | // to the TOC entry we will synthesize later. 'TOCEntry' is a label used to |
1223 | // reference the storage allocated in the TOC which contains the address of |
1224 | // 'MOSymbol'. |
1225 | MCSymbol *TOCEntry = |
1226 | lookUpOrCreateTOCEntry(Sym: MOSymbol, Type: getTOCEntryTypeForMO(MO), Kind: VK); |
1227 | const MCExpr *Exp = MCSymbolRefExpr::create(Symbol: TOCEntry, |
1228 | Kind: MCSymbolRefExpr::VK_PPC_L, |
1229 | Ctx&: OutContext); |
1230 | TmpInst.getOperand(i: 1) = MCOperand::createExpr(Val: Exp); |
1231 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1232 | return; |
1233 | } |
1234 | case PPC::ADDIStocHA8: { |
1235 | // Transform %xd = ADDIStocHA8 %x2, @sym |
1236 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1237 | |
1238 | // Change the opcode to ADDIS8. If the global address is the address of |
1239 | // an external symbol, is a jump table address, is a block address, or is a |
1240 | // constant pool index with large code model enabled, then generate a TOC |
1241 | // entry and reference that. Otherwise, reference the symbol directly. |
1242 | TmpInst.setOpcode(PPC::ADDIS8); |
1243 | |
1244 | const MachineOperand &MO = MI->getOperand(i: 2); |
1245 | assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && |
1246 | "Invalid operand for ADDIStocHA8!" ); |
1247 | |
1248 | const MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, AP&: *this); |
1249 | |
1250 | MCSymbolRefExpr::VariantKind VK = GetVKForMO(MO); |
1251 | |
1252 | const bool GlobalToc = |
1253 | MO.isGlobal() && Subtarget->isGVIndirectSymbol(GV: MO.getGlobal()); |
1254 | |
1255 | const CodeModel::Model CM = |
1256 | IsAIX ? getCodeModel(S: *Subtarget, TM, MO) : TM.getCodeModel(); |
1257 | |
1258 | if (GlobalToc || MO.isJTI() || MO.isBlockAddress() || |
1259 | (MO.isCPI() && CM == CodeModel::Large)) |
1260 | MOSymbol = lookUpOrCreateTOCEntry(Sym: MOSymbol, Type: getTOCEntryTypeForMO(MO), Kind: VK); |
1261 | |
1262 | VK = IsAIX ? MCSymbolRefExpr::VK_PPC_U : MCSymbolRefExpr::VK_PPC_TOC_HA; |
1263 | |
1264 | const MCExpr *Exp = |
1265 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: VK, Ctx&: OutContext); |
1266 | |
1267 | if (!MO.isJTI() && MO.getOffset()) |
1268 | Exp = MCBinaryExpr::createAdd(LHS: Exp, |
1269 | RHS: MCConstantExpr::create(Value: MO.getOffset(), |
1270 | Ctx&: OutContext), |
1271 | Ctx&: OutContext); |
1272 | |
1273 | TmpInst.getOperand(i: 2) = MCOperand::createExpr(Val: Exp); |
1274 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1275 | return; |
1276 | } |
1277 | case PPC::LDtocL: { |
1278 | // Transform %xd = LDtocL @sym, %xs |
1279 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1280 | |
1281 | // Change the opcode to LD. If the global address is the address of |
1282 | // an external symbol, is a jump table address, is a block address, or is |
1283 | // a constant pool index with large code model enabled, then generate a |
1284 | // TOC entry and reference that. Otherwise, reference the symbol directly. |
1285 | TmpInst.setOpcode(PPC::LD); |
1286 | |
1287 | const MachineOperand &MO = MI->getOperand(i: 1); |
1288 | assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || |
1289 | MO.isBlockAddress()) && |
1290 | "Invalid operand for LDtocL!" ); |
1291 | |
1292 | LLVM_DEBUG(assert( |
1293 | (!MO.isGlobal() || Subtarget->isGVIndirectSymbol(MO.getGlobal())) && |
1294 | "LDtocL used on symbol that could be accessed directly is " |
1295 | "invalid. Must match ADDIStocHA8." )); |
1296 | |
1297 | const MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, AP&: *this); |
1298 | |
1299 | MCSymbolRefExpr::VariantKind VK = GetVKForMO(MO); |
1300 | CodeModel::Model CM = |
1301 | IsAIX ? getCodeModel(S: *Subtarget, TM, MO) : TM.getCodeModel(); |
1302 | if (!MO.isCPI() || CM == CodeModel::Large) |
1303 | MOSymbol = lookUpOrCreateTOCEntry(Sym: MOSymbol, Type: getTOCEntryTypeForMO(MO), Kind: VK); |
1304 | |
1305 | VK = IsAIX ? MCSymbolRefExpr::VK_PPC_L : MCSymbolRefExpr::VK_PPC_TOC_LO; |
1306 | const MCExpr *Exp = |
1307 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: VK, Ctx&: OutContext); |
1308 | TmpInst.getOperand(i: 1) = MCOperand::createExpr(Val: Exp); |
1309 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1310 | return; |
1311 | } |
1312 | case PPC::ADDItocL: |
1313 | case PPC::ADDItocL8: { |
1314 | // Transform %xd = ADDItocL %xs, @sym |
1315 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1316 | |
1317 | unsigned Op = MI->getOpcode(); |
1318 | |
1319 | // Change the opcode to load address for toc-data. |
1320 | // ADDItocL is only used for 32-bit toc-data on AIX and will always use LA. |
1321 | TmpInst.setOpcode(Op == PPC::ADDItocL8 ? (IsAIX ? PPC::LA8 : PPC::ADDI8) |
1322 | : PPC::LA); |
1323 | |
1324 | const MachineOperand &MO = MI->getOperand(i: 2); |
1325 | assert((Op == PPC::ADDItocL8) |
1326 | ? (MO.isGlobal() || MO.isCPI()) |
1327 | : MO.isGlobal() && "Invalid operand for ADDItocL8." ); |
1328 | assert(!(MO.isGlobal() && Subtarget->isGVIndirectSymbol(MO.getGlobal())) && |
1329 | "Interposable definitions must use indirect accesses." ); |
1330 | |
1331 | // Map the operand to its corresponding MCSymbol. |
1332 | const MCSymbol *const MOSymbol = getMCSymbolForTOCPseudoMO(MO, AP&: *this); |
1333 | |
1334 | const MCExpr *Exp = MCSymbolRefExpr::create( |
1335 | Symbol: MOSymbol, |
1336 | Kind: IsAIX ? MCSymbolRefExpr::VK_PPC_L : MCSymbolRefExpr::VK_PPC_TOC_LO, |
1337 | Ctx&: OutContext); |
1338 | |
1339 | TmpInst.getOperand(i: 2) = MCOperand::createExpr(Val: Exp); |
1340 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1341 | return; |
1342 | } |
1343 | case PPC::ADDISgotTprelHA: { |
1344 | // Transform: %xd = ADDISgotTprelHA %x2, @sym |
1345 | // Into: %xd = ADDIS8 %x2, sym@got@tlsgd@ha |
1346 | assert(IsPPC64 && "Not supported for 32-bit PowerPC" ); |
1347 | const MachineOperand &MO = MI->getOperand(i: 2); |
1348 | const GlobalValue *GValue = MO.getGlobal(); |
1349 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1350 | const MCExpr *SymGotTprel = |
1351 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_PPC_GOT_TPREL_HA, |
1352 | Ctx&: OutContext); |
1353 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::ADDIS8) |
1354 | .addReg(Reg: MI->getOperand(i: 0).getReg()) |
1355 | .addReg(Reg: MI->getOperand(i: 1).getReg()) |
1356 | .addExpr(Val: SymGotTprel)); |
1357 | return; |
1358 | } |
1359 | case PPC::LDgotTprelL: |
1360 | case PPC::LDgotTprelL32: { |
1361 | // Transform %xd = LDgotTprelL @sym, %xs |
1362 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1363 | |
1364 | // Change the opcode to LD. |
1365 | TmpInst.setOpcode(IsPPC64 ? PPC::LD : PPC::LWZ); |
1366 | const MachineOperand &MO = MI->getOperand(i: 1); |
1367 | const GlobalValue *GValue = MO.getGlobal(); |
1368 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1369 | const MCExpr *Exp = MCSymbolRefExpr::create( |
1370 | Symbol: MOSymbol, Kind: IsPPC64 ? MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO |
1371 | : MCSymbolRefExpr::VK_PPC_GOT_TPREL, |
1372 | Ctx&: OutContext); |
1373 | TmpInst.getOperand(i: 1) = MCOperand::createExpr(Val: Exp); |
1374 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1375 | return; |
1376 | } |
1377 | |
1378 | case PPC::PPC32PICGOT: { |
1379 | MCSymbol *GOTSymbol = OutContext.getOrCreateSymbol(Name: StringRef("_GLOBAL_OFFSET_TABLE_" )); |
1380 | MCSymbol *GOTRef = OutContext.createTempSymbol(); |
1381 | MCSymbol *NextInstr = OutContext.createTempSymbol(); |
1382 | |
1383 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::BL) |
1384 | // FIXME: We would like an efficient form for this, so we don't have to do |
1385 | // a lot of extra uniquing. |
1386 | .addExpr(Val: MCSymbolRefExpr::create(Symbol: NextInstr, Ctx&: OutContext))); |
1387 | const MCExpr *OffsExpr = |
1388 | MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: GOTSymbol, Ctx&: OutContext), |
1389 | RHS: MCSymbolRefExpr::create(Symbol: GOTRef, Ctx&: OutContext), |
1390 | Ctx&: OutContext); |
1391 | OutStreamer->emitLabel(Symbol: GOTRef); |
1392 | OutStreamer->emitValue(Value: OffsExpr, Size: 4); |
1393 | OutStreamer->emitLabel(Symbol: NextInstr); |
1394 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::MFLR) |
1395 | .addReg(Reg: MI->getOperand(i: 0).getReg())); |
1396 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::LWZ) |
1397 | .addReg(Reg: MI->getOperand(i: 1).getReg()) |
1398 | .addImm(Val: 0) |
1399 | .addReg(Reg: MI->getOperand(i: 0).getReg())); |
1400 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::ADD4) |
1401 | .addReg(Reg: MI->getOperand(i: 0).getReg()) |
1402 | .addReg(Reg: MI->getOperand(i: 1).getReg()) |
1403 | .addReg(Reg: MI->getOperand(i: 0).getReg())); |
1404 | return; |
1405 | } |
1406 | case PPC::PPC32GOT: { |
1407 | MCSymbol *GOTSymbol = |
1408 | OutContext.getOrCreateSymbol(Name: StringRef("_GLOBAL_OFFSET_TABLE_" )); |
1409 | const MCExpr *SymGotTlsL = MCSymbolRefExpr::create( |
1410 | Symbol: GOTSymbol, Kind: MCSymbolRefExpr::VK_PPC_LO, Ctx&: OutContext); |
1411 | const MCExpr *SymGotTlsHA = MCSymbolRefExpr::create( |
1412 | Symbol: GOTSymbol, Kind: MCSymbolRefExpr::VK_PPC_HA, Ctx&: OutContext); |
1413 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::LI) |
1414 | .addReg(Reg: MI->getOperand(i: 0).getReg()) |
1415 | .addExpr(Val: SymGotTlsL)); |
1416 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::ADDIS) |
1417 | .addReg(Reg: MI->getOperand(i: 0).getReg()) |
1418 | .addReg(Reg: MI->getOperand(i: 0).getReg()) |
1419 | .addExpr(Val: SymGotTlsHA)); |
1420 | return; |
1421 | } |
1422 | case PPC::ADDIStlsgdHA: { |
1423 | // Transform: %xd = ADDIStlsgdHA %x2, @sym |
1424 | // Into: %xd = ADDIS8 %x2, sym@got@tlsgd@ha |
1425 | assert(IsPPC64 && "Not supported for 32-bit PowerPC" ); |
1426 | const MachineOperand &MO = MI->getOperand(i: 2); |
1427 | const GlobalValue *GValue = MO.getGlobal(); |
1428 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1429 | const MCExpr *SymGotTlsGD = |
1430 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HA, |
1431 | Ctx&: OutContext); |
1432 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::ADDIS8) |
1433 | .addReg(Reg: MI->getOperand(i: 0).getReg()) |
1434 | .addReg(Reg: MI->getOperand(i: 1).getReg()) |
1435 | .addExpr(Val: SymGotTlsGD)); |
1436 | return; |
1437 | } |
1438 | case PPC::ADDItlsgdL: |
1439 | // Transform: %xd = ADDItlsgdL %xs, @sym |
1440 | // Into: %xd = ADDI8 %xs, sym@got@tlsgd@l |
1441 | case PPC::ADDItlsgdL32: { |
1442 | // Transform: %rd = ADDItlsgdL32 %rs, @sym |
1443 | // Into: %rd = ADDI %rs, sym@got@tlsgd |
1444 | const MachineOperand &MO = MI->getOperand(i: 2); |
1445 | const GlobalValue *GValue = MO.getGlobal(); |
1446 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1447 | const MCExpr *SymGotTlsGD = MCSymbolRefExpr::create( |
1448 | Symbol: MOSymbol, Kind: IsPPC64 ? MCSymbolRefExpr::VK_PPC_GOT_TLSGD_LO |
1449 | : MCSymbolRefExpr::VK_PPC_GOT_TLSGD, |
1450 | Ctx&: OutContext); |
1451 | EmitToStreamer(S&: *OutStreamer, |
1452 | Inst: MCInstBuilder(IsPPC64 ? PPC::ADDI8 : PPC::ADDI) |
1453 | .addReg(Reg: MI->getOperand(i: 0).getReg()) |
1454 | .addReg(Reg: MI->getOperand(i: 1).getReg()) |
1455 | .addExpr(Val: SymGotTlsGD)); |
1456 | return; |
1457 | } |
1458 | case PPC::GETtlsMOD32AIX: |
1459 | case PPC::GETtlsMOD64AIX: |
1460 | // Transform: %r3 = GETtlsMODNNAIX %r3 (for NN == 32/64). |
1461 | // Into: BLA .__tls_get_mod() |
1462 | // Input parameter is a module handle (_$TLSML[TC]@ml) for all variables. |
1463 | case PPC::GETtlsADDR: |
1464 | // Transform: %x3 = GETtlsADDR %x3, @sym |
1465 | // Into: BL8_NOP_TLS __tls_get_addr(sym at tlsgd) |
1466 | case PPC::GETtlsADDRPCREL: |
1467 | case PPC::GETtlsADDR32AIX: |
1468 | case PPC::GETtlsADDR64AIX: |
1469 | // Transform: %r3 = GETtlsADDRNNAIX %r3, %r4 (for NN == 32/64). |
1470 | // Into: BLA .__tls_get_addr() |
1471 | // Unlike on Linux, there is no symbol or relocation needed for this call. |
1472 | case PPC::GETtlsADDR32: { |
1473 | // Transform: %r3 = GETtlsADDR32 %r3, @sym |
1474 | // Into: BL_TLS __tls_get_addr(sym at tlsgd)@PLT |
1475 | EmitTlsCall(MI, VK: MCSymbolRefExpr::VK_PPC_TLSGD); |
1476 | return; |
1477 | } |
1478 | case PPC::GETtlsTpointer32AIX: { |
1479 | // Transform: %r3 = GETtlsTpointer32AIX |
1480 | // Into: BLA .__get_tpointer() |
1481 | EmitAIXTlsCallHelper(MI); |
1482 | return; |
1483 | } |
1484 | case PPC::ADDIStlsldHA: { |
1485 | // Transform: %xd = ADDIStlsldHA %x2, @sym |
1486 | // Into: %xd = ADDIS8 %x2, sym@got@tlsld@ha |
1487 | assert(IsPPC64 && "Not supported for 32-bit PowerPC" ); |
1488 | const MachineOperand &MO = MI->getOperand(i: 2); |
1489 | const GlobalValue *GValue = MO.getGlobal(); |
1490 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1491 | const MCExpr *SymGotTlsLD = |
1492 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HA, |
1493 | Ctx&: OutContext); |
1494 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::ADDIS8) |
1495 | .addReg(Reg: MI->getOperand(i: 0).getReg()) |
1496 | .addReg(Reg: MI->getOperand(i: 1).getReg()) |
1497 | .addExpr(Val: SymGotTlsLD)); |
1498 | return; |
1499 | } |
1500 | case PPC::ADDItlsldL: |
1501 | // Transform: %xd = ADDItlsldL %xs, @sym |
1502 | // Into: %xd = ADDI8 %xs, sym@got@tlsld@l |
1503 | case PPC::ADDItlsldL32: { |
1504 | // Transform: %rd = ADDItlsldL32 %rs, @sym |
1505 | // Into: %rd = ADDI %rs, sym@got@tlsld |
1506 | const MachineOperand &MO = MI->getOperand(i: 2); |
1507 | const GlobalValue *GValue = MO.getGlobal(); |
1508 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1509 | const MCExpr *SymGotTlsLD = MCSymbolRefExpr::create( |
1510 | Symbol: MOSymbol, Kind: IsPPC64 ? MCSymbolRefExpr::VK_PPC_GOT_TLSLD_LO |
1511 | : MCSymbolRefExpr::VK_PPC_GOT_TLSLD, |
1512 | Ctx&: OutContext); |
1513 | EmitToStreamer(S&: *OutStreamer, |
1514 | Inst: MCInstBuilder(IsPPC64 ? PPC::ADDI8 : PPC::ADDI) |
1515 | .addReg(Reg: MI->getOperand(i: 0).getReg()) |
1516 | .addReg(Reg: MI->getOperand(i: 1).getReg()) |
1517 | .addExpr(Val: SymGotTlsLD)); |
1518 | return; |
1519 | } |
1520 | case PPC::GETtlsldADDR: |
1521 | // Transform: %x3 = GETtlsldADDR %x3, @sym |
1522 | // Into: BL8_NOP_TLS __tls_get_addr(sym at tlsld) |
1523 | case PPC::GETtlsldADDRPCREL: |
1524 | case PPC::GETtlsldADDR32: { |
1525 | // Transform: %r3 = GETtlsldADDR32 %r3, @sym |
1526 | // Into: BL_TLS __tls_get_addr(sym at tlsld)@PLT |
1527 | EmitTlsCall(MI, VK: MCSymbolRefExpr::VK_PPC_TLSLD); |
1528 | return; |
1529 | } |
1530 | case PPC::ADDISdtprelHA: |
1531 | // Transform: %xd = ADDISdtprelHA %xs, @sym |
1532 | // Into: %xd = ADDIS8 %xs, sym@dtprel@ha |
1533 | case PPC::ADDISdtprelHA32: { |
1534 | // Transform: %rd = ADDISdtprelHA32 %rs, @sym |
1535 | // Into: %rd = ADDIS %rs, sym@dtprel@ha |
1536 | const MachineOperand &MO = MI->getOperand(i: 2); |
1537 | const GlobalValue *GValue = MO.getGlobal(); |
1538 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1539 | const MCExpr *SymDtprel = |
1540 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_PPC_DTPREL_HA, |
1541 | Ctx&: OutContext); |
1542 | EmitToStreamer( |
1543 | S&: *OutStreamer, |
1544 | Inst: MCInstBuilder(IsPPC64 ? PPC::ADDIS8 : PPC::ADDIS) |
1545 | .addReg(Reg: MI->getOperand(i: 0).getReg()) |
1546 | .addReg(Reg: MI->getOperand(i: 1).getReg()) |
1547 | .addExpr(Val: SymDtprel)); |
1548 | return; |
1549 | } |
1550 | case PPC::PADDIdtprel: { |
1551 | // Transform: %rd = PADDIdtprel %rs, @sym |
1552 | // Into: %rd = PADDI8 %rs, sym@dtprel |
1553 | const MachineOperand &MO = MI->getOperand(i: 2); |
1554 | const GlobalValue *GValue = MO.getGlobal(); |
1555 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1556 | const MCExpr *SymDtprel = MCSymbolRefExpr::create( |
1557 | Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_DTPREL, Ctx&: OutContext); |
1558 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::PADDI8) |
1559 | .addReg(Reg: MI->getOperand(i: 0).getReg()) |
1560 | .addReg(Reg: MI->getOperand(i: 1).getReg()) |
1561 | .addExpr(Val: SymDtprel)); |
1562 | return; |
1563 | } |
1564 | |
1565 | case PPC::ADDIdtprelL: |
1566 | // Transform: %xd = ADDIdtprelL %xs, @sym |
1567 | // Into: %xd = ADDI8 %xs, sym@dtprel@l |
1568 | case PPC::ADDIdtprelL32: { |
1569 | // Transform: %rd = ADDIdtprelL32 %rs, @sym |
1570 | // Into: %rd = ADDI %rs, sym@dtprel@l |
1571 | const MachineOperand &MO = MI->getOperand(i: 2); |
1572 | const GlobalValue *GValue = MO.getGlobal(); |
1573 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1574 | const MCExpr *SymDtprel = |
1575 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_PPC_DTPREL_LO, |
1576 | Ctx&: OutContext); |
1577 | EmitToStreamer(S&: *OutStreamer, |
1578 | Inst: MCInstBuilder(IsPPC64 ? PPC::ADDI8 : PPC::ADDI) |
1579 | .addReg(Reg: MI->getOperand(i: 0).getReg()) |
1580 | .addReg(Reg: MI->getOperand(i: 1).getReg()) |
1581 | .addExpr(Val: SymDtprel)); |
1582 | return; |
1583 | } |
1584 | case PPC::MFOCRF: |
1585 | case PPC::MFOCRF8: |
1586 | if (!Subtarget->hasMFOCRF()) { |
1587 | // Transform: %r3 = MFOCRF %cr7 |
1588 | // Into: %r3 = MFCR ;; cr7 |
1589 | unsigned NewOpcode = |
1590 | MI->getOpcode() == PPC::MFOCRF ? PPC::MFCR : PPC::MFCR8; |
1591 | OutStreamer->AddComment(T: PPCInstPrinter:: |
1592 | getRegisterName(Reg: MI->getOperand(i: 1).getReg())); |
1593 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(NewOpcode) |
1594 | .addReg(Reg: MI->getOperand(i: 0).getReg())); |
1595 | return; |
1596 | } |
1597 | break; |
1598 | case PPC::MTOCRF: |
1599 | case PPC::MTOCRF8: |
1600 | if (!Subtarget->hasMFOCRF()) { |
1601 | // Transform: %cr7 = MTOCRF %r3 |
1602 | // Into: MTCRF mask, %r3 ;; cr7 |
1603 | unsigned NewOpcode = |
1604 | MI->getOpcode() == PPC::MTOCRF ? PPC::MTCRF : PPC::MTCRF8; |
1605 | unsigned Mask = 0x80 >> OutContext.getRegisterInfo() |
1606 | ->getEncodingValue(RegNo: MI->getOperand(i: 0).getReg()); |
1607 | OutStreamer->AddComment(T: PPCInstPrinter:: |
1608 | getRegisterName(Reg: MI->getOperand(i: 0).getReg())); |
1609 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(NewOpcode) |
1610 | .addImm(Val: Mask) |
1611 | .addReg(Reg: MI->getOperand(i: 1).getReg())); |
1612 | return; |
1613 | } |
1614 | break; |
1615 | case PPC::LD: |
1616 | case PPC::STD: |
1617 | case PPC::LWA_32: |
1618 | case PPC::LWA: { |
1619 | // Verify alignment is legal, so we don't create relocations |
1620 | // that can't be supported. |
1621 | unsigned OpNum = (MI->getOpcode() == PPC::STD) ? 2 : 1; |
1622 | // For non-TOC-based local-exec TLS accesses with non-zero offsets, the |
1623 | // machine operand (which is a TargetGlobalTLSAddress) is expected to be |
1624 | // the same operand for both loads and stores. |
1625 | for (const MachineOperand &TempMO : MI->operands()) { |
1626 | if (((TempMO.getTargetFlags() == PPCII::MO_TPREL_FLAG || |
1627 | TempMO.getTargetFlags() == PPCII::MO_TLSLD_FLAG)) && |
1628 | TempMO.getOperandNo() == 1) |
1629 | OpNum = 1; |
1630 | } |
1631 | const MachineOperand &MO = MI->getOperand(i: OpNum); |
1632 | if (MO.isGlobal()) { |
1633 | const DataLayout &DL = MO.getGlobal()->getDataLayout(); |
1634 | if (MO.getGlobal()->getPointerAlignment(DL) < 4) |
1635 | llvm_unreachable("Global must be word-aligned for LD, STD, LWA!" ); |
1636 | } |
1637 | // As these load/stores share common code with the following load/stores, |
1638 | // fall through to the subsequent cases in order to either process the |
1639 | // non-TOC-based local-exec sequence or to process the instruction normally. |
1640 | [[fallthrough]]; |
1641 | } |
1642 | case PPC::LBZ: |
1643 | case PPC::LBZ8: |
1644 | case PPC::LHA: |
1645 | case PPC::LHA8: |
1646 | case PPC::LHZ: |
1647 | case PPC::LHZ8: |
1648 | case PPC::LWZ: |
1649 | case PPC::LWZ8: |
1650 | case PPC::STB: |
1651 | case PPC::STB8: |
1652 | case PPC::STH: |
1653 | case PPC::STH8: |
1654 | case PPC::STW: |
1655 | case PPC::STW8: |
1656 | case PPC::LFS: |
1657 | case PPC::STFS: |
1658 | case PPC::LFD: |
1659 | case PPC::STFD: |
1660 | case PPC::ADDI8: { |
1661 | // A faster non-TOC-based local-[exec|dynamic] sequence is represented by |
1662 | // `addi` or a load/store instruction (that directly loads or stores off of |
1663 | // the thread pointer) with an immediate operand having the |
1664 | // [MO_TPREL_FLAG|MO_TLSLD_FLAG]. Such instructions do not otherwise arise. |
1665 | if (!HasAIXSmallLocalTLS) |
1666 | break; |
1667 | bool IsMIADDI8 = MI->getOpcode() == PPC::ADDI8; |
1668 | unsigned OpNum = IsMIADDI8 ? 2 : 1; |
1669 | const MachineOperand &MO = MI->getOperand(i: OpNum); |
1670 | unsigned Flag = MO.getTargetFlags(); |
1671 | if (Flag == PPCII::MO_TPREL_FLAG || |
1672 | Flag == PPCII::MO_GOT_TPREL_PCREL_FLAG || |
1673 | Flag == PPCII::MO_TPREL_PCREL_FLAG || Flag == PPCII::MO_TLSLD_FLAG) { |
1674 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1675 | |
1676 | const MCExpr *Expr = getAdjustedFasterLocalExpr(MO, Offset: MO.getOffset()); |
1677 | if (Expr) |
1678 | TmpInst.getOperand(i: OpNum) = MCOperand::createExpr(Val: Expr); |
1679 | |
1680 | // Change the opcode to load address if the original opcode is an `addi`. |
1681 | if (IsMIADDI8) |
1682 | TmpInst.setOpcode(PPC::LA8); |
1683 | |
1684 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1685 | return; |
1686 | } |
1687 | // Now process the instruction normally. |
1688 | break; |
1689 | } |
1690 | case PPC::PseudoEIEIO: { |
1691 | EmitToStreamer( |
1692 | S&: *OutStreamer, |
1693 | Inst: MCInstBuilder(PPC::ORI).addReg(Reg: PPC::X2).addReg(Reg: PPC::X2).addImm(Val: 0)); |
1694 | EmitToStreamer( |
1695 | S&: *OutStreamer, |
1696 | Inst: MCInstBuilder(PPC::ORI).addReg(Reg: PPC::X2).addReg(Reg: PPC::X2).addImm(Val: 0)); |
1697 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::EnforceIEIO)); |
1698 | return; |
1699 | } |
1700 | } |
1701 | |
1702 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1703 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1704 | } |
1705 | |
1706 | // For non-TOC-based local-[exec|dynamic] variables that have a non-zero offset, |
1707 | // we need to create a new MCExpr that adds the non-zero offset to the address |
1708 | // of the local-[exec|dynamic] variable that will be used in either an addi, |
1709 | // load or store. However, the final displacement for these instructions must be |
1710 | // between [-32768, 32768), so if the TLS address + its non-zero offset is |
1711 | // greater than 32KB, a new MCExpr is produced to accommodate this situation. |
1712 | const MCExpr * |
1713 | PPCAsmPrinter::getAdjustedFasterLocalExpr(const MachineOperand &MO, |
1714 | int64_t Offset) { |
1715 | // Non-zero offsets (for loads, stores or `addi`) require additional handling. |
1716 | // When the offset is zero, there is no need to create an adjusted MCExpr. |
1717 | if (!Offset) |
1718 | return nullptr; |
1719 | |
1720 | assert(MO.isGlobal() && "Only expecting a global MachineOperand here!" ); |
1721 | const GlobalValue *GValue = MO.getGlobal(); |
1722 | TLSModel::Model Model = TM.getTLSModel(GV: GValue); |
1723 | assert((Model == TLSModel::LocalExec || Model == TLSModel::LocalDynamic) && |
1724 | "Only local-[exec|dynamic] accesses are handled!" ); |
1725 | |
1726 | bool IsGlobalADeclaration = GValue->isDeclarationForLinker(); |
1727 | // Find the GlobalVariable that corresponds to the particular TLS variable |
1728 | // in the TLS variable-to-address mapping. All TLS variables should exist |
1729 | // within this map, with the exception of TLS variables marked as extern. |
1730 | const auto TLSVarsMapEntryIter = TLSVarsToAddressMapping.find(Key: GValue); |
1731 | if (TLSVarsMapEntryIter == TLSVarsToAddressMapping.end()) |
1732 | assert(IsGlobalADeclaration && |
1733 | "Only expecting to find extern TLS variables not present in the TLS " |
1734 | "variable-to-address map!" ); |
1735 | |
1736 | unsigned TLSVarAddress = |
1737 | IsGlobalADeclaration ? 0 : TLSVarsMapEntryIter->second; |
1738 | ptrdiff_t FinalAddress = (TLSVarAddress + Offset); |
1739 | // If the address of the TLS variable + the offset is less than 32KB, |
1740 | // or if the TLS variable is extern, we simply produce an MCExpr to add the |
1741 | // non-zero offset to the TLS variable address. |
1742 | // For when TLS variables are extern, this is safe to do because we can |
1743 | // assume that the address of extern TLS variables are zero. |
1744 | const MCExpr *Expr = MCSymbolRefExpr::create( |
1745 | Symbol: getSymbol(GV: GValue), |
1746 | Kind: Model == TLSModel::LocalExec ? MCSymbolRefExpr::VK_PPC_AIX_TLSLE |
1747 | : MCSymbolRefExpr::VK_PPC_AIX_TLSLD, |
1748 | Ctx&: OutContext); |
1749 | Expr = MCBinaryExpr::createAdd( |
1750 | LHS: Expr, RHS: MCConstantExpr::create(Value: Offset, Ctx&: OutContext), Ctx&: OutContext); |
1751 | if (FinalAddress >= 32768) { |
1752 | // Handle the written offset for cases where: |
1753 | // TLS variable address + Offset > 32KB. |
1754 | |
1755 | // The assembly that is printed will look like: |
1756 | // TLSVar@le + Offset - Delta |
1757 | // where Delta is a multiple of 64KB: ((FinalAddress + 32768) & ~0xFFFF). |
1758 | ptrdiff_t Delta = ((FinalAddress + 32768) & ~0xFFFF); |
1759 | // Check that the total instruction displacement fits within [-32768,32768). |
1760 | [[maybe_unused]] ptrdiff_t InstDisp = TLSVarAddress + Offset - Delta; |
1761 | assert( |
1762 | ((InstDisp < 32768) && (InstDisp >= -32768)) && |
1763 | "Expecting the instruction displacement for local-[exec|dynamic] TLS " |
1764 | "variables to be between [-32768, 32768)!" ); |
1765 | Expr = MCBinaryExpr::createAdd( |
1766 | LHS: Expr, RHS: MCConstantExpr::create(Value: -Delta, Ctx&: OutContext), Ctx&: OutContext); |
1767 | } |
1768 | |
1769 | return Expr; |
1770 | } |
1771 | |
1772 | void PPCLinuxAsmPrinter::emitGNUAttributes(Module &M) { |
1773 | // Emit float ABI into GNU attribute |
1774 | Metadata *MD = M.getModuleFlag(Key: "float-abi" ); |
1775 | MDString *FloatABI = dyn_cast_or_null<MDString>(Val: MD); |
1776 | if (!FloatABI) |
1777 | return; |
1778 | StringRef flt = FloatABI->getString(); |
1779 | // TODO: Support emitting soft-fp and hard double/single attributes. |
1780 | if (flt == "doubledouble" ) |
1781 | OutStreamer->emitGNUAttribute(Tag: Tag_GNU_Power_ABI_FP, |
1782 | Value: Val_GNU_Power_ABI_HardFloat_DP | |
1783 | Val_GNU_Power_ABI_LDBL_IBM128); |
1784 | else if (flt == "ieeequad" ) |
1785 | OutStreamer->emitGNUAttribute(Tag: Tag_GNU_Power_ABI_FP, |
1786 | Value: Val_GNU_Power_ABI_HardFloat_DP | |
1787 | Val_GNU_Power_ABI_LDBL_IEEE128); |
1788 | else if (flt == "ieeedouble" ) |
1789 | OutStreamer->emitGNUAttribute(Tag: Tag_GNU_Power_ABI_FP, |
1790 | Value: Val_GNU_Power_ABI_HardFloat_DP | |
1791 | Val_GNU_Power_ABI_LDBL_64); |
1792 | } |
1793 | |
1794 | void PPCLinuxAsmPrinter::emitInstruction(const MachineInstr *MI) { |
1795 | if (!Subtarget->isPPC64()) |
1796 | return PPCAsmPrinter::emitInstruction(MI); |
1797 | |
1798 | switch (MI->getOpcode()) { |
1799 | default: |
1800 | break; |
1801 | case TargetOpcode::PATCHABLE_FUNCTION_ENTER: { |
1802 | // .begin: |
1803 | // b .end # lis 0, FuncId[16..32] |
1804 | // nop # li 0, FuncId[0..15] |
1805 | // std 0, -8(1) |
1806 | // mflr 0 |
1807 | // bl __xray_FunctionEntry |
1808 | // mtlr 0 |
1809 | // .end: |
1810 | // |
1811 | // Update compiler-rt/lib/xray/xray_powerpc64.cc accordingly when number |
1812 | // of instructions change. |
1813 | // XRAY is only supported on PPC Linux little endian. |
1814 | if (!MAI->isLittleEndian()) |
1815 | break; |
1816 | MCSymbol *BeginOfSled = OutContext.createTempSymbol(); |
1817 | MCSymbol *EndOfSled = OutContext.createTempSymbol(); |
1818 | OutStreamer->emitLabel(Symbol: BeginOfSled); |
1819 | EmitToStreamer(S&: *OutStreamer, |
1820 | Inst: MCInstBuilder(PPC::B).addExpr( |
1821 | Val: MCSymbolRefExpr::create(Symbol: EndOfSled, Ctx&: OutContext))); |
1822 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::NOP)); |
1823 | EmitToStreamer( |
1824 | S&: *OutStreamer, |
1825 | Inst: MCInstBuilder(PPC::STD).addReg(Reg: PPC::X0).addImm(Val: -8).addReg(Reg: PPC::X1)); |
1826 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::MFLR8).addReg(Reg: PPC::X0)); |
1827 | EmitToStreamer(S&: *OutStreamer, |
1828 | Inst: MCInstBuilder(PPC::BL8_NOP) |
1829 | .addExpr(Val: MCSymbolRefExpr::create( |
1830 | Symbol: OutContext.getOrCreateSymbol(Name: "__xray_FunctionEntry" ), |
1831 | Ctx&: OutContext))); |
1832 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::MTLR8).addReg(Reg: PPC::X0)); |
1833 | OutStreamer->emitLabel(Symbol: EndOfSled); |
1834 | recordSled(Sled: BeginOfSled, MI: *MI, Kind: SledKind::FUNCTION_ENTER, Version: 2); |
1835 | break; |
1836 | } |
1837 | case TargetOpcode::PATCHABLE_RET: { |
1838 | unsigned RetOpcode = MI->getOperand(i: 0).getImm(); |
1839 | MCInst RetInst; |
1840 | RetInst.setOpcode(RetOpcode); |
1841 | for (const auto &MO : llvm::drop_begin(RangeOrContainer: MI->operands())) { |
1842 | MCOperand MCOp; |
1843 | if (LowerPPCMachineOperandToMCOperand(MO, OutMO&: MCOp, AP&: *this)) |
1844 | RetInst.addOperand(Op: MCOp); |
1845 | } |
1846 | |
1847 | bool IsConditional; |
1848 | if (RetOpcode == PPC::BCCLR) { |
1849 | IsConditional = true; |
1850 | } else if (RetOpcode == PPC::TCRETURNdi8 || RetOpcode == PPC::TCRETURNri8 || |
1851 | RetOpcode == PPC::TCRETURNai8) { |
1852 | break; |
1853 | } else if (RetOpcode == PPC::BLR8 || RetOpcode == PPC::TAILB8) { |
1854 | IsConditional = false; |
1855 | } else { |
1856 | EmitToStreamer(S&: *OutStreamer, Inst: RetInst); |
1857 | return; |
1858 | } |
1859 | |
1860 | MCSymbol *FallthroughLabel; |
1861 | if (IsConditional) { |
1862 | // Before: |
1863 | // bgtlr cr0 |
1864 | // |
1865 | // After: |
1866 | // ble cr0, .end |
1867 | // .p2align 3 |
1868 | // .begin: |
1869 | // blr # lis 0, FuncId[16..32] |
1870 | // nop # li 0, FuncId[0..15] |
1871 | // std 0, -8(1) |
1872 | // mflr 0 |
1873 | // bl __xray_FunctionExit |
1874 | // mtlr 0 |
1875 | // blr |
1876 | // .end: |
1877 | // |
1878 | // Update compiler-rt/lib/xray/xray_powerpc64.cc accordingly when number |
1879 | // of instructions change. |
1880 | FallthroughLabel = OutContext.createTempSymbol(); |
1881 | EmitToStreamer( |
1882 | S&: *OutStreamer, |
1883 | Inst: MCInstBuilder(PPC::BCC) |
1884 | .addImm(Val: PPC::InvertPredicate( |
1885 | Opcode: static_cast<PPC::Predicate>(MI->getOperand(i: 1).getImm()))) |
1886 | .addReg(Reg: MI->getOperand(i: 2).getReg()) |
1887 | .addExpr(Val: MCSymbolRefExpr::create(Symbol: FallthroughLabel, Ctx&: OutContext))); |
1888 | RetInst = MCInst(); |
1889 | RetInst.setOpcode(PPC::BLR8); |
1890 | } |
1891 | // .p2align 3 |
1892 | // .begin: |
1893 | // b(lr)? # lis 0, FuncId[16..32] |
1894 | // nop # li 0, FuncId[0..15] |
1895 | // std 0, -8(1) |
1896 | // mflr 0 |
1897 | // bl __xray_FunctionExit |
1898 | // mtlr 0 |
1899 | // b(lr)? |
1900 | // |
1901 | // Update compiler-rt/lib/xray/xray_powerpc64.cc accordingly when number |
1902 | // of instructions change. |
1903 | OutStreamer->emitCodeAlignment(Alignment: Align(8), STI: &getSubtargetInfo()); |
1904 | MCSymbol *BeginOfSled = OutContext.createTempSymbol(); |
1905 | OutStreamer->emitLabel(Symbol: BeginOfSled); |
1906 | EmitToStreamer(S&: *OutStreamer, Inst: RetInst); |
1907 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::NOP)); |
1908 | EmitToStreamer( |
1909 | S&: *OutStreamer, |
1910 | Inst: MCInstBuilder(PPC::STD).addReg(Reg: PPC::X0).addImm(Val: -8).addReg(Reg: PPC::X1)); |
1911 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::MFLR8).addReg(Reg: PPC::X0)); |
1912 | EmitToStreamer(S&: *OutStreamer, |
1913 | Inst: MCInstBuilder(PPC::BL8_NOP) |
1914 | .addExpr(Val: MCSymbolRefExpr::create( |
1915 | Symbol: OutContext.getOrCreateSymbol(Name: "__xray_FunctionExit" ), |
1916 | Ctx&: OutContext))); |
1917 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::MTLR8).addReg(Reg: PPC::X0)); |
1918 | EmitToStreamer(S&: *OutStreamer, Inst: RetInst); |
1919 | if (IsConditional) |
1920 | OutStreamer->emitLabel(Symbol: FallthroughLabel); |
1921 | recordSled(Sled: BeginOfSled, MI: *MI, Kind: SledKind::FUNCTION_EXIT, Version: 2); |
1922 | return; |
1923 | } |
1924 | case TargetOpcode::PATCHABLE_FUNCTION_EXIT: |
1925 | llvm_unreachable("PATCHABLE_FUNCTION_EXIT should never be emitted" ); |
1926 | case TargetOpcode::PATCHABLE_TAIL_CALL: |
1927 | // TODO: Define a trampoline `__xray_FunctionTailExit` and differentiate a |
1928 | // normal function exit from a tail exit. |
1929 | llvm_unreachable("Tail call is handled in the normal case. See comments " |
1930 | "around this assert." ); |
1931 | } |
1932 | return PPCAsmPrinter::emitInstruction(MI); |
1933 | } |
1934 | |
1935 | void PPCLinuxAsmPrinter::emitStartOfAsmFile(Module &M) { |
1936 | if (static_cast<const PPCTargetMachine &>(TM).isELFv2ABI()) { |
1937 | PPCTargetStreamer *TS = |
1938 | static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer()); |
1939 | TS->emitAbiVersion(AbiVersion: 2); |
1940 | } |
1941 | |
1942 | if (static_cast<const PPCTargetMachine &>(TM).isPPC64() || |
1943 | !isPositionIndependent()) |
1944 | return AsmPrinter::emitStartOfAsmFile(M); |
1945 | |
1946 | if (M.getPICLevel() == PICLevel::SmallPIC) |
1947 | return AsmPrinter::emitStartOfAsmFile(M); |
1948 | |
1949 | OutStreamer->switchSection(Section: OutContext.getELFSection( |
1950 | Section: ".got2" , Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_WRITE | ELF::SHF_ALLOC)); |
1951 | |
1952 | MCSymbol *TOCSym = OutContext.getOrCreateSymbol(Name: Twine(".LTOC" )); |
1953 | MCSymbol *CurrentPos = OutContext.createTempSymbol(); |
1954 | |
1955 | OutStreamer->emitLabel(Symbol: CurrentPos); |
1956 | |
1957 | // The GOT pointer points to the middle of the GOT, in order to reference the |
1958 | // entire 64kB range. 0x8000 is the midpoint. |
1959 | const MCExpr *tocExpr = |
1960 | MCBinaryExpr::createAdd(LHS: MCSymbolRefExpr::create(Symbol: CurrentPos, Ctx&: OutContext), |
1961 | RHS: MCConstantExpr::create(Value: 0x8000, Ctx&: OutContext), |
1962 | Ctx&: OutContext); |
1963 | |
1964 | OutStreamer->emitAssignment(Symbol: TOCSym, Value: tocExpr); |
1965 | |
1966 | OutStreamer->switchSection(Section: getObjFileLowering().getTextSection()); |
1967 | } |
1968 | |
1969 | void PPCLinuxAsmPrinter::emitFunctionEntryLabel() { |
1970 | // linux/ppc32 - Normal entry label. |
1971 | if (!Subtarget->isPPC64() && |
1972 | (!isPositionIndependent() || |
1973 | MF->getFunction().getParent()->getPICLevel() == PICLevel::SmallPIC)) |
1974 | return AsmPrinter::emitFunctionEntryLabel(); |
1975 | |
1976 | if (!Subtarget->isPPC64()) { |
1977 | const PPCFunctionInfo *PPCFI = MF->getInfo<PPCFunctionInfo>(); |
1978 | if (PPCFI->usesPICBase() && !Subtarget->isSecurePlt()) { |
1979 | MCSymbol *RelocSymbol = PPCFI->getPICOffsetSymbol(MF&: *MF); |
1980 | MCSymbol *PICBase = MF->getPICBaseSymbol(); |
1981 | OutStreamer->emitLabel(Symbol: RelocSymbol); |
1982 | |
1983 | const MCExpr *OffsExpr = |
1984 | MCBinaryExpr::createSub( |
1985 | LHS: MCSymbolRefExpr::create(Symbol: OutContext.getOrCreateSymbol(Name: Twine(".LTOC" )), |
1986 | Ctx&: OutContext), |
1987 | RHS: MCSymbolRefExpr::create(Symbol: PICBase, Ctx&: OutContext), |
1988 | Ctx&: OutContext); |
1989 | OutStreamer->emitValue(Value: OffsExpr, Size: 4); |
1990 | OutStreamer->emitLabel(Symbol: CurrentFnSym); |
1991 | return; |
1992 | } else |
1993 | return AsmPrinter::emitFunctionEntryLabel(); |
1994 | } |
1995 | |
1996 | // ELFv2 ABI - Normal entry label. |
1997 | if (Subtarget->isELFv2ABI()) { |
1998 | // In the Large code model, we allow arbitrary displacements between |
1999 | // the text section and its associated TOC section. We place the |
2000 | // full 8-byte offset to the TOC in memory immediately preceding |
2001 | // the function global entry point. |
2002 | if (TM.getCodeModel() == CodeModel::Large |
2003 | && !MF->getRegInfo().use_empty(RegNo: PPC::X2)) { |
2004 | const PPCFunctionInfo *PPCFI = MF->getInfo<PPCFunctionInfo>(); |
2005 | |
2006 | MCSymbol *TOCSymbol = OutContext.getOrCreateSymbol(Name: StringRef(".TOC." )); |
2007 | MCSymbol *GlobalEPSymbol = PPCFI->getGlobalEPSymbol(MF&: *MF); |
2008 | const MCExpr *TOCDeltaExpr = |
2009 | MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: TOCSymbol, Ctx&: OutContext), |
2010 | RHS: MCSymbolRefExpr::create(Symbol: GlobalEPSymbol, |
2011 | Ctx&: OutContext), |
2012 | Ctx&: OutContext); |
2013 | |
2014 | OutStreamer->emitLabel(Symbol: PPCFI->getTOCOffsetSymbol(MF&: *MF)); |
2015 | OutStreamer->emitValue(Value: TOCDeltaExpr, Size: 8); |
2016 | } |
2017 | return AsmPrinter::emitFunctionEntryLabel(); |
2018 | } |
2019 | |
2020 | // Emit an official procedure descriptor. |
2021 | MCSectionSubPair Current = OutStreamer->getCurrentSection(); |
2022 | MCSectionELF *Section = OutStreamer->getContext().getELFSection( |
2023 | Section: ".opd" , Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_WRITE | ELF::SHF_ALLOC); |
2024 | OutStreamer->switchSection(Section); |
2025 | OutStreamer->emitLabel(Symbol: CurrentFnSym); |
2026 | OutStreamer->emitValueToAlignment(Alignment: Align(8)); |
2027 | MCSymbol *Symbol1 = CurrentFnSymForSize; |
2028 | // Generates a R_PPC64_ADDR64 (from FK_DATA_8) relocation for the function |
2029 | // entry point. |
2030 | OutStreamer->emitValue(Value: MCSymbolRefExpr::create(Symbol: Symbol1, Ctx&: OutContext), |
2031 | Size: 8 /*size*/); |
2032 | MCSymbol *Symbol2 = OutContext.getOrCreateSymbol(Name: StringRef(".TOC." )); |
2033 | // Generates a R_PPC64_TOC relocation for TOC base insertion. |
2034 | OutStreamer->emitValue( |
2035 | Value: MCSymbolRefExpr::create(Symbol: Symbol2, Kind: MCSymbolRefExpr::VK_PPC_TOCBASE, Ctx&: OutContext), |
2036 | Size: 8/*size*/); |
2037 | // Emit a null environment pointer. |
2038 | OutStreamer->emitIntValue(Value: 0, Size: 8 /* size */); |
2039 | OutStreamer->switchSection(Section: Current.first, Subsec: Current.second); |
2040 | } |
2041 | |
2042 | void PPCLinuxAsmPrinter::emitEndOfAsmFile(Module &M) { |
2043 | const DataLayout &DL = getDataLayout(); |
2044 | |
2045 | bool isPPC64 = DL.getPointerSizeInBits() == 64; |
2046 | |
2047 | PPCTargetStreamer *TS = |
2048 | static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer()); |
2049 | |
2050 | // If we are using any values provided by Glibc at fixed addresses, |
2051 | // we need to ensure that the Glibc used at link time actually provides |
2052 | // those values. All versions of Glibc that do will define the symbol |
2053 | // named "__parse_hwcap_and_convert_at_platform". |
2054 | if (static_cast<const PPCTargetMachine &>(TM).hasGlibcHWCAPAccess()) |
2055 | OutStreamer->emitSymbolValue( |
2056 | Sym: GetExternalSymbolSymbol(Sym: "__parse_hwcap_and_convert_at_platform" ), |
2057 | Size: MAI->getCodePointerSize()); |
2058 | emitGNUAttributes(M); |
2059 | |
2060 | if (!TOC.empty()) { |
2061 | const char *Name = isPPC64 ? ".toc" : ".got2" ; |
2062 | MCSectionELF *Section = OutContext.getELFSection( |
2063 | Section: Name, Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_WRITE | ELF::SHF_ALLOC); |
2064 | OutStreamer->switchSection(Section); |
2065 | if (!isPPC64) |
2066 | OutStreamer->emitValueToAlignment(Alignment: Align(4)); |
2067 | |
2068 | for (const auto &TOCMapPair : TOC) { |
2069 | const MCSymbol *const TOCEntryTarget = TOCMapPair.first.first; |
2070 | MCSymbol *const TOCEntryLabel = TOCMapPair.second; |
2071 | |
2072 | OutStreamer->emitLabel(Symbol: TOCEntryLabel); |
2073 | if (isPPC64) |
2074 | TS->emitTCEntry(S: *TOCEntryTarget, Kind: TOCMapPair.first.second); |
2075 | else |
2076 | OutStreamer->emitSymbolValue(Sym: TOCEntryTarget, Size: 4); |
2077 | } |
2078 | } |
2079 | |
2080 | PPCAsmPrinter::emitEndOfAsmFile(M); |
2081 | } |
2082 | |
2083 | /// EmitFunctionBodyStart - Emit a global entry point prefix for ELFv2. |
2084 | void PPCLinuxAsmPrinter::emitFunctionBodyStart() { |
2085 | // In the ELFv2 ABI, in functions that use the TOC register, we need to |
2086 | // provide two entry points. The ABI guarantees that when calling the |
2087 | // local entry point, r2 is set up by the caller to contain the TOC base |
2088 | // for this function, and when calling the global entry point, r12 is set |
2089 | // up by the caller to hold the address of the global entry point. We |
2090 | // thus emit a prefix sequence along the following lines: |
2091 | // |
2092 | // func: |
2093 | // .Lfunc_gepNN: |
2094 | // # global entry point |
2095 | // addis r2,r12,(.TOC.-.Lfunc_gepNN)@ha |
2096 | // addi r2,r2,(.TOC.-.Lfunc_gepNN)@l |
2097 | // .Lfunc_lepNN: |
2098 | // .localentry func, .Lfunc_lepNN-.Lfunc_gepNN |
2099 | // # local entry point, followed by function body |
2100 | // |
2101 | // For the Large code model, we create |
2102 | // |
2103 | // .Lfunc_tocNN: |
2104 | // .quad .TOC.-.Lfunc_gepNN # done by EmitFunctionEntryLabel |
2105 | // func: |
2106 | // .Lfunc_gepNN: |
2107 | // # global entry point |
2108 | // ld r2,.Lfunc_tocNN-.Lfunc_gepNN(r12) |
2109 | // add r2,r2,r12 |
2110 | // .Lfunc_lepNN: |
2111 | // .localentry func, .Lfunc_lepNN-.Lfunc_gepNN |
2112 | // # local entry point, followed by function body |
2113 | // |
2114 | // This ensures we have r2 set up correctly while executing the function |
2115 | // body, no matter which entry point is called. |
2116 | const PPCFunctionInfo *PPCFI = MF->getInfo<PPCFunctionInfo>(); |
2117 | const bool UsesX2OrR2 = !MF->getRegInfo().use_empty(RegNo: PPC::X2) || |
2118 | !MF->getRegInfo().use_empty(RegNo: PPC::R2); |
2119 | const bool PCrelGEPRequired = Subtarget->isUsingPCRelativeCalls() && |
2120 | UsesX2OrR2 && PPCFI->usesTOCBasePtr(); |
2121 | const bool NonPCrelGEPRequired = !Subtarget->isUsingPCRelativeCalls() && |
2122 | Subtarget->isELFv2ABI() && UsesX2OrR2; |
2123 | |
2124 | // Only do all that if the function uses R2 as the TOC pointer |
2125 | // in the first place. We don't need the global entry point if the |
2126 | // function uses R2 as an allocatable register. |
2127 | if (NonPCrelGEPRequired || PCrelGEPRequired) { |
2128 | // Note: The logic here must be synchronized with the code in the |
2129 | // branch-selection pass which sets the offset of the first block in the |
2130 | // function. This matters because it affects the alignment. |
2131 | MCSymbol *GlobalEntryLabel = PPCFI->getGlobalEPSymbol(MF&: *MF); |
2132 | OutStreamer->emitLabel(Symbol: GlobalEntryLabel); |
2133 | const MCSymbolRefExpr *GlobalEntryLabelExp = |
2134 | MCSymbolRefExpr::create(Symbol: GlobalEntryLabel, Ctx&: OutContext); |
2135 | |
2136 | if (TM.getCodeModel() != CodeModel::Large) { |
2137 | MCSymbol *TOCSymbol = OutContext.getOrCreateSymbol(Name: StringRef(".TOC." )); |
2138 | const MCExpr *TOCDeltaExpr = |
2139 | MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: TOCSymbol, Ctx&: OutContext), |
2140 | RHS: GlobalEntryLabelExp, Ctx&: OutContext); |
2141 | |
2142 | const MCExpr *TOCDeltaHi = PPCMCExpr::createHa(Expr: TOCDeltaExpr, Ctx&: OutContext); |
2143 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::ADDIS) |
2144 | .addReg(Reg: PPC::X2) |
2145 | .addReg(Reg: PPC::X12) |
2146 | .addExpr(Val: TOCDeltaHi)); |
2147 | |
2148 | const MCExpr *TOCDeltaLo = PPCMCExpr::createLo(Expr: TOCDeltaExpr, Ctx&: OutContext); |
2149 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::ADDI) |
2150 | .addReg(Reg: PPC::X2) |
2151 | .addReg(Reg: PPC::X2) |
2152 | .addExpr(Val: TOCDeltaLo)); |
2153 | } else { |
2154 | MCSymbol *TOCOffset = PPCFI->getTOCOffsetSymbol(MF&: *MF); |
2155 | const MCExpr *TOCOffsetDeltaExpr = |
2156 | MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: TOCOffset, Ctx&: OutContext), |
2157 | RHS: GlobalEntryLabelExp, Ctx&: OutContext); |
2158 | |
2159 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::LD) |
2160 | .addReg(Reg: PPC::X2) |
2161 | .addExpr(Val: TOCOffsetDeltaExpr) |
2162 | .addReg(Reg: PPC::X12)); |
2163 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(PPC::ADD8) |
2164 | .addReg(Reg: PPC::X2) |
2165 | .addReg(Reg: PPC::X2) |
2166 | .addReg(Reg: PPC::X12)); |
2167 | } |
2168 | |
2169 | MCSymbol *LocalEntryLabel = PPCFI->getLocalEPSymbol(MF&: *MF); |
2170 | OutStreamer->emitLabel(Symbol: LocalEntryLabel); |
2171 | const MCSymbolRefExpr *LocalEntryLabelExp = |
2172 | MCSymbolRefExpr::create(Symbol: LocalEntryLabel, Ctx&: OutContext); |
2173 | const MCExpr *LocalOffsetExp = |
2174 | MCBinaryExpr::createSub(LHS: LocalEntryLabelExp, |
2175 | RHS: GlobalEntryLabelExp, Ctx&: OutContext); |
2176 | |
2177 | PPCTargetStreamer *TS = |
2178 | static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer()); |
2179 | TS->emitLocalEntry(S: cast<MCSymbolELF>(Val: CurrentFnSym), LocalOffset: LocalOffsetExp); |
2180 | } else if (Subtarget->isUsingPCRelativeCalls()) { |
2181 | // When generating the entry point for a function we have a few scenarios |
2182 | // based on whether or not that function uses R2 and whether or not that |
2183 | // function makes calls (or is a leaf function). |
2184 | // 1) A leaf function that does not use R2 (or treats it as callee-saved |
2185 | // and preserves it). In this case st_other=0 and both |
2186 | // the local and global entry points for the function are the same. |
2187 | // No special entry point code is required. |
2188 | // 2) A function uses the TOC pointer R2. This function may or may not have |
2189 | // calls. In this case st_other=[2,6] and the global and local entry |
2190 | // points are different. Code to correctly setup the TOC pointer in R2 |
2191 | // is put between the global and local entry points. This case is |
2192 | // covered by the if statatement above. |
2193 | // 3) A function does not use the TOC pointer R2 but does have calls. |
2194 | // In this case st_other=1 since we do not know whether or not any |
2195 | // of the callees clobber R2. This case is dealt with in this else if |
2196 | // block. Tail calls are considered calls and the st_other should also |
2197 | // be set to 1 in that case as well. |
2198 | // 4) The function does not use the TOC pointer but R2 is used inside |
2199 | // the function. In this case st_other=1 once again. |
2200 | // 5) This function uses inline asm. We mark R2 as reserved if the function |
2201 | // has inline asm as we have to assume that it may be used. |
2202 | if (MF->getFrameInfo().hasCalls() || MF->getFrameInfo().hasTailCall() || |
2203 | MF->hasInlineAsm() || (!PPCFI->usesTOCBasePtr() && UsesX2OrR2)) { |
2204 | PPCTargetStreamer *TS = |
2205 | static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer()); |
2206 | TS->emitLocalEntry(S: cast<MCSymbolELF>(Val: CurrentFnSym), |
2207 | LocalOffset: MCConstantExpr::create(Value: 1, Ctx&: OutContext)); |
2208 | } |
2209 | } |
2210 | } |
2211 | |
2212 | /// EmitFunctionBodyEnd - Print the traceback table before the .size |
2213 | /// directive. |
2214 | /// |
2215 | void PPCLinuxAsmPrinter::emitFunctionBodyEnd() { |
2216 | // Only the 64-bit target requires a traceback table. For now, |
2217 | // we only emit the word of zeroes that GDB requires to find |
2218 | // the end of the function, and zeroes for the eight-byte |
2219 | // mandatory fields. |
2220 | // FIXME: We should fill in the eight-byte mandatory fields as described in |
2221 | // the PPC64 ELF ABI (this is a low-priority item because GDB does not |
2222 | // currently make use of these fields). |
2223 | if (Subtarget->isPPC64()) { |
2224 | OutStreamer->emitIntValue(Value: 0, Size: 4/*size*/); |
2225 | OutStreamer->emitIntValue(Value: 0, Size: 8/*size*/); |
2226 | } |
2227 | } |
2228 | |
2229 | void PPCAIXAsmPrinter::emitLinkage(const GlobalValue *GV, |
2230 | MCSymbol *GVSym) const { |
2231 | |
2232 | assert(MAI->hasVisibilityOnlyWithLinkage() && |
2233 | "AIX's linkage directives take a visibility setting." ); |
2234 | |
2235 | MCSymbolAttr LinkageAttr = MCSA_Invalid; |
2236 | switch (GV->getLinkage()) { |
2237 | case GlobalValue::ExternalLinkage: |
2238 | LinkageAttr = GV->isDeclaration() ? MCSA_Extern : MCSA_Global; |
2239 | break; |
2240 | case GlobalValue::LinkOnceAnyLinkage: |
2241 | case GlobalValue::LinkOnceODRLinkage: |
2242 | case GlobalValue::WeakAnyLinkage: |
2243 | case GlobalValue::WeakODRLinkage: |
2244 | case GlobalValue::ExternalWeakLinkage: |
2245 | LinkageAttr = MCSA_Weak; |
2246 | break; |
2247 | case GlobalValue::AvailableExternallyLinkage: |
2248 | LinkageAttr = MCSA_Extern; |
2249 | break; |
2250 | case GlobalValue::PrivateLinkage: |
2251 | return; |
2252 | case GlobalValue::InternalLinkage: |
2253 | assert(GV->getVisibility() == GlobalValue::DefaultVisibility && |
2254 | "InternalLinkage should not have other visibility setting." ); |
2255 | LinkageAttr = MCSA_LGlobal; |
2256 | break; |
2257 | case GlobalValue::AppendingLinkage: |
2258 | llvm_unreachable("Should never emit this" ); |
2259 | case GlobalValue::CommonLinkage: |
2260 | llvm_unreachable("CommonLinkage of XCOFF should not come to this path" ); |
2261 | } |
2262 | |
2263 | assert(LinkageAttr != MCSA_Invalid && "LinkageAttr should not MCSA_Invalid." ); |
2264 | |
2265 | MCSymbolAttr VisibilityAttr = MCSA_Invalid; |
2266 | if (!TM.getIgnoreXCOFFVisibility()) { |
2267 | if (GV->hasDLLExportStorageClass() && !GV->hasDefaultVisibility()) |
2268 | report_fatal_error( |
2269 | reason: "Cannot not be both dllexport and non-default visibility" ); |
2270 | switch (GV->getVisibility()) { |
2271 | |
2272 | // TODO: "internal" Visibility needs to go here. |
2273 | case GlobalValue::DefaultVisibility: |
2274 | if (GV->hasDLLExportStorageClass()) |
2275 | VisibilityAttr = MAI->getExportedVisibilityAttr(); |
2276 | break; |
2277 | case GlobalValue::HiddenVisibility: |
2278 | VisibilityAttr = MAI->getHiddenVisibilityAttr(); |
2279 | break; |
2280 | case GlobalValue::ProtectedVisibility: |
2281 | VisibilityAttr = MAI->getProtectedVisibilityAttr(); |
2282 | break; |
2283 | } |
2284 | } |
2285 | |
2286 | // Do not emit the _$TLSML symbol. |
2287 | if (GV->getThreadLocalMode() == GlobalVariable::LocalDynamicTLSModel && |
2288 | GV->hasName() && GV->getName() == "_$TLSML" ) |
2289 | return; |
2290 | |
2291 | OutStreamer->emitXCOFFSymbolLinkageWithVisibility(Symbol: GVSym, Linkage: LinkageAttr, |
2292 | Visibility: VisibilityAttr); |
2293 | } |
2294 | |
2295 | void PPCAIXAsmPrinter::SetupMachineFunction(MachineFunction &MF) { |
2296 | // Setup CurrentFnDescSym and its containing csect. |
2297 | MCSectionXCOFF *FnDescSec = |
2298 | cast<MCSectionXCOFF>(Val: getObjFileLowering().getSectionForFunctionDescriptor( |
2299 | F: &MF.getFunction(), TM)); |
2300 | FnDescSec->setAlignment(Align(Subtarget->isPPC64() ? 8 : 4)); |
2301 | |
2302 | CurrentFnDescSym = FnDescSec->getQualNameSymbol(); |
2303 | |
2304 | return AsmPrinter::SetupMachineFunction(MF); |
2305 | } |
2306 | |
2307 | uint16_t PPCAIXAsmPrinter::getNumberOfVRSaved() { |
2308 | // Calculate the number of VRs be saved. |
2309 | // Vector registers 20 through 31 are marked as reserved and cannot be used |
2310 | // in the default ABI. |
2311 | const PPCSubtarget &Subtarget = MF->getSubtarget<PPCSubtarget>(); |
2312 | if (Subtarget.isAIXABI() && Subtarget.hasAltivec() && |
2313 | TM.getAIXExtendedAltivecABI()) { |
2314 | const MachineRegisterInfo &MRI = MF->getRegInfo(); |
2315 | for (unsigned Reg = PPC::V20; Reg <= PPC::V31; ++Reg) |
2316 | if (MRI.isPhysRegModified(PhysReg: Reg)) |
2317 | // Number of VRs saved. |
2318 | return PPC::V31 - Reg + 1; |
2319 | } |
2320 | return 0; |
2321 | } |
2322 | |
2323 | void PPCAIXAsmPrinter::emitFunctionBodyEnd() { |
2324 | |
2325 | if (!TM.getXCOFFTracebackTable()) |
2326 | return; |
2327 | |
2328 | emitTracebackTable(); |
2329 | |
2330 | // If ShouldEmitEHBlock returns true, then the eh info table |
2331 | // will be emitted via `AIXException::endFunction`. Otherwise, we |
2332 | // need to emit a dumy eh info table when VRs are saved. We could not |
2333 | // consolidate these two places into one because there is no easy way |
2334 | // to access register information in `AIXException` class. |
2335 | if (!TargetLoweringObjectFileXCOFF::ShouldEmitEHBlock(MF) && |
2336 | (getNumberOfVRSaved() > 0)) { |
2337 | // Emit dummy EH Info Table. |
2338 | OutStreamer->switchSection(Section: getObjFileLowering().getCompactUnwindSection()); |
2339 | MCSymbol *EHInfoLabel = |
2340 | TargetLoweringObjectFileXCOFF::getEHInfoTableSymbol(MF); |
2341 | OutStreamer->emitLabel(Symbol: EHInfoLabel); |
2342 | |
2343 | // Version number. |
2344 | OutStreamer->emitInt32(Value: 0); |
2345 | |
2346 | const DataLayout &DL = MMI->getModule()->getDataLayout(); |
2347 | const unsigned PointerSize = DL.getPointerSize(); |
2348 | // Add necessary paddings in 64 bit mode. |
2349 | OutStreamer->emitValueToAlignment(Alignment: Align(PointerSize)); |
2350 | |
2351 | OutStreamer->emitIntValue(Value: 0, Size: PointerSize); |
2352 | OutStreamer->emitIntValue(Value: 0, Size: PointerSize); |
2353 | OutStreamer->switchSection(Section: MF->getSection()); |
2354 | } |
2355 | } |
2356 | |
2357 | void PPCAIXAsmPrinter::emitTracebackTable() { |
2358 | |
2359 | // Create a symbol for the end of function. |
2360 | MCSymbol *FuncEnd = createTempSymbol(Name: MF->getName()); |
2361 | OutStreamer->emitLabel(Symbol: FuncEnd); |
2362 | |
2363 | OutStreamer->AddComment(T: "Traceback table begin" ); |
2364 | // Begin with a fullword of zero. |
2365 | OutStreamer->emitIntValueInHexWithPadding(Value: 0, Size: 4 /*size*/); |
2366 | |
2367 | SmallString<128> ; |
2368 | raw_svector_ostream (CommentString); |
2369 | |
2370 | auto = [&]() { |
2371 | OutStreamer->AddComment(T: CommentOS.str()); |
2372 | CommentString.clear(); |
2373 | }; |
2374 | |
2375 | auto EmitCommentAndValue = [&](uint64_t Value, int Size) { |
2376 | EmitComment(); |
2377 | OutStreamer->emitIntValueInHexWithPadding(Value, Size); |
2378 | }; |
2379 | |
2380 | unsigned int Version = 0; |
2381 | CommentOS << "Version = " << Version; |
2382 | EmitCommentAndValue(Version, 1); |
2383 | |
2384 | // There is a lack of information in the IR to assist with determining the |
2385 | // source language. AIX exception handling mechanism would only search for |
2386 | // personality routine and LSDA area when such language supports exception |
2387 | // handling. So to be conservatively correct and allow runtime to do its job, |
2388 | // we need to set it to C++ for now. |
2389 | TracebackTable::LanguageID LanguageIdentifier = |
2390 | TracebackTable::CPlusPlus; // C++ |
2391 | |
2392 | CommentOS << "Language = " |
2393 | << getNameForTracebackTableLanguageId(LangId: LanguageIdentifier); |
2394 | EmitCommentAndValue(LanguageIdentifier, 1); |
2395 | |
2396 | // This is only populated for the third and fourth bytes. |
2397 | uint32_t FirstHalfOfMandatoryField = 0; |
2398 | |
2399 | // Emit the 3rd byte of the mandatory field. |
2400 | |
2401 | // We always set traceback offset bit to true. |
2402 | FirstHalfOfMandatoryField |= TracebackTable::HasTraceBackTableOffsetMask; |
2403 | |
2404 | const PPCFunctionInfo *FI = MF->getInfo<PPCFunctionInfo>(); |
2405 | const MachineRegisterInfo &MRI = MF->getRegInfo(); |
2406 | |
2407 | // Check the function uses floating-point processor instructions or not |
2408 | for (unsigned Reg = PPC::F0; Reg <= PPC::F31; ++Reg) { |
2409 | if (MRI.isPhysRegUsed(PhysReg: Reg, /* SkipRegMaskTest */ true)) { |
2410 | FirstHalfOfMandatoryField |= TracebackTable::IsFloatingPointPresentMask; |
2411 | break; |
2412 | } |
2413 | } |
2414 | |
2415 | #define (Prefix, V, Field) \ |
2416 | CommentOS << (Prefix) << ((V) & (TracebackTable::Field##Mask) ? "+" : "-") \ |
2417 | << #Field |
2418 | |
2419 | #define (PrefixAndName, V, Field) \ |
2420 | CommentOS << (PrefixAndName) << " = " \ |
2421 | << static_cast<unsigned>(((V) & (TracebackTable::Field##Mask)) >> \ |
2422 | (TracebackTable::Field##Shift)) |
2423 | |
2424 | GENBOOLCOMMENT("" , FirstHalfOfMandatoryField, IsGlobaLinkage); |
2425 | GENBOOLCOMMENT(", " , FirstHalfOfMandatoryField, IsOutOfLineEpilogOrPrologue); |
2426 | EmitComment(); |
2427 | |
2428 | GENBOOLCOMMENT("" , FirstHalfOfMandatoryField, HasTraceBackTableOffset); |
2429 | GENBOOLCOMMENT(", " , FirstHalfOfMandatoryField, IsInternalProcedure); |
2430 | EmitComment(); |
2431 | |
2432 | GENBOOLCOMMENT("" , FirstHalfOfMandatoryField, HasControlledStorage); |
2433 | GENBOOLCOMMENT(", " , FirstHalfOfMandatoryField, IsTOCless); |
2434 | EmitComment(); |
2435 | |
2436 | GENBOOLCOMMENT("" , FirstHalfOfMandatoryField, IsFloatingPointPresent); |
2437 | EmitComment(); |
2438 | GENBOOLCOMMENT("" , FirstHalfOfMandatoryField, |
2439 | IsFloatingPointOperationLogOrAbortEnabled); |
2440 | EmitComment(); |
2441 | |
2442 | OutStreamer->emitIntValueInHexWithPadding( |
2443 | Value: (FirstHalfOfMandatoryField & 0x0000ff00) >> 8, Size: 1); |
2444 | |
2445 | // Set the 4th byte of the mandatory field. |
2446 | FirstHalfOfMandatoryField |= TracebackTable::IsFunctionNamePresentMask; |
2447 | |
2448 | const PPCRegisterInfo *RegInfo = |
2449 | static_cast<const PPCRegisterInfo *>(Subtarget->getRegisterInfo()); |
2450 | Register FrameReg = RegInfo->getFrameRegister(MF: *MF); |
2451 | if (FrameReg == (Subtarget->isPPC64() ? PPC::X31 : PPC::R31)) |
2452 | FirstHalfOfMandatoryField |= TracebackTable::IsAllocaUsedMask; |
2453 | |
2454 | const SmallVectorImpl<Register> &MustSaveCRs = FI->getMustSaveCRs(); |
2455 | if (!MustSaveCRs.empty()) |
2456 | FirstHalfOfMandatoryField |= TracebackTable::IsCRSavedMask; |
2457 | |
2458 | if (FI->mustSaveLR()) |
2459 | FirstHalfOfMandatoryField |= TracebackTable::IsLRSavedMask; |
2460 | |
2461 | GENBOOLCOMMENT("" , FirstHalfOfMandatoryField, IsInterruptHandler); |
2462 | GENBOOLCOMMENT(", " , FirstHalfOfMandatoryField, IsFunctionNamePresent); |
2463 | GENBOOLCOMMENT(", " , FirstHalfOfMandatoryField, IsAllocaUsed); |
2464 | EmitComment(); |
2465 | GENVALUECOMMENT("OnConditionDirective" , FirstHalfOfMandatoryField, |
2466 | OnConditionDirective); |
2467 | GENBOOLCOMMENT(", " , FirstHalfOfMandatoryField, IsCRSaved); |
2468 | GENBOOLCOMMENT(", " , FirstHalfOfMandatoryField, IsLRSaved); |
2469 | EmitComment(); |
2470 | OutStreamer->emitIntValueInHexWithPadding(Value: (FirstHalfOfMandatoryField & 0xff), |
2471 | Size: 1); |
2472 | |
2473 | // Set the 5th byte of mandatory field. |
2474 | uint32_t SecondHalfOfMandatoryField = 0; |
2475 | |
2476 | SecondHalfOfMandatoryField |= MF->getFrameInfo().getStackSize() |
2477 | ? TracebackTable::IsBackChainStoredMask |
2478 | : 0; |
2479 | |
2480 | uint32_t FPRSaved = 0; |
2481 | for (unsigned Reg = PPC::F14; Reg <= PPC::F31; ++Reg) { |
2482 | if (MRI.isPhysRegModified(PhysReg: Reg)) { |
2483 | FPRSaved = PPC::F31 - Reg + 1; |
2484 | break; |
2485 | } |
2486 | } |
2487 | SecondHalfOfMandatoryField |= (FPRSaved << TracebackTable::FPRSavedShift) & |
2488 | TracebackTable::FPRSavedMask; |
2489 | GENBOOLCOMMENT("" , SecondHalfOfMandatoryField, IsBackChainStored); |
2490 | GENBOOLCOMMENT(", " , SecondHalfOfMandatoryField, IsFixup); |
2491 | GENVALUECOMMENT(", NumOfFPRsSaved" , SecondHalfOfMandatoryField, FPRSaved); |
2492 | EmitComment(); |
2493 | OutStreamer->emitIntValueInHexWithPadding( |
2494 | Value: (SecondHalfOfMandatoryField & 0xff000000) >> 24, Size: 1); |
2495 | |
2496 | // Set the 6th byte of mandatory field. |
2497 | |
2498 | // Check whether has Vector Instruction,We only treat instructions uses vector |
2499 | // register as vector instructions. |
2500 | bool HasVectorInst = false; |
2501 | for (unsigned Reg = PPC::V0; Reg <= PPC::V31; ++Reg) |
2502 | if (MRI.isPhysRegUsed(PhysReg: Reg, /* SkipRegMaskTest */ true)) { |
2503 | // Has VMX instruction. |
2504 | HasVectorInst = true; |
2505 | break; |
2506 | } |
2507 | |
2508 | if (FI->hasVectorParms() || HasVectorInst) |
2509 | SecondHalfOfMandatoryField |= TracebackTable::HasVectorInfoMask; |
2510 | |
2511 | uint16_t NumOfVRSaved = getNumberOfVRSaved(); |
2512 | bool ShouldEmitEHBlock = |
2513 | TargetLoweringObjectFileXCOFF::ShouldEmitEHBlock(MF) || NumOfVRSaved > 0; |
2514 | |
2515 | if (ShouldEmitEHBlock) |
2516 | SecondHalfOfMandatoryField |= TracebackTable::HasExtensionTableMask; |
2517 | |
2518 | uint32_t GPRSaved = 0; |
2519 | |
2520 | // X13 is reserved under 64-bit environment. |
2521 | unsigned GPRBegin = Subtarget->isPPC64() ? PPC::X14 : PPC::R13; |
2522 | unsigned GPREnd = Subtarget->isPPC64() ? PPC::X31 : PPC::R31; |
2523 | |
2524 | for (unsigned Reg = GPRBegin; Reg <= GPREnd; ++Reg) { |
2525 | if (MRI.isPhysRegModified(PhysReg: Reg)) { |
2526 | GPRSaved = GPREnd - Reg + 1; |
2527 | break; |
2528 | } |
2529 | } |
2530 | |
2531 | SecondHalfOfMandatoryField |= (GPRSaved << TracebackTable::GPRSavedShift) & |
2532 | TracebackTable::GPRSavedMask; |
2533 | |
2534 | GENBOOLCOMMENT("" , SecondHalfOfMandatoryField, HasExtensionTable); |
2535 | GENBOOLCOMMENT(", " , SecondHalfOfMandatoryField, HasVectorInfo); |
2536 | GENVALUECOMMENT(", NumOfGPRsSaved" , SecondHalfOfMandatoryField, GPRSaved); |
2537 | EmitComment(); |
2538 | OutStreamer->emitIntValueInHexWithPadding( |
2539 | Value: (SecondHalfOfMandatoryField & 0x00ff0000) >> 16, Size: 1); |
2540 | |
2541 | // Set the 7th byte of mandatory field. |
2542 | uint32_t NumberOfFixedParms = FI->getFixedParmsNum(); |
2543 | SecondHalfOfMandatoryField |= |
2544 | (NumberOfFixedParms << TracebackTable::NumberOfFixedParmsShift) & |
2545 | TracebackTable::NumberOfFixedParmsMask; |
2546 | GENVALUECOMMENT("NumberOfFixedParms" , SecondHalfOfMandatoryField, |
2547 | NumberOfFixedParms); |
2548 | EmitComment(); |
2549 | OutStreamer->emitIntValueInHexWithPadding( |
2550 | Value: (SecondHalfOfMandatoryField & 0x0000ff00) >> 8, Size: 1); |
2551 | |
2552 | // Set the 8th byte of mandatory field. |
2553 | |
2554 | // Always set parameter on stack. |
2555 | SecondHalfOfMandatoryField |= TracebackTable::HasParmsOnStackMask; |
2556 | |
2557 | uint32_t NumberOfFPParms = FI->getFloatingPointParmsNum(); |
2558 | SecondHalfOfMandatoryField |= |
2559 | (NumberOfFPParms << TracebackTable::NumberOfFloatingPointParmsShift) & |
2560 | TracebackTable::NumberOfFloatingPointParmsMask; |
2561 | |
2562 | GENVALUECOMMENT("NumberOfFPParms" , SecondHalfOfMandatoryField, |
2563 | NumberOfFloatingPointParms); |
2564 | GENBOOLCOMMENT(", " , SecondHalfOfMandatoryField, HasParmsOnStack); |
2565 | EmitComment(); |
2566 | OutStreamer->emitIntValueInHexWithPadding(Value: SecondHalfOfMandatoryField & 0xff, |
2567 | Size: 1); |
2568 | |
2569 | // Generate the optional fields of traceback table. |
2570 | |
2571 | // Parameter type. |
2572 | if (NumberOfFixedParms || NumberOfFPParms) { |
2573 | uint32_t ParmsTypeValue = FI->getParmsType(); |
2574 | |
2575 | Expected<SmallString<32>> ParmsType = |
2576 | FI->hasVectorParms() |
2577 | ? XCOFF::parseParmsTypeWithVecInfo( |
2578 | Value: ParmsTypeValue, FixedParmsNum: NumberOfFixedParms, FloatingParmsNum: NumberOfFPParms, |
2579 | VectorParmsNum: FI->getVectorParmsNum()) |
2580 | : XCOFF::parseParmsType(Value: ParmsTypeValue, FixedParmsNum: NumberOfFixedParms, |
2581 | FloatingParmsNum: NumberOfFPParms); |
2582 | |
2583 | assert(ParmsType && toString(ParmsType.takeError()).c_str()); |
2584 | if (ParmsType) { |
2585 | CommentOS << "Parameter type = " << ParmsType.get(); |
2586 | EmitComment(); |
2587 | } |
2588 | OutStreamer->emitIntValueInHexWithPadding(Value: ParmsTypeValue, |
2589 | Size: sizeof(ParmsTypeValue)); |
2590 | } |
2591 | // Traceback table offset. |
2592 | OutStreamer->AddComment(T: "Function size" ); |
2593 | if (FirstHalfOfMandatoryField & TracebackTable::HasTraceBackTableOffsetMask) { |
2594 | MCSymbol *FuncSectSym = getObjFileLowering().getFunctionEntryPointSymbol( |
2595 | Func: &(MF->getFunction()), TM); |
2596 | OutStreamer->emitAbsoluteSymbolDiff(Hi: FuncEnd, Lo: FuncSectSym, Size: 4); |
2597 | } |
2598 | |
2599 | // Since we unset the Int_Handler. |
2600 | if (FirstHalfOfMandatoryField & TracebackTable::IsInterruptHandlerMask) |
2601 | report_fatal_error(reason: "Hand_Mask not implement yet" ); |
2602 | |
2603 | if (FirstHalfOfMandatoryField & TracebackTable::HasControlledStorageMask) |
2604 | report_fatal_error(reason: "Ctl_Info not implement yet" ); |
2605 | |
2606 | if (FirstHalfOfMandatoryField & TracebackTable::IsFunctionNamePresentMask) { |
2607 | StringRef Name = MF->getName().substr(Start: 0, INT16_MAX); |
2608 | int16_t NameLength = Name.size(); |
2609 | CommentOS << "Function name len = " |
2610 | << static_cast<unsigned int>(NameLength); |
2611 | EmitCommentAndValue(NameLength, 2); |
2612 | OutStreamer->AddComment(T: "Function Name" ); |
2613 | OutStreamer->emitBytes(Data: Name); |
2614 | } |
2615 | |
2616 | if (FirstHalfOfMandatoryField & TracebackTable::IsAllocaUsedMask) { |
2617 | uint8_t AllocReg = XCOFF::AllocRegNo; |
2618 | OutStreamer->AddComment(T: "AllocaUsed" ); |
2619 | OutStreamer->emitIntValueInHex(Value: AllocReg, Size: sizeof(AllocReg)); |
2620 | } |
2621 | |
2622 | if (SecondHalfOfMandatoryField & TracebackTable::HasVectorInfoMask) { |
2623 | uint16_t VRData = 0; |
2624 | if (NumOfVRSaved) { |
2625 | // Number of VRs saved. |
2626 | VRData |= (NumOfVRSaved << TracebackTable::NumberOfVRSavedShift) & |
2627 | TracebackTable::NumberOfVRSavedMask; |
2628 | // This bit is supposed to set only when the special register |
2629 | // VRSAVE is saved on stack. |
2630 | // However, IBM XL compiler sets the bit when any vector registers |
2631 | // are saved on the stack. We will follow XL's behavior on AIX |
2632 | // so that we don't get surprise behavior change for C code. |
2633 | VRData |= TracebackTable::IsVRSavedOnStackMask; |
2634 | } |
2635 | |
2636 | // Set has_varargs. |
2637 | if (FI->getVarArgsFrameIndex()) |
2638 | VRData |= TracebackTable::HasVarArgsMask; |
2639 | |
2640 | // Vector parameters number. |
2641 | unsigned VectorParmsNum = FI->getVectorParmsNum(); |
2642 | VRData |= (VectorParmsNum << TracebackTable::NumberOfVectorParmsShift) & |
2643 | TracebackTable::NumberOfVectorParmsMask; |
2644 | |
2645 | if (HasVectorInst) |
2646 | VRData |= TracebackTable::HasVMXInstructionMask; |
2647 | |
2648 | GENVALUECOMMENT("NumOfVRsSaved" , VRData, NumberOfVRSaved); |
2649 | GENBOOLCOMMENT(", " , VRData, IsVRSavedOnStack); |
2650 | GENBOOLCOMMENT(", " , VRData, HasVarArgs); |
2651 | EmitComment(); |
2652 | OutStreamer->emitIntValueInHexWithPadding(Value: (VRData & 0xff00) >> 8, Size: 1); |
2653 | |
2654 | GENVALUECOMMENT("NumOfVectorParams" , VRData, NumberOfVectorParms); |
2655 | GENBOOLCOMMENT(", " , VRData, HasVMXInstruction); |
2656 | EmitComment(); |
2657 | OutStreamer->emitIntValueInHexWithPadding(Value: VRData & 0x00ff, Size: 1); |
2658 | |
2659 | uint32_t VecParmTypeValue = FI->getVecExtParmsType(); |
2660 | |
2661 | Expected<SmallString<32>> VecParmsType = |
2662 | XCOFF::parseVectorParmsType(Value: VecParmTypeValue, ParmsNum: VectorParmsNum); |
2663 | assert(VecParmsType && toString(VecParmsType.takeError()).c_str()); |
2664 | if (VecParmsType) { |
2665 | CommentOS << "Vector Parameter type = " << VecParmsType.get(); |
2666 | EmitComment(); |
2667 | } |
2668 | OutStreamer->emitIntValueInHexWithPadding(Value: VecParmTypeValue, |
2669 | Size: sizeof(VecParmTypeValue)); |
2670 | // Padding 2 bytes. |
2671 | CommentOS << "Padding" ; |
2672 | EmitCommentAndValue(0, 2); |
2673 | } |
2674 | |
2675 | uint8_t ExtensionTableFlag = 0; |
2676 | if (SecondHalfOfMandatoryField & TracebackTable::HasExtensionTableMask) { |
2677 | if (ShouldEmitEHBlock) |
2678 | ExtensionTableFlag |= ExtendedTBTableFlag::TB_EH_INFO; |
2679 | if (EnableSSPCanaryBitInTB && |
2680 | TargetLoweringObjectFileXCOFF::ShouldSetSSPCanaryBitInTB(MF)) |
2681 | ExtensionTableFlag |= ExtendedTBTableFlag::TB_SSP_CANARY; |
2682 | |
2683 | CommentOS << "ExtensionTableFlag = " |
2684 | << getExtendedTBTableFlagString(Flag: ExtensionTableFlag); |
2685 | EmitCommentAndValue(ExtensionTableFlag, sizeof(ExtensionTableFlag)); |
2686 | } |
2687 | |
2688 | if (ExtensionTableFlag & ExtendedTBTableFlag::TB_EH_INFO) { |
2689 | auto &Ctx = OutStreamer->getContext(); |
2690 | MCSymbol *EHInfoSym = |
2691 | TargetLoweringObjectFileXCOFF::getEHInfoTableSymbol(MF); |
2692 | MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(Sym: EHInfoSym, Type: TOCType_EHBlock); |
2693 | const MCSymbol *TOCBaseSym = |
2694 | cast<MCSectionXCOFF>(Val: getObjFileLowering().getTOCBaseSection()) |
2695 | ->getQualNameSymbol(); |
2696 | const MCExpr *Exp = |
2697 | MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: TOCEntry, Ctx), |
2698 | RHS: MCSymbolRefExpr::create(Symbol: TOCBaseSym, Ctx), Ctx); |
2699 | |
2700 | const DataLayout &DL = getDataLayout(); |
2701 | OutStreamer->emitValueToAlignment(Alignment: Align(4)); |
2702 | OutStreamer->AddComment(T: "EHInfo Table" ); |
2703 | OutStreamer->emitValue(Value: Exp, Size: DL.getPointerSize()); |
2704 | } |
2705 | #undef GENBOOLCOMMENT |
2706 | #undef GENVALUECOMMENT |
2707 | } |
2708 | |
2709 | static bool isSpecialLLVMGlobalArrayToSkip(const GlobalVariable *GV) { |
2710 | return GV->hasAppendingLinkage() && |
2711 | StringSwitch<bool>(GV->getName()) |
2712 | // TODO: Linker could still eliminate the GV if we just skip |
2713 | // handling llvm.used array. Skipping them for now until we or the |
2714 | // AIX OS team come up with a good solution. |
2715 | .Case(S: "llvm.used" , Value: true) |
2716 | // It's correct to just skip llvm.compiler.used array here. |
2717 | .Case(S: "llvm.compiler.used" , Value: true) |
2718 | .Default(Value: false); |
2719 | } |
2720 | |
2721 | static bool isSpecialLLVMGlobalArrayForStaticInit(const GlobalVariable *GV) { |
2722 | return StringSwitch<bool>(GV->getName()) |
2723 | .Cases(S0: "llvm.global_ctors" , S1: "llvm.global_dtors" , Value: true) |
2724 | .Default(Value: false); |
2725 | } |
2726 | |
2727 | uint64_t PPCAIXAsmPrinter::getAliasOffset(const Constant *C) { |
2728 | if (auto *GA = dyn_cast<GlobalAlias>(Val: C)) |
2729 | return getAliasOffset(C: GA->getAliasee()); |
2730 | if (auto *CE = dyn_cast<ConstantExpr>(Val: C)) { |
2731 | const MCExpr *LowC = lowerConstant(CV: CE); |
2732 | const MCBinaryExpr *CBE = dyn_cast<MCBinaryExpr>(Val: LowC); |
2733 | if (!CBE) |
2734 | return 0; |
2735 | if (CBE->getOpcode() != MCBinaryExpr::Add) |
2736 | report_fatal_error(reason: "Only adding an offset is supported now." ); |
2737 | auto *RHS = dyn_cast<MCConstantExpr>(Val: CBE->getRHS()); |
2738 | if (!RHS) |
2739 | report_fatal_error(reason: "Unable to get the offset of alias." ); |
2740 | return RHS->getValue(); |
2741 | } |
2742 | return 0; |
2743 | } |
2744 | |
2745 | static void tocDataChecks(unsigned PointerSize, const GlobalVariable *GV) { |
2746 | // TODO: These asserts should be updated as more support for the toc data |
2747 | // transformation is added (struct support, etc.). |
2748 | assert( |
2749 | PointerSize >= GV->getAlign().valueOrOne().value() && |
2750 | "GlobalVariables with an alignment requirement stricter than TOC entry " |
2751 | "size not supported by the toc data transformation." ); |
2752 | |
2753 | Type *GVType = GV->getValueType(); |
2754 | assert(GVType->isSized() && "A GlobalVariable's size must be known to be " |
2755 | "supported by the toc data transformation." ); |
2756 | if (GV->getDataLayout().getTypeSizeInBits(Ty: GVType) > |
2757 | PointerSize * 8) |
2758 | report_fatal_error( |
2759 | reason: "A GlobalVariable with size larger than a TOC entry is not currently " |
2760 | "supported by the toc data transformation." ); |
2761 | if (GV->hasPrivateLinkage()) |
2762 | report_fatal_error(reason: "A GlobalVariable with private linkage is not " |
2763 | "currently supported by the toc data transformation." ); |
2764 | } |
2765 | |
2766 | void PPCAIXAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { |
2767 | // Special LLVM global arrays have been handled at the initialization. |
2768 | if (isSpecialLLVMGlobalArrayToSkip(GV) || isSpecialLLVMGlobalArrayForStaticInit(GV)) |
2769 | return; |
2770 | |
2771 | // If the Global Variable has the toc-data attribute, it needs to be emitted |
2772 | // when we emit the .toc section. |
2773 | if (GV->hasAttribute(Kind: "toc-data" )) { |
2774 | unsigned PointerSize = GV->getDataLayout().getPointerSize(); |
2775 | tocDataChecks(PointerSize, GV); |
2776 | TOCDataGlobalVars.push_back(Elt: GV); |
2777 | return; |
2778 | } |
2779 | |
2780 | emitGlobalVariableHelper(GV); |
2781 | } |
2782 | |
2783 | void PPCAIXAsmPrinter::emitGlobalVariableHelper(const GlobalVariable *GV) { |
2784 | assert(!GV->getName().starts_with("llvm." ) && |
2785 | "Unhandled intrinsic global variable." ); |
2786 | |
2787 | if (GV->hasComdat()) |
2788 | report_fatal_error(reason: "COMDAT not yet supported by AIX." ); |
2789 | |
2790 | MCSymbolXCOFF *GVSym = cast<MCSymbolXCOFF>(Val: getSymbol(GV)); |
2791 | |
2792 | if (GV->isDeclarationForLinker()) { |
2793 | emitLinkage(GV, GVSym); |
2794 | return; |
2795 | } |
2796 | |
2797 | SectionKind GVKind = getObjFileLowering().getKindForGlobal(GO: GV, TM); |
2798 | if (!GVKind.isGlobalWriteableData() && !GVKind.isReadOnly() && |
2799 | !GVKind.isThreadLocal()) // Checks for both ThreadData and ThreadBSS. |
2800 | report_fatal_error(reason: "Encountered a global variable kind that is " |
2801 | "not supported yet." ); |
2802 | |
2803 | // Print GV in verbose mode |
2804 | if (isVerbose()) { |
2805 | if (GV->hasInitializer()) { |
2806 | GV->printAsOperand(O&: OutStreamer->getCommentOS(), |
2807 | /*PrintType=*/false, M: GV->getParent()); |
2808 | OutStreamer->getCommentOS() << '\n'; |
2809 | } |
2810 | } |
2811 | |
2812 | MCSectionXCOFF *Csect = cast<MCSectionXCOFF>( |
2813 | Val: getObjFileLowering().SectionForGlobal(GO: GV, Kind: GVKind, TM)); |
2814 | |
2815 | // Switch to the containing csect. |
2816 | OutStreamer->switchSection(Section: Csect); |
2817 | |
2818 | const DataLayout &DL = GV->getDataLayout(); |
2819 | |
2820 | // Handle common and zero-initialized local symbols. |
2821 | if (GV->hasCommonLinkage() || GVKind.isBSSLocal() || |
2822 | GVKind.isThreadBSSLocal()) { |
2823 | Align Alignment = GV->getAlign().value_or(u: DL.getPreferredAlign(GV)); |
2824 | uint64_t Size = DL.getTypeAllocSize(Ty: GV->getValueType()); |
2825 | GVSym->setStorageClass( |
2826 | TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GV)); |
2827 | |
2828 | if (GVKind.isBSSLocal() && Csect->getMappingClass() == XCOFF::XMC_TD) { |
2829 | OutStreamer->emitZeros(NumBytes: Size); |
2830 | } else if (GVKind.isBSSLocal() || GVKind.isThreadBSSLocal()) { |
2831 | assert(Csect->getMappingClass() != XCOFF::XMC_TD && |
2832 | "BSS local toc-data already handled and TLS variables " |
2833 | "incompatible with XMC_TD" ); |
2834 | OutStreamer->emitXCOFFLocalCommonSymbol( |
2835 | LabelSym: OutContext.getOrCreateSymbol(Name: GVSym->getSymbolTableName()), Size, |
2836 | CsectSym: GVSym, Alignment); |
2837 | } else { |
2838 | OutStreamer->emitCommonSymbol(Symbol: GVSym, Size, ByteAlignment: Alignment); |
2839 | } |
2840 | return; |
2841 | } |
2842 | |
2843 | MCSymbol *EmittedInitSym = GVSym; |
2844 | |
2845 | // Emit linkage for the global variable and its aliases. |
2846 | emitLinkage(GV, GVSym: EmittedInitSym); |
2847 | for (const GlobalAlias *GA : GOAliasMap[GV]) |
2848 | emitLinkage(GV: GA, GVSym: getSymbol(GV: GA)); |
2849 | |
2850 | emitAlignment(Alignment: getGVAlignment(GV, DL), GV); |
2851 | |
2852 | // When -fdata-sections is enabled, every GlobalVariable will |
2853 | // be put into its own csect; therefore, label is not necessary here. |
2854 | if (!TM.getDataSections() || GV->hasSection()) { |
2855 | if (Csect->getMappingClass() != XCOFF::XMC_TD) |
2856 | OutStreamer->emitLabel(Symbol: EmittedInitSym); |
2857 | } |
2858 | |
2859 | // No alias to emit. |
2860 | if (!GOAliasMap[GV].size()) { |
2861 | emitGlobalConstant(DL: GV->getDataLayout(), CV: GV->getInitializer()); |
2862 | return; |
2863 | } |
2864 | |
2865 | // Aliases with the same offset should be aligned. Record the list of aliases |
2866 | // associated with the offset. |
2867 | AliasMapTy AliasList; |
2868 | for (const GlobalAlias *GA : GOAliasMap[GV]) |
2869 | AliasList[getAliasOffset(C: GA->getAliasee())].push_back(Elt: GA); |
2870 | |
2871 | // Emit alias label and element value for global variable. |
2872 | emitGlobalConstant(DL: GV->getDataLayout(), CV: GV->getInitializer(), |
2873 | AliasList: &AliasList); |
2874 | } |
2875 | |
2876 | void PPCAIXAsmPrinter::emitFunctionDescriptor() { |
2877 | const DataLayout &DL = getDataLayout(); |
2878 | const unsigned PointerSize = DL.getPointerSizeInBits() == 64 ? 8 : 4; |
2879 | |
2880 | MCSectionSubPair Current = OutStreamer->getCurrentSection(); |
2881 | // Emit function descriptor. |
2882 | OutStreamer->switchSection( |
2883 | Section: cast<MCSymbolXCOFF>(Val: CurrentFnDescSym)->getRepresentedCsect()); |
2884 | |
2885 | // Emit aliasing label for function descriptor csect. |
2886 | for (const GlobalAlias *Alias : GOAliasMap[&MF->getFunction()]) |
2887 | OutStreamer->emitLabel(Symbol: getSymbol(GV: Alias)); |
2888 | |
2889 | // Emit function entry point address. |
2890 | OutStreamer->emitValue(Value: MCSymbolRefExpr::create(Symbol: CurrentFnSym, Ctx&: OutContext), |
2891 | Size: PointerSize); |
2892 | // Emit TOC base address. |
2893 | const MCSymbol *TOCBaseSym = |
2894 | cast<MCSectionXCOFF>(Val: getObjFileLowering().getTOCBaseSection()) |
2895 | ->getQualNameSymbol(); |
2896 | OutStreamer->emitValue(Value: MCSymbolRefExpr::create(Symbol: TOCBaseSym, Ctx&: OutContext), |
2897 | Size: PointerSize); |
2898 | // Emit a null environment pointer. |
2899 | OutStreamer->emitIntValue(Value: 0, Size: PointerSize); |
2900 | |
2901 | OutStreamer->switchSection(Section: Current.first, Subsec: Current.second); |
2902 | } |
2903 | |
2904 | void PPCAIXAsmPrinter::emitFunctionEntryLabel() { |
2905 | // For functions without user defined section, it's not necessary to emit the |
2906 | // label when we have individual function in its own csect. |
2907 | if (!TM.getFunctionSections() || MF->getFunction().hasSection()) |
2908 | PPCAsmPrinter::emitFunctionEntryLabel(); |
2909 | |
2910 | // Emit aliasing label for function entry point label. |
2911 | for (const GlobalAlias *Alias : GOAliasMap[&MF->getFunction()]) |
2912 | OutStreamer->emitLabel( |
2913 | Symbol: getObjFileLowering().getFunctionEntryPointSymbol(Func: Alias, TM)); |
2914 | } |
2915 | |
2916 | void PPCAIXAsmPrinter::emitPGORefs(Module &M) { |
2917 | if (!OutContext.hasXCOFFSection( |
2918 | Section: "__llvm_prf_cnts" , |
2919 | CsectProp: XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD))) |
2920 | return; |
2921 | |
2922 | // When inside a csect `foo`, a .ref directive referring to a csect `bar` |
2923 | // translates into a relocation entry from `foo` to` bar`. The referring |
2924 | // csect, `foo`, is identified by its address. If multiple csects have the |
2925 | // same address (because one or more of them are zero-length), the referring |
2926 | // csect cannot be determined. Hence, we don't generate the .ref directives |
2927 | // if `__llvm_prf_cnts` is an empty section. |
2928 | bool HasNonZeroLengthPrfCntsSection = false; |
2929 | const DataLayout &DL = M.getDataLayout(); |
2930 | for (GlobalVariable &GV : M.globals()) |
2931 | if (GV.hasSection() && GV.getSection() == "__llvm_prf_cnts" && |
2932 | DL.getTypeAllocSize(Ty: GV.getValueType()) > 0) { |
2933 | HasNonZeroLengthPrfCntsSection = true; |
2934 | break; |
2935 | } |
2936 | |
2937 | if (HasNonZeroLengthPrfCntsSection) { |
2938 | MCSection *CntsSection = OutContext.getXCOFFSection( |
2939 | Section: "__llvm_prf_cnts" , K: SectionKind::getData(), |
2940 | CsectProp: XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD), |
2941 | /*MultiSymbolsAllowed*/ true); |
2942 | |
2943 | OutStreamer->switchSection(Section: CntsSection); |
2944 | if (OutContext.hasXCOFFSection( |
2945 | Section: "__llvm_prf_data" , |
2946 | CsectProp: XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD))) { |
2947 | MCSymbol *S = OutContext.getOrCreateSymbol(Name: "__llvm_prf_data[RW]" ); |
2948 | OutStreamer->emitXCOFFRefDirective(Symbol: S); |
2949 | } |
2950 | if (OutContext.hasXCOFFSection( |
2951 | Section: "__llvm_prf_names" , |
2952 | CsectProp: XCOFF::CsectProperties(XCOFF::XMC_RO, XCOFF::XTY_SD))) { |
2953 | MCSymbol *S = OutContext.getOrCreateSymbol(Name: "__llvm_prf_names[RO]" ); |
2954 | OutStreamer->emitXCOFFRefDirective(Symbol: S); |
2955 | } |
2956 | if (OutContext.hasXCOFFSection( |
2957 | Section: "__llvm_prf_vnds" , |
2958 | CsectProp: XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD))) { |
2959 | MCSymbol *S = OutContext.getOrCreateSymbol(Name: "__llvm_prf_vnds[RW]" ); |
2960 | OutStreamer->emitXCOFFRefDirective(Symbol: S); |
2961 | } |
2962 | } |
2963 | } |
2964 | |
2965 | void PPCAIXAsmPrinter::emitEndOfAsmFile(Module &M) { |
2966 | // If there are no functions and there are no toc-data definitions in this |
2967 | // module, we will never need to reference the TOC base. |
2968 | if (M.empty() && TOCDataGlobalVars.empty()) |
2969 | return; |
2970 | |
2971 | emitPGORefs(M); |
2972 | |
2973 | // Switch to section to emit TOC base. |
2974 | OutStreamer->switchSection(Section: getObjFileLowering().getTOCBaseSection()); |
2975 | |
2976 | PPCTargetStreamer *TS = |
2977 | static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer()); |
2978 | |
2979 | for (auto &I : TOC) { |
2980 | MCSectionXCOFF *TCEntry; |
2981 | // Setup the csect for the current TC entry. If the variant kind is |
2982 | // VK_PPC_AIX_TLSGDM the entry represents the region handle, we create a |
2983 | // new symbol to prefix the name with a dot. |
2984 | // If TLS model opt is turned on, create a new symbol to prefix the name |
2985 | // with a dot. |
2986 | if (I.first.second == MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSGDM || |
2987 | (Subtarget->hasAIXShLibTLSModelOpt() && |
2988 | I.first.second == MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSLD)) { |
2989 | SmallString<128> Name; |
2990 | StringRef Prefix = "." ; |
2991 | Name += Prefix; |
2992 | Name += cast<MCSymbolXCOFF>(Val: I.first.first)->getSymbolTableName(); |
2993 | MCSymbol *S = OutContext.getOrCreateSymbol(Name); |
2994 | TCEntry = cast<MCSectionXCOFF>( |
2995 | Val: getObjFileLowering().getSectionForTOCEntry(S, TM)); |
2996 | } else { |
2997 | TCEntry = cast<MCSectionXCOFF>( |
2998 | Val: getObjFileLowering().getSectionForTOCEntry(S: I.first.first, TM)); |
2999 | } |
3000 | OutStreamer->switchSection(Section: TCEntry); |
3001 | |
3002 | OutStreamer->emitLabel(Symbol: I.second); |
3003 | TS->emitTCEntry(S: *I.first.first, Kind: I.first.second); |
3004 | } |
3005 | |
3006 | // Traverse the list of global variables twice, emitting all of the |
3007 | // non-common global variables before the common ones, as emitting a |
3008 | // .comm directive changes the scope from .toc to the common symbol. |
3009 | for (const auto *GV : TOCDataGlobalVars) { |
3010 | if (!GV->hasCommonLinkage()) |
3011 | emitGlobalVariableHelper(GV); |
3012 | } |
3013 | for (const auto *GV : TOCDataGlobalVars) { |
3014 | if (GV->hasCommonLinkage()) |
3015 | emitGlobalVariableHelper(GV); |
3016 | } |
3017 | } |
3018 | |
3019 | bool PPCAIXAsmPrinter::doInitialization(Module &M) { |
3020 | const bool Result = PPCAsmPrinter::doInitialization(M); |
3021 | |
3022 | auto setCsectAlignment = [this](const GlobalObject *GO) { |
3023 | // Declarations have 0 alignment which is set by default. |
3024 | if (GO->isDeclarationForLinker()) |
3025 | return; |
3026 | |
3027 | SectionKind GOKind = getObjFileLowering().getKindForGlobal(GO, TM); |
3028 | MCSectionXCOFF *Csect = cast<MCSectionXCOFF>( |
3029 | Val: getObjFileLowering().SectionForGlobal(GO, Kind: GOKind, TM)); |
3030 | |
3031 | Align GOAlign = getGVAlignment(GV: GO, DL: GO->getDataLayout()); |
3032 | Csect->ensureMinAlignment(MinAlignment: GOAlign); |
3033 | }; |
3034 | |
3035 | // For all TLS variables, calculate their corresponding addresses and store |
3036 | // them into TLSVarsToAddressMapping, which will be used to determine whether |
3037 | // or not local-exec TLS variables require special assembly printing. |
3038 | uint64_t TLSVarAddress = 0; |
3039 | auto DL = M.getDataLayout(); |
3040 | for (const auto &G : M.globals()) { |
3041 | if (G.isThreadLocal() && !G.isDeclaration()) { |
3042 | TLSVarAddress = alignTo(Size: TLSVarAddress, A: getGVAlignment(GV: &G, DL)); |
3043 | TLSVarsToAddressMapping[&G] = TLSVarAddress; |
3044 | TLSVarAddress += DL.getTypeAllocSize(Ty: G.getValueType()); |
3045 | } |
3046 | } |
3047 | |
3048 | // We need to know, up front, the alignment of csects for the assembly path, |
3049 | // because once a .csect directive gets emitted, we could not change the |
3050 | // alignment value on it. |
3051 | for (const auto &G : M.globals()) { |
3052 | if (isSpecialLLVMGlobalArrayToSkip(GV: &G)) |
3053 | continue; |
3054 | |
3055 | if (isSpecialLLVMGlobalArrayForStaticInit(GV: &G)) { |
3056 | // Generate a format indicator and a unique module id to be a part of |
3057 | // the sinit and sterm function names. |
3058 | if (FormatIndicatorAndUniqueModId.empty()) { |
3059 | std::string UniqueModuleId = getUniqueModuleId(M: &M); |
3060 | if (UniqueModuleId != "" ) |
3061 | // TODO: Use source file full path to generate the unique module id |
3062 | // and add a format indicator as a part of function name in case we |
3063 | // will support more than one format. |
3064 | FormatIndicatorAndUniqueModId = "clang_" + UniqueModuleId.substr(pos: 1); |
3065 | else { |
3066 | // Use threadId, Pid, and current time as the unique module id when we |
3067 | // cannot generate one based on a module's strong external symbols. |
3068 | auto CurTime = |
3069 | std::chrono::duration_cast<std::chrono::nanoseconds>( |
3070 | d: std::chrono::steady_clock::now().time_since_epoch()) |
3071 | .count(); |
3072 | FormatIndicatorAndUniqueModId = |
3073 | "clangPidTidTime_" + llvm::itostr(X: sys::Process::getProcessId()) + |
3074 | "_" + llvm::itostr(X: llvm::get_threadid()) + "_" + |
3075 | llvm::itostr(X: CurTime); |
3076 | } |
3077 | } |
3078 | |
3079 | emitSpecialLLVMGlobal(GV: &G); |
3080 | continue; |
3081 | } |
3082 | |
3083 | setCsectAlignment(&G); |
3084 | std::optional<CodeModel::Model> OptionalCodeModel = G.getCodeModel(); |
3085 | if (OptionalCodeModel) |
3086 | setOptionalCodeModel(XSym: cast<MCSymbolXCOFF>(Val: getSymbol(GV: &G)), |
3087 | CM: *OptionalCodeModel); |
3088 | } |
3089 | |
3090 | for (const auto &F : M) |
3091 | setCsectAlignment(&F); |
3092 | |
3093 | // Construct an aliasing list for each GlobalObject. |
3094 | for (const auto &Alias : M.aliases()) { |
3095 | const GlobalObject *Aliasee = Alias.getAliaseeObject(); |
3096 | if (!Aliasee) |
3097 | report_fatal_error( |
3098 | reason: "alias without a base object is not yet supported on AIX" ); |
3099 | |
3100 | if (Aliasee->hasCommonLinkage()) { |
3101 | report_fatal_error(reason: "Aliases to common variables are not allowed on AIX:" |
3102 | "\n\tAlias attribute for " + |
3103 | Alias.getGlobalIdentifier() + |
3104 | " is invalid because " + Aliasee->getName() + |
3105 | " is common." , |
3106 | gen_crash_diag: false); |
3107 | } |
3108 | |
3109 | const GlobalVariable *GVar = |
3110 | dyn_cast_or_null<GlobalVariable>(Val: Alias.getAliaseeObject()); |
3111 | if (GVar) { |
3112 | std::optional<CodeModel::Model> OptionalCodeModel = GVar->getCodeModel(); |
3113 | if (OptionalCodeModel) |
3114 | setOptionalCodeModel(XSym: cast<MCSymbolXCOFF>(Val: getSymbol(GV: &Alias)), |
3115 | CM: *OptionalCodeModel); |
3116 | } |
3117 | |
3118 | GOAliasMap[Aliasee].push_back(Elt: &Alias); |
3119 | } |
3120 | |
3121 | return Result; |
3122 | } |
3123 | |
3124 | void PPCAIXAsmPrinter::emitInstruction(const MachineInstr *MI) { |
3125 | switch (MI->getOpcode()) { |
3126 | default: |
3127 | break; |
3128 | case PPC::TW: |
3129 | case PPC::TWI: |
3130 | case PPC::TD: |
3131 | case PPC::TDI: { |
3132 | if (MI->getNumOperands() < 5) |
3133 | break; |
3134 | const MachineOperand &LangMO = MI->getOperand(i: 3); |
3135 | const MachineOperand &ReasonMO = MI->getOperand(i: 4); |
3136 | if (!LangMO.isImm() || !ReasonMO.isImm()) |
3137 | break; |
3138 | MCSymbol *TempSym = OutContext.createNamedTempSymbol(); |
3139 | OutStreamer->emitLabel(Symbol: TempSym); |
3140 | OutStreamer->emitXCOFFExceptDirective(Symbol: CurrentFnSym, Trap: TempSym, |
3141 | Lang: LangMO.getImm(), Reason: ReasonMO.getImm(), |
3142 | FunctionSize: Subtarget->isPPC64() ? MI->getMF()->getInstructionCount() * 8 : |
3143 | MI->getMF()->getInstructionCount() * 4, |
3144 | hasDebug: MMI->hasDebugInfo()); |
3145 | break; |
3146 | } |
3147 | case PPC::GETtlsMOD32AIX: |
3148 | case PPC::GETtlsMOD64AIX: |
3149 | case PPC::GETtlsTpointer32AIX: |
3150 | case PPC::GETtlsADDR64AIX: |
3151 | case PPC::GETtlsADDR32AIX: { |
3152 | // A reference to .__tls_get_mod/.__tls_get_addr/.__get_tpointer is unknown |
3153 | // to the assembler so we need to emit an external symbol reference. |
3154 | MCSymbol *TlsGetAddr = |
3155 | createMCSymbolForTlsGetAddr(Ctx&: OutContext, MIOpc: MI->getOpcode()); |
3156 | ExtSymSDNodeSymbols.insert(X: TlsGetAddr); |
3157 | break; |
3158 | } |
3159 | case PPC::BL8: |
3160 | case PPC::BL: |
3161 | case PPC::BL8_NOP: |
3162 | case PPC::BL_NOP: { |
3163 | const MachineOperand &MO = MI->getOperand(i: 0); |
3164 | if (MO.isSymbol()) { |
3165 | MCSymbolXCOFF *S = |
3166 | cast<MCSymbolXCOFF>(Val: OutContext.getOrCreateSymbol(Name: MO.getSymbolName())); |
3167 | ExtSymSDNodeSymbols.insert(X: S); |
3168 | } |
3169 | } break; |
3170 | case PPC::BL_TLS: |
3171 | case PPC::BL8_TLS: |
3172 | case PPC::BL8_TLS_: |
3173 | case PPC::BL8_NOP_TLS: |
3174 | report_fatal_error(reason: "TLS call not yet implemented" ); |
3175 | case PPC::TAILB: |
3176 | case PPC::TAILB8: |
3177 | case PPC::TAILBA: |
3178 | case PPC::TAILBA8: |
3179 | case PPC::TAILBCTR: |
3180 | case PPC::TAILBCTR8: |
3181 | if (MI->getOperand(i: 0).isSymbol()) |
3182 | report_fatal_error(reason: "Tail call for extern symbol not yet supported." ); |
3183 | break; |
3184 | case PPC::DST: |
3185 | case PPC::DST64: |
3186 | case PPC::DSTT: |
3187 | case PPC::DSTT64: |
3188 | case PPC::DSTST: |
3189 | case PPC::DSTST64: |
3190 | case PPC::DSTSTT: |
3191 | case PPC::DSTSTT64: |
3192 | EmitToStreamer( |
3193 | S&: *OutStreamer, |
3194 | Inst: MCInstBuilder(PPC::ORI).addReg(Reg: PPC::R0).addReg(Reg: PPC::R0).addImm(Val: 0)); |
3195 | return; |
3196 | } |
3197 | return PPCAsmPrinter::emitInstruction(MI); |
3198 | } |
3199 | |
3200 | bool PPCAIXAsmPrinter::doFinalization(Module &M) { |
3201 | // Do streamer related finalization for DWARF. |
3202 | if (!MAI->usesDwarfFileAndLocDirectives() && MMI->hasDebugInfo()) |
3203 | OutStreamer->doFinalizationAtSectionEnd( |
3204 | Section: OutStreamer->getContext().getObjectFileInfo()->getTextSection()); |
3205 | |
3206 | for (MCSymbol *Sym : ExtSymSDNodeSymbols) |
3207 | OutStreamer->emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_Extern); |
3208 | return PPCAsmPrinter::doFinalization(M); |
3209 | } |
3210 | |
3211 | static unsigned mapToSinitPriority(int P) { |
3212 | if (P < 0 || P > 65535) |
3213 | report_fatal_error(reason: "invalid init priority" ); |
3214 | |
3215 | if (P <= 20) |
3216 | return P; |
3217 | |
3218 | if (P < 81) |
3219 | return 20 + (P - 20) * 16; |
3220 | |
3221 | if (P <= 1124) |
3222 | return 1004 + (P - 81); |
3223 | |
3224 | if (P < 64512) |
3225 | return 2047 + (P - 1124) * 33878; |
3226 | |
3227 | return 2147482625u + (P - 64512); |
3228 | } |
3229 | |
3230 | static std::string convertToSinitPriority(int Priority) { |
3231 | // This helper function converts clang init priority to values used in sinit |
3232 | // and sterm functions. |
3233 | // |
3234 | // The conversion strategies are: |
3235 | // We map the reserved clang/gnu priority range [0, 100] into the sinit/sterm |
3236 | // reserved priority range [0, 1023] by |
3237 | // - directly mapping the first 21 and the last 20 elements of the ranges |
3238 | // - linear interpolating the intermediate values with a step size of 16. |
3239 | // |
3240 | // We map the non reserved clang/gnu priority range of [101, 65535] into the |
3241 | // sinit/sterm priority range [1024, 2147483648] by: |
3242 | // - directly mapping the first and the last 1024 elements of the ranges |
3243 | // - linear interpolating the intermediate values with a step size of 33878. |
3244 | unsigned int P = mapToSinitPriority(P: Priority); |
3245 | |
3246 | std::string PrioritySuffix; |
3247 | llvm::raw_string_ostream os(PrioritySuffix); |
3248 | os << llvm::format_hex_no_prefix(N: P, Width: 8); |
3249 | os.flush(); |
3250 | return PrioritySuffix; |
3251 | } |
3252 | |
3253 | void PPCAIXAsmPrinter::emitXXStructorList(const DataLayout &DL, |
3254 | const Constant *List, bool IsCtor) { |
3255 | SmallVector<Structor, 8> Structors; |
3256 | preprocessXXStructorList(DL, List, Structors); |
3257 | if (Structors.empty()) |
3258 | return; |
3259 | |
3260 | unsigned Index = 0; |
3261 | for (Structor &S : Structors) { |
3262 | if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(Val: S.Func)) |
3263 | S.Func = CE->getOperand(i_nocapture: 0); |
3264 | |
3265 | llvm::GlobalAlias::create( |
3266 | Linkage: GlobalValue::ExternalLinkage, |
3267 | Name: (IsCtor ? llvm::Twine("__sinit" ) : llvm::Twine("__sterm" )) + |
3268 | llvm::Twine(convertToSinitPriority(Priority: S.Priority)) + |
3269 | llvm::Twine("_" , FormatIndicatorAndUniqueModId) + |
3270 | llvm::Twine("_" , llvm::utostr(X: Index++)), |
3271 | Aliasee: cast<Function>(Val: S.Func)); |
3272 | } |
3273 | } |
3274 | |
3275 | void PPCAIXAsmPrinter::emitTTypeReference(const GlobalValue *GV, |
3276 | unsigned Encoding) { |
3277 | if (GV) { |
3278 | TOCEntryType GlobalType = TOCType_GlobalInternal; |
3279 | GlobalValue::LinkageTypes Linkage = GV->getLinkage(); |
3280 | if (Linkage == GlobalValue::ExternalLinkage || |
3281 | Linkage == GlobalValue::AvailableExternallyLinkage || |
3282 | Linkage == GlobalValue::ExternalWeakLinkage) |
3283 | GlobalType = TOCType_GlobalExternal; |
3284 | MCSymbol *TypeInfoSym = TM.getSymbol(GV); |
3285 | MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(Sym: TypeInfoSym, Type: GlobalType); |
3286 | const MCSymbol *TOCBaseSym = |
3287 | cast<MCSectionXCOFF>(Val: getObjFileLowering().getTOCBaseSection()) |
3288 | ->getQualNameSymbol(); |
3289 | auto &Ctx = OutStreamer->getContext(); |
3290 | const MCExpr *Exp = |
3291 | MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: TOCEntry, Ctx), |
3292 | RHS: MCSymbolRefExpr::create(Symbol: TOCBaseSym, Ctx), Ctx); |
3293 | OutStreamer->emitValue(Value: Exp, Size: GetSizeOfEncodedValue(Encoding)); |
3294 | } else |
3295 | OutStreamer->emitIntValue(Value: 0, Size: GetSizeOfEncodedValue(Encoding)); |
3296 | } |
3297 | |
3298 | // Return a pass that prints the PPC assembly code for a MachineFunction to the |
3299 | // given output stream. |
3300 | static AsmPrinter * |
3301 | createPPCAsmPrinterPass(TargetMachine &tm, |
3302 | std::unique_ptr<MCStreamer> &&Streamer) { |
3303 | if (tm.getTargetTriple().isOSAIX()) |
3304 | return new PPCAIXAsmPrinter(tm, std::move(Streamer)); |
3305 | |
3306 | return new PPCLinuxAsmPrinter(tm, std::move(Streamer)); |
3307 | } |
3308 | |
3309 | void PPCAIXAsmPrinter::emitModuleCommandLines(Module &M) { |
3310 | const NamedMDNode *NMD = M.getNamedMetadata(Name: "llvm.commandline" ); |
3311 | if (!NMD || !NMD->getNumOperands()) |
3312 | return; |
3313 | |
3314 | std::string S; |
3315 | raw_string_ostream RSOS(S); |
3316 | for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { |
3317 | const MDNode *N = NMD->getOperand(i); |
3318 | assert(N->getNumOperands() == 1 && |
3319 | "llvm.commandline metadata entry can have only one operand" ); |
3320 | const MDString *MDS = cast<MDString>(Val: N->getOperand(I: 0)); |
3321 | // Add "@(#)" to support retrieving the command line information with the |
3322 | // AIX "what" command |
3323 | RSOS << "@(#)opt " << MDS->getString() << "\n" ; |
3324 | RSOS.write(C: '\0'); |
3325 | } |
3326 | OutStreamer->emitXCOFFCInfoSym(Name: ".GCC.command.line" , Metadata: RSOS.str()); |
3327 | } |
3328 | |
3329 | // Force static initialization. |
3330 | extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializePowerPCAsmPrinter() { |
3331 | TargetRegistry::RegisterAsmPrinter(T&: getThePPC32Target(), |
3332 | Fn: createPPCAsmPrinterPass); |
3333 | TargetRegistry::RegisterAsmPrinter(T&: getThePPC32LETarget(), |
3334 | Fn: createPPCAsmPrinterPass); |
3335 | TargetRegistry::RegisterAsmPrinter(T&: getThePPC64Target(), |
3336 | Fn: createPPCAsmPrinterPass); |
3337 | TargetRegistry::RegisterAsmPrinter(T&: getThePPC64LETarget(), |
3338 | Fn: createPPCAsmPrinterPass); |
3339 | } |
3340 | |