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/SmallPtrSet.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 *getAdjustedLocalExecExpr(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 | SmallPtrSet<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(*OutStreamer, 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(*OutStreamer, MCInstBuilder(PPC::LI8) |
573 | .addReg(ScratchReg) |
574 | .addImm((CallTarget >> 32) & 0xFFFF)); |
575 | ++EncodedBytes; |
576 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::RLDIC) |
577 | .addReg(ScratchReg) |
578 | .addReg(ScratchReg) |
579 | .addImm(32).addImm(16)); |
580 | ++EncodedBytes; |
581 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ORIS8) |
582 | .addReg(ScratchReg) |
583 | .addReg(ScratchReg) |
584 | .addImm((CallTarget >> 16) & 0xFFFF)); |
585 | ++EncodedBytes; |
586 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ORI8) |
587 | .addReg(ScratchReg) |
588 | .addReg(ScratchReg) |
589 | .addImm(CallTarget & 0xFFFF)); |
590 | |
591 | // Save the current TOC pointer before the remote call. |
592 | int TOCSaveOffset = Subtarget->getFrameLowering()->getTOCSaveOffset(); |
593 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::STD) |
594 | .addReg(PPC::X2) |
595 | .addImm(TOCSaveOffset) |
596 | .addReg(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(*OutStreamer, MCInstBuilder(PPC::LD) |
606 | .addReg(PPC::X2) |
607 | .addImm(8) |
608 | .addReg(ScratchReg)); |
609 | ++EncodedBytes; |
610 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LD) |
611 | .addReg(ScratchReg) |
612 | .addImm(0) |
613 | .addReg(ScratchReg)); |
614 | ++EncodedBytes; |
615 | } |
616 | |
617 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MTCTR8) |
618 | .addReg(ScratchReg)); |
619 | ++EncodedBytes; |
620 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::BCTRL8)); |
621 | ++EncodedBytes; |
622 | |
623 | // Restore the TOC pointer after the call. |
624 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LD) |
625 | .addReg(PPC::X2) |
626 | .addImm(TOCSaveOffset) |
627 | .addReg(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(*OutStreamer, MCInstBuilder(PPC::BL8_NOP) |
636 | .addExpr(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(*OutStreamer, 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(*OutStreamer, MCInstBuilder(PPC::BLA).addExpr(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(MI->getOpcode(), |
801 | 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 | llvm_unreachable("Only expecting local-exec or initial-exec accesses!" ); |
882 | } |
883 | // For GD TLS access on AIX, we have two TOC entries for the symbol (one for |
884 | // the variable offset and the other for the region handle). They are |
885 | // differentiated by MO_TLSGD_FLAG and MO_TLSGDM_FLAG. |
886 | if (Flag == PPCII::MO_TLSGDM_FLAG) |
887 | return MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSGDM; |
888 | if (Flag == PPCII::MO_TLSGD_FLAG || Flag == PPCII::MO_GOT_TLSGD_PCREL_FLAG) |
889 | return MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSGD; |
890 | // For local-dynamic TLS access on AIX, we have one TOC entry for the symbol |
891 | // (the variable offset) and one shared TOC entry for the module handle. |
892 | // They are differentiated by MO_TLSLD_FLAG and MO_TLSLDM_FLAG. |
893 | if (Flag == PPCII::MO_TLSLD_FLAG && IsAIX) |
894 | return MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSLD; |
895 | if (Flag == PPCII::MO_TLSLDM_FLAG && IsAIX) |
896 | return MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSML; |
897 | return MCSymbolRefExpr::VariantKind::VK_None; |
898 | }; |
899 | |
900 | // Lower multi-instruction pseudo operations. |
901 | switch (MI->getOpcode()) { |
902 | default: break; |
903 | case TargetOpcode::DBG_VALUE: |
904 | llvm_unreachable("Should be handled target independently" ); |
905 | case TargetOpcode::STACKMAP: |
906 | return LowerSTACKMAP(SM, MI: *MI); |
907 | case TargetOpcode::PATCHPOINT: |
908 | return LowerPATCHPOINT(SM, MI: *MI); |
909 | |
910 | case PPC::MoveGOTtoLR: { |
911 | // Transform %lr = MoveGOTtoLR |
912 | // Into this: bl _GLOBAL_OFFSET_TABLE_@local-4 |
913 | // _GLOBAL_OFFSET_TABLE_@local-4 (instruction preceding |
914 | // _GLOBAL_OFFSET_TABLE_) has exactly one instruction: |
915 | // blrl |
916 | // This will return the pointer to _GLOBAL_OFFSET_TABLE_@local |
917 | MCSymbol *GOTSymbol = |
918 | OutContext.getOrCreateSymbol(Name: StringRef("_GLOBAL_OFFSET_TABLE_" )); |
919 | const MCExpr *OffsExpr = |
920 | MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: GOTSymbol, |
921 | Kind: MCSymbolRefExpr::VK_PPC_LOCAL, |
922 | Ctx&: OutContext), |
923 | RHS: MCConstantExpr::create(Value: 4, Ctx&: OutContext), |
924 | Ctx&: OutContext); |
925 | |
926 | // Emit the 'bl'. |
927 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::BL).addExpr(OffsExpr)); |
928 | return; |
929 | } |
930 | case PPC::MovePCtoLR: |
931 | case PPC::MovePCtoLR8: { |
932 | // Transform %lr = MovePCtoLR |
933 | // Into this, where the label is the PIC base: |
934 | // bl L1$pb |
935 | // L1$pb: |
936 | MCSymbol *PICBase = MF->getPICBaseSymbol(); |
937 | |
938 | // Emit the 'bl'. |
939 | EmitToStreamer(*OutStreamer, |
940 | MCInstBuilder(PPC::BL) |
941 | // FIXME: We would like an efficient form for this, so we |
942 | // don't have to do a lot of extra uniquing. |
943 | .addExpr(MCSymbolRefExpr::create(PICBase, OutContext))); |
944 | |
945 | // Emit the label. |
946 | OutStreamer->emitLabel(Symbol: PICBase); |
947 | return; |
948 | } |
949 | case PPC::UpdateGBR: { |
950 | // Transform %rd = UpdateGBR(%rt, %ri) |
951 | // Into: lwz %rt, .L0$poff - .L0$pb(%ri) |
952 | // add %rd, %rt, %ri |
953 | // or into (if secure plt mode is on): |
954 | // addis r30, r30, {.LTOC,_GLOBAL_OFFSET_TABLE} - .L0$pb@ha |
955 | // addi r30, r30, {.LTOC,_GLOBAL_OFFSET_TABLE} - .L0$pb@l |
956 | // Get the offset from the GOT Base Register to the GOT |
957 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
958 | if (Subtarget->isSecurePlt() && isPositionIndependent() ) { |
959 | unsigned PICR = TmpInst.getOperand(i: 0).getReg(); |
960 | MCSymbol *BaseSymbol = OutContext.getOrCreateSymbol( |
961 | Name: M->getPICLevel() == PICLevel::SmallPIC ? "_GLOBAL_OFFSET_TABLE_" |
962 | : ".LTOC" ); |
963 | const MCExpr *PB = |
964 | MCSymbolRefExpr::create(Symbol: MF->getPICBaseSymbol(), Ctx&: OutContext); |
965 | |
966 | const MCExpr *DeltaExpr = MCBinaryExpr::createSub( |
967 | LHS: MCSymbolRefExpr::create(Symbol: BaseSymbol, Ctx&: OutContext), RHS: PB, Ctx&: OutContext); |
968 | |
969 | const MCExpr *DeltaHi = PPCMCExpr::createHa(Expr: DeltaExpr, Ctx&: OutContext); |
970 | EmitToStreamer( |
971 | *OutStreamer, |
972 | MCInstBuilder(PPC::ADDIS).addReg(PICR).addReg(PICR).addExpr(DeltaHi)); |
973 | |
974 | const MCExpr *DeltaLo = PPCMCExpr::createLo(Expr: DeltaExpr, Ctx&: OutContext); |
975 | EmitToStreamer( |
976 | *OutStreamer, |
977 | MCInstBuilder(PPC::ADDI).addReg(PICR).addReg(PICR).addExpr(DeltaLo)); |
978 | return; |
979 | } else { |
980 | MCSymbol *PICOffset = |
981 | MF->getInfo<PPCFunctionInfo>()->getPICOffsetSymbol(MF&: *MF); |
982 | TmpInst.setOpcode(PPC::LWZ); |
983 | const MCExpr *Exp = |
984 | MCSymbolRefExpr::create(Symbol: PICOffset, Kind: MCSymbolRefExpr::VK_None, Ctx&: OutContext); |
985 | const MCExpr *PB = |
986 | MCSymbolRefExpr::create(Symbol: MF->getPICBaseSymbol(), |
987 | Kind: MCSymbolRefExpr::VK_None, |
988 | Ctx&: OutContext); |
989 | const MCOperand TR = TmpInst.getOperand(i: 1); |
990 | const MCOperand PICR = TmpInst.getOperand(i: 0); |
991 | |
992 | // Step 1: lwz %rt, .L$poff - .L$pb(%ri) |
993 | TmpInst.getOperand(i: 1) = |
994 | MCOperand::createExpr(Val: MCBinaryExpr::createSub(LHS: Exp, RHS: PB, Ctx&: OutContext)); |
995 | TmpInst.getOperand(i: 0) = TR; |
996 | TmpInst.getOperand(i: 2) = PICR; |
997 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
998 | |
999 | TmpInst.setOpcode(PPC::ADD4); |
1000 | TmpInst.getOperand(i: 0) = PICR; |
1001 | TmpInst.getOperand(i: 1) = TR; |
1002 | TmpInst.getOperand(i: 2) = PICR; |
1003 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1004 | return; |
1005 | } |
1006 | } |
1007 | case PPC::LWZtoc: { |
1008 | // Transform %rN = LWZtoc @op1, %r2 |
1009 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1010 | |
1011 | // Change the opcode to LWZ. |
1012 | TmpInst.setOpcode(PPC::LWZ); |
1013 | |
1014 | const MachineOperand &MO = MI->getOperand(i: 1); |
1015 | assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && |
1016 | "Invalid operand for LWZtoc." ); |
1017 | |
1018 | // Map the operand to its corresponding MCSymbol. |
1019 | const MCSymbol *const MOSymbol = getMCSymbolForTOCPseudoMO(MO, AP&: *this); |
1020 | |
1021 | // Create a reference to the GOT entry for the symbol. The GOT entry will be |
1022 | // synthesized later. |
1023 | if (PL == PICLevel::SmallPIC && !IsAIX) { |
1024 | const MCExpr *Exp = |
1025 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_GOT, |
1026 | Ctx&: OutContext); |
1027 | TmpInst.getOperand(i: 1) = MCOperand::createExpr(Val: Exp); |
1028 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1029 | return; |
1030 | } |
1031 | |
1032 | MCSymbolRefExpr::VariantKind VK = GetVKForMO(MO); |
1033 | |
1034 | // Otherwise, use the TOC. 'TOCEntry' is a label used to reference the |
1035 | // storage allocated in the TOC which contains the address of |
1036 | // 'MOSymbol'. Said TOC entry will be synthesized later. |
1037 | MCSymbol *TOCEntry = |
1038 | lookUpOrCreateTOCEntry(Sym: MOSymbol, Type: getTOCEntryTypeForMO(MO), Kind: VK); |
1039 | const MCExpr *Exp = |
1040 | MCSymbolRefExpr::create(Symbol: TOCEntry, Kind: MCSymbolRefExpr::VK_None, Ctx&: OutContext); |
1041 | |
1042 | // AIX uses the label directly as the lwz displacement operand for |
1043 | // references into the toc section. The displacement value will be generated |
1044 | // relative to the toc-base. |
1045 | if (IsAIX) { |
1046 | assert( |
1047 | getCodeModel(*Subtarget, TM, MO) == CodeModel::Small && |
1048 | "This pseudo should only be selected for 32-bit small code model." ); |
1049 | Exp = getTOCEntryLoadingExprForXCOFF(MOSymbol, Exp, VK); |
1050 | TmpInst.getOperand(i: 1) = MCOperand::createExpr(Val: Exp); |
1051 | |
1052 | // Print MO for better readability |
1053 | if (isVerbose()) |
1054 | OutStreamer->getCommentOS() << MO << '\n'; |
1055 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1056 | return; |
1057 | } |
1058 | |
1059 | // Create an explicit subtract expression between the local symbol and |
1060 | // '.LTOC' to manifest the toc-relative offset. |
1061 | const MCExpr *PB = MCSymbolRefExpr::create( |
1062 | Symbol: OutContext.getOrCreateSymbol(Name: Twine(".LTOC" )), Ctx&: OutContext); |
1063 | Exp = MCBinaryExpr::createSub(LHS: Exp, RHS: PB, Ctx&: OutContext); |
1064 | TmpInst.getOperand(i: 1) = MCOperand::createExpr(Val: Exp); |
1065 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1066 | return; |
1067 | } |
1068 | case PPC::ADDItoc: |
1069 | case PPC::ADDItoc8: { |
1070 | assert(IsAIX && TM.getCodeModel() == CodeModel::Small && |
1071 | "PseudoOp only valid for small code model AIX" ); |
1072 | |
1073 | // Transform %rN = ADDItoc/8 @op1, %r2. |
1074 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1075 | |
1076 | // Change the opcode to load address. |
1077 | TmpInst.setOpcode((!IsPPC64) ? (PPC::LA) : (PPC::LA8)); |
1078 | |
1079 | const MachineOperand &MO = MI->getOperand(i: 1); |
1080 | assert(MO.isGlobal() && "Invalid operand for ADDItoc[8]." ); |
1081 | |
1082 | // Map the operand to its corresponding MCSymbol. |
1083 | const MCSymbol *const MOSymbol = getMCSymbolForTOCPseudoMO(MO, AP&: *this); |
1084 | |
1085 | const MCExpr *Exp = |
1086 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_None, Ctx&: OutContext); |
1087 | |
1088 | TmpInst.getOperand(i: 1) = TmpInst.getOperand(i: 2); |
1089 | TmpInst.getOperand(i: 2) = MCOperand::createExpr(Val: Exp); |
1090 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1091 | return; |
1092 | } |
1093 | case PPC::LDtocJTI: |
1094 | case PPC::LDtocCPT: |
1095 | case PPC::LDtocBA: |
1096 | case PPC::LDtoc: { |
1097 | // Transform %x3 = LDtoc @min1, %x2 |
1098 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1099 | |
1100 | // Change the opcode to LD. |
1101 | TmpInst.setOpcode(PPC::LD); |
1102 | |
1103 | const MachineOperand &MO = MI->getOperand(i: 1); |
1104 | assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && |
1105 | "Invalid operand!" ); |
1106 | |
1107 | // Map the operand to its corresponding MCSymbol. |
1108 | const MCSymbol *const MOSymbol = getMCSymbolForTOCPseudoMO(MO, AP&: *this); |
1109 | |
1110 | MCSymbolRefExpr::VariantKind VK = GetVKForMO(MO); |
1111 | |
1112 | // Map the machine operand to its corresponding MCSymbol, then map the |
1113 | // global address operand to be a reference to the TOC entry we will |
1114 | // synthesize later. |
1115 | MCSymbol *TOCEntry = |
1116 | lookUpOrCreateTOCEntry(Sym: MOSymbol, Type: getTOCEntryTypeForMO(MO), Kind: VK); |
1117 | |
1118 | MCSymbolRefExpr::VariantKind VKExpr = |
1119 | IsAIX ? MCSymbolRefExpr::VK_None : MCSymbolRefExpr::VK_PPC_TOC; |
1120 | const MCExpr *Exp = MCSymbolRefExpr::create(Symbol: TOCEntry, Kind: VKExpr, Ctx&: OutContext); |
1121 | TmpInst.getOperand(i: 1) = MCOperand::createExpr( |
1122 | Val: IsAIX ? getTOCEntryLoadingExprForXCOFF(MOSymbol, Exp, VK) : Exp); |
1123 | |
1124 | // Print MO for better readability |
1125 | if (isVerbose() && IsAIX) |
1126 | OutStreamer->getCommentOS() << MO << '\n'; |
1127 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1128 | return; |
1129 | } |
1130 | case PPC::ADDIStocHA: { |
1131 | const MachineOperand &MO = MI->getOperand(i: 2); |
1132 | |
1133 | assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && |
1134 | "Invalid operand for ADDIStocHA." ); |
1135 | assert((IsAIX && !IsPPC64 && |
1136 | getCodeModel(*Subtarget, TM, MO) == CodeModel::Large) && |
1137 | "This pseudo should only be selected for 32-bit large code model on" |
1138 | " AIX." ); |
1139 | |
1140 | // Transform %rd = ADDIStocHA %rA, @sym(%r2) |
1141 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1142 | |
1143 | // Change the opcode to ADDIS. |
1144 | TmpInst.setOpcode(PPC::ADDIS); |
1145 | |
1146 | // Map the machine operand to its corresponding MCSymbol. |
1147 | MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, AP&: *this); |
1148 | |
1149 | MCSymbolRefExpr::VariantKind VK = GetVKForMO(MO); |
1150 | |
1151 | // If the symbol isn't toc-data then use the TOC on AIX. |
1152 | // Map the global address operand to be a reference to the TOC entry we |
1153 | // will synthesize later. 'TOCEntry' is a label used to reference the |
1154 | // storage allocated in the TOC which contains the address of 'MOSymbol'. |
1155 | // If the toc-data attribute is used, the TOC entry contains the data |
1156 | // rather than the address of the MOSymbol. |
1157 | if (![](const MachineOperand &MO) { |
1158 | if (!MO.isGlobal()) |
1159 | return false; |
1160 | |
1161 | const GlobalVariable *GV = dyn_cast<GlobalVariable>(Val: MO.getGlobal()); |
1162 | if (!GV) |
1163 | return false; |
1164 | |
1165 | return GV->hasAttribute(Kind: "toc-data" ); |
1166 | }(MO)) { |
1167 | MOSymbol = lookUpOrCreateTOCEntry(Sym: MOSymbol, Type: getTOCEntryTypeForMO(MO), Kind: VK); |
1168 | } |
1169 | |
1170 | const MCExpr *Exp = MCSymbolRefExpr::create( |
1171 | Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_PPC_U, Ctx&: OutContext); |
1172 | TmpInst.getOperand(i: 2) = MCOperand::createExpr(Val: Exp); |
1173 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1174 | return; |
1175 | } |
1176 | case PPC::LWZtocL: { |
1177 | const MachineOperand &MO = MI->getOperand(i: 1); |
1178 | |
1179 | assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && |
1180 | "Invalid operand for LWZtocL." ); |
1181 | assert(IsAIX && !IsPPC64 && |
1182 | getCodeModel(*Subtarget, TM, MO) == CodeModel::Large && |
1183 | "This pseudo should only be selected for 32-bit large code model on" |
1184 | " AIX." ); |
1185 | |
1186 | // Transform %rd = LWZtocL @sym, %rs. |
1187 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1188 | |
1189 | // Change the opcode to lwz. |
1190 | TmpInst.setOpcode(PPC::LWZ); |
1191 | |
1192 | // Map the machine operand to its corresponding MCSymbol. |
1193 | MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, AP&: *this); |
1194 | |
1195 | MCSymbolRefExpr::VariantKind VK = GetVKForMO(MO); |
1196 | |
1197 | // Always use TOC on AIX. Map the global address operand to be a reference |
1198 | // to the TOC entry we will synthesize later. 'TOCEntry' is a label used to |
1199 | // reference the storage allocated in the TOC which contains the address of |
1200 | // 'MOSymbol'. |
1201 | MCSymbol *TOCEntry = |
1202 | lookUpOrCreateTOCEntry(Sym: MOSymbol, Type: getTOCEntryTypeForMO(MO), Kind: VK); |
1203 | const MCExpr *Exp = MCSymbolRefExpr::create(Symbol: TOCEntry, |
1204 | Kind: MCSymbolRefExpr::VK_PPC_L, |
1205 | Ctx&: OutContext); |
1206 | TmpInst.getOperand(i: 1) = MCOperand::createExpr(Val: Exp); |
1207 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1208 | return; |
1209 | } |
1210 | case PPC::ADDIStocHA8: { |
1211 | // Transform %xd = ADDIStocHA8 %x2, @sym |
1212 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1213 | |
1214 | // Change the opcode to ADDIS8. If the global address is the address of |
1215 | // an external symbol, is a jump table address, is a block address, or is a |
1216 | // constant pool index with large code model enabled, then generate a TOC |
1217 | // entry and reference that. Otherwise, reference the symbol directly. |
1218 | TmpInst.setOpcode(PPC::ADDIS8); |
1219 | |
1220 | const MachineOperand &MO = MI->getOperand(i: 2); |
1221 | assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && |
1222 | "Invalid operand for ADDIStocHA8!" ); |
1223 | |
1224 | const MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, AP&: *this); |
1225 | |
1226 | MCSymbolRefExpr::VariantKind VK = GetVKForMO(MO); |
1227 | |
1228 | const bool GlobalToc = |
1229 | MO.isGlobal() && Subtarget->isGVIndirectSymbol(GV: MO.getGlobal()); |
1230 | |
1231 | const CodeModel::Model CM = |
1232 | IsAIX ? getCodeModel(S: *Subtarget, TM, MO) : TM.getCodeModel(); |
1233 | |
1234 | if (GlobalToc || MO.isJTI() || MO.isBlockAddress() || |
1235 | (MO.isCPI() && CM == CodeModel::Large)) |
1236 | MOSymbol = lookUpOrCreateTOCEntry(Sym: MOSymbol, Type: getTOCEntryTypeForMO(MO), Kind: VK); |
1237 | |
1238 | VK = IsAIX ? MCSymbolRefExpr::VK_PPC_U : MCSymbolRefExpr::VK_PPC_TOC_HA; |
1239 | |
1240 | const MCExpr *Exp = |
1241 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: VK, Ctx&: OutContext); |
1242 | |
1243 | if (!MO.isJTI() && MO.getOffset()) |
1244 | Exp = MCBinaryExpr::createAdd(LHS: Exp, |
1245 | RHS: MCConstantExpr::create(Value: MO.getOffset(), |
1246 | Ctx&: OutContext), |
1247 | Ctx&: OutContext); |
1248 | |
1249 | TmpInst.getOperand(i: 2) = MCOperand::createExpr(Val: Exp); |
1250 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1251 | return; |
1252 | } |
1253 | case PPC::LDtocL: { |
1254 | // Transform %xd = LDtocL @sym, %xs |
1255 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1256 | |
1257 | // Change the opcode to LD. If the global address is the address of |
1258 | // an external symbol, is a jump table address, is a block address, or is |
1259 | // a constant pool index with large code model enabled, then generate a |
1260 | // TOC entry and reference that. Otherwise, reference the symbol directly. |
1261 | TmpInst.setOpcode(PPC::LD); |
1262 | |
1263 | const MachineOperand &MO = MI->getOperand(i: 1); |
1264 | assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || |
1265 | MO.isBlockAddress()) && |
1266 | "Invalid operand for LDtocL!" ); |
1267 | |
1268 | LLVM_DEBUG(assert( |
1269 | (!MO.isGlobal() || Subtarget->isGVIndirectSymbol(MO.getGlobal())) && |
1270 | "LDtocL used on symbol that could be accessed directly is " |
1271 | "invalid. Must match ADDIStocHA8." )); |
1272 | |
1273 | const MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, AP&: *this); |
1274 | |
1275 | MCSymbolRefExpr::VariantKind VK = GetVKForMO(MO); |
1276 | CodeModel::Model CM = |
1277 | IsAIX ? getCodeModel(S: *Subtarget, TM, MO) : TM.getCodeModel(); |
1278 | if (!MO.isCPI() || CM == CodeModel::Large) |
1279 | MOSymbol = lookUpOrCreateTOCEntry(Sym: MOSymbol, Type: getTOCEntryTypeForMO(MO), Kind: VK); |
1280 | |
1281 | VK = IsAIX ? MCSymbolRefExpr::VK_PPC_L : MCSymbolRefExpr::VK_PPC_TOC_LO; |
1282 | const MCExpr *Exp = |
1283 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: VK, Ctx&: OutContext); |
1284 | TmpInst.getOperand(i: 1) = MCOperand::createExpr(Val: Exp); |
1285 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1286 | return; |
1287 | } |
1288 | case PPC::ADDItocL: |
1289 | case PPC::ADDItocL8: { |
1290 | // Transform %xd = ADDItocL %xs, @sym |
1291 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1292 | |
1293 | unsigned Op = MI->getOpcode(); |
1294 | |
1295 | // Change the opcode to load address for tocdata |
1296 | TmpInst.setOpcode(Op == PPC::ADDItocL8 ? PPC::ADDI8 : PPC::LA); |
1297 | |
1298 | const MachineOperand &MO = MI->getOperand(i: 2); |
1299 | assert((Op == PPC::ADDItocL8) |
1300 | ? (MO.isGlobal() || MO.isCPI()) |
1301 | : MO.isGlobal() && "Invalid operand for ADDItocL8." ); |
1302 | assert(!(MO.isGlobal() && Subtarget->isGVIndirectSymbol(MO.getGlobal())) && |
1303 | "Interposable definitions must use indirect accesses." ); |
1304 | |
1305 | // Map the operand to its corresponding MCSymbol. |
1306 | const MCSymbol *const MOSymbol = getMCSymbolForTOCPseudoMO(MO, AP&: *this); |
1307 | |
1308 | const MCExpr *Exp = MCSymbolRefExpr::create( |
1309 | MOSymbol, |
1310 | Op == PPC::ADDItocL8 ? MCSymbolRefExpr::VK_PPC_TOC_LO |
1311 | : MCSymbolRefExpr::VK_PPC_L, |
1312 | OutContext); |
1313 | |
1314 | TmpInst.getOperand(i: 2) = MCOperand::createExpr(Val: Exp); |
1315 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1316 | return; |
1317 | } |
1318 | case PPC::ADDISgotTprelHA: { |
1319 | // Transform: %xd = ADDISgotTprelHA %x2, @sym |
1320 | // Into: %xd = ADDIS8 %x2, sym@got@tlsgd@ha |
1321 | assert(IsPPC64 && "Not supported for 32-bit PowerPC" ); |
1322 | const MachineOperand &MO = MI->getOperand(i: 2); |
1323 | const GlobalValue *GValue = MO.getGlobal(); |
1324 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1325 | const MCExpr *SymGotTprel = |
1326 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_PPC_GOT_TPREL_HA, |
1327 | Ctx&: OutContext); |
1328 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS8) |
1329 | .addReg(MI->getOperand(0).getReg()) |
1330 | .addReg(MI->getOperand(1).getReg()) |
1331 | .addExpr(SymGotTprel)); |
1332 | return; |
1333 | } |
1334 | case PPC::LDgotTprelL: |
1335 | case PPC::LDgotTprelL32: { |
1336 | // Transform %xd = LDgotTprelL @sym, %xs |
1337 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1338 | |
1339 | // Change the opcode to LD. |
1340 | TmpInst.setOpcode(IsPPC64 ? PPC::LD : PPC::LWZ); |
1341 | const MachineOperand &MO = MI->getOperand(i: 1); |
1342 | const GlobalValue *GValue = MO.getGlobal(); |
1343 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1344 | const MCExpr *Exp = MCSymbolRefExpr::create( |
1345 | Symbol: MOSymbol, Kind: IsPPC64 ? MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO |
1346 | : MCSymbolRefExpr::VK_PPC_GOT_TPREL, |
1347 | Ctx&: OutContext); |
1348 | TmpInst.getOperand(i: 1) = MCOperand::createExpr(Val: Exp); |
1349 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1350 | return; |
1351 | } |
1352 | |
1353 | case PPC::PPC32PICGOT: { |
1354 | MCSymbol *GOTSymbol = OutContext.getOrCreateSymbol(Name: StringRef("_GLOBAL_OFFSET_TABLE_" )); |
1355 | MCSymbol *GOTRef = OutContext.createTempSymbol(); |
1356 | MCSymbol *NextInstr = OutContext.createTempSymbol(); |
1357 | |
1358 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::BL) |
1359 | // FIXME: We would like an efficient form for this, so we don't have to do |
1360 | // a lot of extra uniquing. |
1361 | .addExpr(MCSymbolRefExpr::create(NextInstr, OutContext))); |
1362 | const MCExpr *OffsExpr = |
1363 | MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: GOTSymbol, Ctx&: OutContext), |
1364 | RHS: MCSymbolRefExpr::create(Symbol: GOTRef, Ctx&: OutContext), |
1365 | Ctx&: OutContext); |
1366 | OutStreamer->emitLabel(Symbol: GOTRef); |
1367 | OutStreamer->emitValue(Value: OffsExpr, Size: 4); |
1368 | OutStreamer->emitLabel(Symbol: NextInstr); |
1369 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MFLR) |
1370 | .addReg(MI->getOperand(0).getReg())); |
1371 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LWZ) |
1372 | .addReg(MI->getOperand(1).getReg()) |
1373 | .addImm(0) |
1374 | .addReg(MI->getOperand(0).getReg())); |
1375 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADD4) |
1376 | .addReg(MI->getOperand(0).getReg()) |
1377 | .addReg(MI->getOperand(1).getReg()) |
1378 | .addReg(MI->getOperand(0).getReg())); |
1379 | return; |
1380 | } |
1381 | case PPC::PPC32GOT: { |
1382 | MCSymbol *GOTSymbol = |
1383 | OutContext.getOrCreateSymbol(Name: StringRef("_GLOBAL_OFFSET_TABLE_" )); |
1384 | const MCExpr *SymGotTlsL = MCSymbolRefExpr::create( |
1385 | Symbol: GOTSymbol, Kind: MCSymbolRefExpr::VK_PPC_LO, Ctx&: OutContext); |
1386 | const MCExpr *SymGotTlsHA = MCSymbolRefExpr::create( |
1387 | Symbol: GOTSymbol, Kind: MCSymbolRefExpr::VK_PPC_HA, Ctx&: OutContext); |
1388 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LI) |
1389 | .addReg(MI->getOperand(0).getReg()) |
1390 | .addExpr(SymGotTlsL)); |
1391 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS) |
1392 | .addReg(MI->getOperand(0).getReg()) |
1393 | .addReg(MI->getOperand(0).getReg()) |
1394 | .addExpr(SymGotTlsHA)); |
1395 | return; |
1396 | } |
1397 | case PPC::ADDIStlsgdHA: { |
1398 | // Transform: %xd = ADDIStlsgdHA %x2, @sym |
1399 | // Into: %xd = ADDIS8 %x2, sym@got@tlsgd@ha |
1400 | assert(IsPPC64 && "Not supported for 32-bit PowerPC" ); |
1401 | const MachineOperand &MO = MI->getOperand(i: 2); |
1402 | const GlobalValue *GValue = MO.getGlobal(); |
1403 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1404 | const MCExpr *SymGotTlsGD = |
1405 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HA, |
1406 | Ctx&: OutContext); |
1407 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS8) |
1408 | .addReg(MI->getOperand(0).getReg()) |
1409 | .addReg(MI->getOperand(1).getReg()) |
1410 | .addExpr(SymGotTlsGD)); |
1411 | return; |
1412 | } |
1413 | case PPC::ADDItlsgdL: |
1414 | // Transform: %xd = ADDItlsgdL %xs, @sym |
1415 | // Into: %xd = ADDI8 %xs, sym@got@tlsgd@l |
1416 | case PPC::ADDItlsgdL32: { |
1417 | // Transform: %rd = ADDItlsgdL32 %rs, @sym |
1418 | // Into: %rd = ADDI %rs, sym@got@tlsgd |
1419 | const MachineOperand &MO = MI->getOperand(i: 2); |
1420 | const GlobalValue *GValue = MO.getGlobal(); |
1421 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1422 | const MCExpr *SymGotTlsGD = MCSymbolRefExpr::create( |
1423 | Symbol: MOSymbol, Kind: IsPPC64 ? MCSymbolRefExpr::VK_PPC_GOT_TLSGD_LO |
1424 | : MCSymbolRefExpr::VK_PPC_GOT_TLSGD, |
1425 | Ctx&: OutContext); |
1426 | EmitToStreamer(*OutStreamer, |
1427 | MCInstBuilder(IsPPC64 ? PPC::ADDI8 : PPC::ADDI) |
1428 | .addReg(MI->getOperand(0).getReg()) |
1429 | .addReg(MI->getOperand(1).getReg()) |
1430 | .addExpr(SymGotTlsGD)); |
1431 | return; |
1432 | } |
1433 | case PPC::GETtlsMOD32AIX: |
1434 | case PPC::GETtlsMOD64AIX: |
1435 | // Transform: %r3 = GETtlsMODNNAIX %r3 (for NN == 32/64). |
1436 | // Into: BLA .__tls_get_mod() |
1437 | // Input parameter is a module handle (_$TLSML[TC]@ml) for all variables. |
1438 | case PPC::GETtlsADDR: |
1439 | // Transform: %x3 = GETtlsADDR %x3, @sym |
1440 | // Into: BL8_NOP_TLS __tls_get_addr(sym at tlsgd) |
1441 | case PPC::GETtlsADDRPCREL: |
1442 | case PPC::GETtlsADDR32AIX: |
1443 | case PPC::GETtlsADDR64AIX: |
1444 | // Transform: %r3 = GETtlsADDRNNAIX %r3, %r4 (for NN == 32/64). |
1445 | // Into: BLA .__tls_get_addr() |
1446 | // Unlike on Linux, there is no symbol or relocation needed for this call. |
1447 | case PPC::GETtlsADDR32: { |
1448 | // Transform: %r3 = GETtlsADDR32 %r3, @sym |
1449 | // Into: BL_TLS __tls_get_addr(sym at tlsgd)@PLT |
1450 | EmitTlsCall(MI, VK: MCSymbolRefExpr::VK_PPC_TLSGD); |
1451 | return; |
1452 | } |
1453 | case PPC::GETtlsTpointer32AIX: { |
1454 | // Transform: %r3 = GETtlsTpointer32AIX |
1455 | // Into: BLA .__get_tpointer() |
1456 | EmitAIXTlsCallHelper(MI); |
1457 | return; |
1458 | } |
1459 | case PPC::ADDIStlsldHA: { |
1460 | // Transform: %xd = ADDIStlsldHA %x2, @sym |
1461 | // Into: %xd = ADDIS8 %x2, sym@got@tlsld@ha |
1462 | assert(IsPPC64 && "Not supported for 32-bit PowerPC" ); |
1463 | const MachineOperand &MO = MI->getOperand(i: 2); |
1464 | const GlobalValue *GValue = MO.getGlobal(); |
1465 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1466 | const MCExpr *SymGotTlsLD = |
1467 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HA, |
1468 | Ctx&: OutContext); |
1469 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS8) |
1470 | .addReg(MI->getOperand(0).getReg()) |
1471 | .addReg(MI->getOperand(1).getReg()) |
1472 | .addExpr(SymGotTlsLD)); |
1473 | return; |
1474 | } |
1475 | case PPC::ADDItlsldL: |
1476 | // Transform: %xd = ADDItlsldL %xs, @sym |
1477 | // Into: %xd = ADDI8 %xs, sym@got@tlsld@l |
1478 | case PPC::ADDItlsldL32: { |
1479 | // Transform: %rd = ADDItlsldL32 %rs, @sym |
1480 | // Into: %rd = ADDI %rs, sym@got@tlsld |
1481 | const MachineOperand &MO = MI->getOperand(i: 2); |
1482 | const GlobalValue *GValue = MO.getGlobal(); |
1483 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1484 | const MCExpr *SymGotTlsLD = MCSymbolRefExpr::create( |
1485 | Symbol: MOSymbol, Kind: IsPPC64 ? MCSymbolRefExpr::VK_PPC_GOT_TLSLD_LO |
1486 | : MCSymbolRefExpr::VK_PPC_GOT_TLSLD, |
1487 | Ctx&: OutContext); |
1488 | EmitToStreamer(*OutStreamer, |
1489 | MCInstBuilder(IsPPC64 ? PPC::ADDI8 : PPC::ADDI) |
1490 | .addReg(MI->getOperand(0).getReg()) |
1491 | .addReg(MI->getOperand(1).getReg()) |
1492 | .addExpr(SymGotTlsLD)); |
1493 | return; |
1494 | } |
1495 | case PPC::GETtlsldADDR: |
1496 | // Transform: %x3 = GETtlsldADDR %x3, @sym |
1497 | // Into: BL8_NOP_TLS __tls_get_addr(sym at tlsld) |
1498 | case PPC::GETtlsldADDRPCREL: |
1499 | case PPC::GETtlsldADDR32: { |
1500 | // Transform: %r3 = GETtlsldADDR32 %r3, @sym |
1501 | // Into: BL_TLS __tls_get_addr(sym at tlsld)@PLT |
1502 | EmitTlsCall(MI, VK: MCSymbolRefExpr::VK_PPC_TLSLD); |
1503 | return; |
1504 | } |
1505 | case PPC::ADDISdtprelHA: |
1506 | // Transform: %xd = ADDISdtprelHA %xs, @sym |
1507 | // Into: %xd = ADDIS8 %xs, sym@dtprel@ha |
1508 | case PPC::ADDISdtprelHA32: { |
1509 | // Transform: %rd = ADDISdtprelHA32 %rs, @sym |
1510 | // Into: %rd = ADDIS %rs, sym@dtprel@ha |
1511 | const MachineOperand &MO = MI->getOperand(i: 2); |
1512 | const GlobalValue *GValue = MO.getGlobal(); |
1513 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1514 | const MCExpr *SymDtprel = |
1515 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_PPC_DTPREL_HA, |
1516 | Ctx&: OutContext); |
1517 | EmitToStreamer( |
1518 | *OutStreamer, |
1519 | MCInstBuilder(IsPPC64 ? PPC::ADDIS8 : PPC::ADDIS) |
1520 | .addReg(MI->getOperand(0).getReg()) |
1521 | .addReg(MI->getOperand(1).getReg()) |
1522 | .addExpr(SymDtprel)); |
1523 | return; |
1524 | } |
1525 | case PPC::PADDIdtprel: { |
1526 | // Transform: %rd = PADDIdtprel %rs, @sym |
1527 | // Into: %rd = PADDI8 %rs, sym@dtprel |
1528 | const MachineOperand &MO = MI->getOperand(i: 2); |
1529 | const GlobalValue *GValue = MO.getGlobal(); |
1530 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1531 | const MCExpr *SymDtprel = MCSymbolRefExpr::create( |
1532 | Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_DTPREL, Ctx&: OutContext); |
1533 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::PADDI8) |
1534 | .addReg(MI->getOperand(0).getReg()) |
1535 | .addReg(MI->getOperand(1).getReg()) |
1536 | .addExpr(SymDtprel)); |
1537 | return; |
1538 | } |
1539 | |
1540 | case PPC::ADDIdtprelL: |
1541 | // Transform: %xd = ADDIdtprelL %xs, @sym |
1542 | // Into: %xd = ADDI8 %xs, sym@dtprel@l |
1543 | case PPC::ADDIdtprelL32: { |
1544 | // Transform: %rd = ADDIdtprelL32 %rs, @sym |
1545 | // Into: %rd = ADDI %rs, sym@dtprel@l |
1546 | const MachineOperand &MO = MI->getOperand(i: 2); |
1547 | const GlobalValue *GValue = MO.getGlobal(); |
1548 | MCSymbol *MOSymbol = getSymbol(GV: GValue); |
1549 | const MCExpr *SymDtprel = |
1550 | MCSymbolRefExpr::create(Symbol: MOSymbol, Kind: MCSymbolRefExpr::VK_PPC_DTPREL_LO, |
1551 | Ctx&: OutContext); |
1552 | EmitToStreamer(*OutStreamer, |
1553 | MCInstBuilder(IsPPC64 ? PPC::ADDI8 : PPC::ADDI) |
1554 | .addReg(MI->getOperand(0).getReg()) |
1555 | .addReg(MI->getOperand(1).getReg()) |
1556 | .addExpr(SymDtprel)); |
1557 | return; |
1558 | } |
1559 | case PPC::MFOCRF: |
1560 | case PPC::MFOCRF8: |
1561 | if (!Subtarget->hasMFOCRF()) { |
1562 | // Transform: %r3 = MFOCRF %cr7 |
1563 | // Into: %r3 = MFCR ;; cr7 |
1564 | unsigned NewOpcode = |
1565 | MI->getOpcode() == PPC::MFOCRF ? PPC::MFCR : PPC::MFCR8; |
1566 | OutStreamer->AddComment(T: PPCInstPrinter:: |
1567 | getRegisterName(Reg: MI->getOperand(i: 1).getReg())); |
1568 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(NewOpcode) |
1569 | .addReg(Reg: MI->getOperand(i: 0).getReg())); |
1570 | return; |
1571 | } |
1572 | break; |
1573 | case PPC::MTOCRF: |
1574 | case PPC::MTOCRF8: |
1575 | if (!Subtarget->hasMFOCRF()) { |
1576 | // Transform: %cr7 = MTOCRF %r3 |
1577 | // Into: MTCRF mask, %r3 ;; cr7 |
1578 | unsigned NewOpcode = |
1579 | MI->getOpcode() == PPC::MTOCRF ? PPC::MTCRF : PPC::MTCRF8; |
1580 | unsigned Mask = 0x80 >> OutContext.getRegisterInfo() |
1581 | ->getEncodingValue(RegNo: MI->getOperand(i: 0).getReg()); |
1582 | OutStreamer->AddComment(T: PPCInstPrinter:: |
1583 | getRegisterName(Reg: MI->getOperand(i: 0).getReg())); |
1584 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(NewOpcode) |
1585 | .addImm(Val: Mask) |
1586 | .addReg(Reg: MI->getOperand(i: 1).getReg())); |
1587 | return; |
1588 | } |
1589 | break; |
1590 | case PPC::LD: |
1591 | case PPC::STD: |
1592 | case PPC::LWA_32: |
1593 | case PPC::LWA: { |
1594 | // Verify alignment is legal, so we don't create relocations |
1595 | // that can't be supported. |
1596 | unsigned OpNum = (MI->getOpcode() == PPC::STD) ? 2 : 1; |
1597 | // For non-TOC-based local-exec TLS accesses with non-zero offsets, the |
1598 | // machine operand (which is a TargetGlobalTLSAddress) is expected to be |
1599 | // the same operand for both loads and stores. |
1600 | for (const MachineOperand &TempMO : MI->operands()) { |
1601 | if (((TempMO.getTargetFlags() == PPCII::MO_TPREL_FLAG)) && |
1602 | TempMO.getOperandNo() == 1) |
1603 | OpNum = 1; |
1604 | } |
1605 | const MachineOperand &MO = MI->getOperand(i: OpNum); |
1606 | if (MO.isGlobal()) { |
1607 | const DataLayout &DL = MO.getGlobal()->getParent()->getDataLayout(); |
1608 | if (MO.getGlobal()->getPointerAlignment(DL) < 4) |
1609 | llvm_unreachable("Global must be word-aligned for LD, STD, LWA!" ); |
1610 | } |
1611 | // As these load/stores share common code with the following load/stores, |
1612 | // fall through to the subsequent cases in order to either process the |
1613 | // non-TOC-based local-exec sequence or to process the instruction normally. |
1614 | [[fallthrough]]; |
1615 | } |
1616 | case PPC::LBZ: |
1617 | case PPC::LBZ8: |
1618 | case PPC::LHA: |
1619 | case PPC::LHA8: |
1620 | case PPC::LHZ: |
1621 | case PPC::LHZ8: |
1622 | case PPC::LWZ: |
1623 | case PPC::LWZ8: |
1624 | case PPC::STB: |
1625 | case PPC::STB8: |
1626 | case PPC::STH: |
1627 | case PPC::STH8: |
1628 | case PPC::STW: |
1629 | case PPC::STW8: |
1630 | case PPC::LFS: |
1631 | case PPC::STFS: |
1632 | case PPC::LFD: |
1633 | case PPC::STFD: |
1634 | case PPC::ADDI8: { |
1635 | // A faster non-TOC-based local-[exec|dynamic] sequence is represented by |
1636 | // `addi` or a load/store instruction (that directly loads or stores off of |
1637 | // the thread pointer) with an immediate operand having the MO_TPREL_FLAG. |
1638 | // Such instructions do not otherwise arise. |
1639 | if (!HasAIXSmallLocalTLS) |
1640 | break; |
1641 | bool IsMIADDI8 = MI->getOpcode() == PPC::ADDI8; |
1642 | unsigned OpNum = IsMIADDI8 ? 2 : 1; |
1643 | const MachineOperand &MO = MI->getOperand(i: OpNum); |
1644 | unsigned Flag = MO.getTargetFlags(); |
1645 | if (Flag == PPCII::MO_TPREL_FLAG || |
1646 | Flag == PPCII::MO_GOT_TPREL_PCREL_FLAG || |
1647 | Flag == PPCII::MO_TPREL_PCREL_FLAG || Flag == PPCII::MO_TLSLD_FLAG) { |
1648 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1649 | |
1650 | const MCExpr *Expr = getAdjustedLocalExecExpr(MO, Offset: MO.getOffset()); |
1651 | if (Expr) |
1652 | TmpInst.getOperand(i: OpNum) = MCOperand::createExpr(Val: Expr); |
1653 | |
1654 | // Change the opcode to load address if the original opcode is an `addi`. |
1655 | if (IsMIADDI8) |
1656 | TmpInst.setOpcode(PPC::LA8); |
1657 | |
1658 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1659 | return; |
1660 | } |
1661 | // Now process the instruction normally. |
1662 | break; |
1663 | } |
1664 | case PPC::PseudoEIEIO: { |
1665 | EmitToStreamer( |
1666 | *OutStreamer, |
1667 | MCInstBuilder(PPC::ORI).addReg(PPC::X2).addReg(PPC::X2).addImm(0)); |
1668 | EmitToStreamer( |
1669 | *OutStreamer, |
1670 | MCInstBuilder(PPC::ORI).addReg(PPC::X2).addReg(PPC::X2).addImm(0)); |
1671 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::EnforceIEIO)); |
1672 | return; |
1673 | } |
1674 | } |
1675 | |
1676 | LowerPPCMachineInstrToMCInst(MI, OutMI&: TmpInst, AP&: *this); |
1677 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
1678 | } |
1679 | |
1680 | // For non-TOC-based local-exec variables that have a non-zero offset, |
1681 | // we need to create a new MCExpr that adds the non-zero offset to the address |
1682 | // of the local-exec variable that will be used in either an addi, load or |
1683 | // store. However, the final displacement for these instructions must be |
1684 | // between [-32768, 32768), so if the TLS address + its non-zero offset is |
1685 | // greater than 32KB, a new MCExpr is produced to accommodate this situation. |
1686 | const MCExpr *PPCAsmPrinter::getAdjustedLocalExecExpr(const MachineOperand &MO, |
1687 | int64_t Offset) { |
1688 | // Non-zero offsets (for loads, stores or `addi`) require additional handling. |
1689 | // When the offset is zero, there is no need to create an adjusted MCExpr. |
1690 | if (!Offset) |
1691 | return nullptr; |
1692 | |
1693 | assert(MO.isGlobal() && "Only expecting a global MachineOperand here!" ); |
1694 | const GlobalValue *GValue = MO.getGlobal(); |
1695 | // TODO: Handle the aix-small-local-dynamic-tls non-zero offset case. |
1696 | TLSModel::Model Model = TM.getTLSModel(GV: GValue); |
1697 | if (Model == TLSModel::LocalDynamic) { |
1698 | return nullptr; |
1699 | } |
1700 | assert(Model == TLSModel::LocalExec && |
1701 | "Only local-exec accesses are handled!" ); |
1702 | |
1703 | bool IsGlobalADeclaration = GValue->isDeclarationForLinker(); |
1704 | // Find the GlobalVariable that corresponds to the particular TLS variable |
1705 | // in the TLS variable-to-address mapping. All TLS variables should exist |
1706 | // within this map, with the exception of TLS variables marked as extern. |
1707 | const auto TLSVarsMapEntryIter = TLSVarsToAddressMapping.find(Key: GValue); |
1708 | if (TLSVarsMapEntryIter == TLSVarsToAddressMapping.end()) |
1709 | assert(IsGlobalADeclaration && |
1710 | "Only expecting to find extern TLS variables not present in the TLS " |
1711 | "variable-to-address map!" ); |
1712 | |
1713 | unsigned TLSVarAddress = |
1714 | IsGlobalADeclaration ? 0 : TLSVarsMapEntryIter->second; |
1715 | ptrdiff_t FinalAddress = (TLSVarAddress + Offset); |
1716 | // If the address of the TLS variable + the offset is less than 32KB, |
1717 | // or if the TLS variable is extern, we simply produce an MCExpr to add the |
1718 | // non-zero offset to the TLS variable address. |
1719 | // For when TLS variables are extern, this is safe to do because we can |
1720 | // assume that the address of extern TLS variables are zero. |
1721 | const MCExpr *Expr = MCSymbolRefExpr::create( |
1722 | Symbol: getSymbol(GV: GValue), Kind: MCSymbolRefExpr::VK_PPC_AIX_TLSLE, Ctx&: OutContext); |
1723 | Expr = MCBinaryExpr::createAdd( |
1724 | LHS: Expr, RHS: MCConstantExpr::create(Value: Offset, Ctx&: OutContext), Ctx&: OutContext); |
1725 | if (FinalAddress >= 32768) { |
1726 | // Handle the written offset for cases where: |
1727 | // TLS variable address + Offset > 32KB. |
1728 | |
1729 | // The assembly that is printed will look like: |
1730 | // TLSVar@le + Offset - Delta |
1731 | // where Delta is a multiple of 64KB: ((FinalAddress + 32768) & ~0xFFFF). |
1732 | ptrdiff_t Delta = ((FinalAddress + 32768) & ~0xFFFF); |
1733 | // Check that the total instruction displacement fits within [-32768,32768). |
1734 | [[maybe_unused]] ptrdiff_t InstDisp = TLSVarAddress + Offset - Delta; |
1735 | assert(((InstDisp < 32768) && |
1736 | (InstDisp >= -32768)) && |
1737 | "Expecting the instruction displacement for local-exec TLS " |
1738 | "variables to be between [-32768, 32768)!" ); |
1739 | Expr = MCBinaryExpr::createAdd( |
1740 | LHS: Expr, RHS: MCConstantExpr::create(Value: -Delta, Ctx&: OutContext), Ctx&: OutContext); |
1741 | } |
1742 | |
1743 | return Expr; |
1744 | } |
1745 | |
1746 | void PPCLinuxAsmPrinter::emitGNUAttributes(Module &M) { |
1747 | // Emit float ABI into GNU attribute |
1748 | Metadata *MD = M.getModuleFlag(Key: "float-abi" ); |
1749 | MDString *FloatABI = dyn_cast_or_null<MDString>(Val: MD); |
1750 | if (!FloatABI) |
1751 | return; |
1752 | StringRef flt = FloatABI->getString(); |
1753 | // TODO: Support emitting soft-fp and hard double/single attributes. |
1754 | if (flt == "doubledouble" ) |
1755 | OutStreamer->emitGNUAttribute(Tag: Tag_GNU_Power_ABI_FP, |
1756 | Value: Val_GNU_Power_ABI_HardFloat_DP | |
1757 | Val_GNU_Power_ABI_LDBL_IBM128); |
1758 | else if (flt == "ieeequad" ) |
1759 | OutStreamer->emitGNUAttribute(Tag: Tag_GNU_Power_ABI_FP, |
1760 | Value: Val_GNU_Power_ABI_HardFloat_DP | |
1761 | Val_GNU_Power_ABI_LDBL_IEEE128); |
1762 | else if (flt == "ieeedouble" ) |
1763 | OutStreamer->emitGNUAttribute(Tag: Tag_GNU_Power_ABI_FP, |
1764 | Value: Val_GNU_Power_ABI_HardFloat_DP | |
1765 | Val_GNU_Power_ABI_LDBL_64); |
1766 | } |
1767 | |
1768 | void PPCLinuxAsmPrinter::emitInstruction(const MachineInstr *MI) { |
1769 | if (!Subtarget->isPPC64()) |
1770 | return PPCAsmPrinter::emitInstruction(MI); |
1771 | |
1772 | switch (MI->getOpcode()) { |
1773 | default: |
1774 | return PPCAsmPrinter::emitInstruction(MI); |
1775 | case TargetOpcode::PATCHABLE_FUNCTION_ENTER: { |
1776 | // .begin: |
1777 | // b .end # lis 0, FuncId[16..32] |
1778 | // nop # li 0, FuncId[0..15] |
1779 | // std 0, -8(1) |
1780 | // mflr 0 |
1781 | // bl __xray_FunctionEntry |
1782 | // mtlr 0 |
1783 | // .end: |
1784 | // |
1785 | // Update compiler-rt/lib/xray/xray_powerpc64.cc accordingly when number |
1786 | // of instructions change. |
1787 | MCSymbol *BeginOfSled = OutContext.createTempSymbol(); |
1788 | MCSymbol *EndOfSled = OutContext.createTempSymbol(); |
1789 | OutStreamer->emitLabel(Symbol: BeginOfSled); |
1790 | EmitToStreamer(*OutStreamer, |
1791 | MCInstBuilder(PPC::B).addExpr( |
1792 | MCSymbolRefExpr::create(EndOfSled, OutContext))); |
1793 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::NOP)); |
1794 | EmitToStreamer( |
1795 | *OutStreamer, |
1796 | MCInstBuilder(PPC::STD).addReg(PPC::X0).addImm(-8).addReg(PPC::X1)); |
1797 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MFLR8).addReg(PPC::X0)); |
1798 | EmitToStreamer(*OutStreamer, |
1799 | MCInstBuilder(PPC::BL8_NOP) |
1800 | .addExpr(MCSymbolRefExpr::create( |
1801 | OutContext.getOrCreateSymbol("__xray_FunctionEntry" ), |
1802 | OutContext))); |
1803 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MTLR8).addReg(PPC::X0)); |
1804 | OutStreamer->emitLabel(Symbol: EndOfSled); |
1805 | recordSled(Sled: BeginOfSled, MI: *MI, Kind: SledKind::FUNCTION_ENTER, Version: 2); |
1806 | break; |
1807 | } |
1808 | case TargetOpcode::PATCHABLE_RET: { |
1809 | unsigned RetOpcode = MI->getOperand(i: 0).getImm(); |
1810 | MCInst RetInst; |
1811 | RetInst.setOpcode(RetOpcode); |
1812 | for (const auto &MO : llvm::drop_begin(RangeOrContainer: MI->operands())) { |
1813 | MCOperand MCOp; |
1814 | if (LowerPPCMachineOperandToMCOperand(MO, OutMO&: MCOp, AP&: *this)) |
1815 | RetInst.addOperand(Op: MCOp); |
1816 | } |
1817 | |
1818 | bool IsConditional; |
1819 | if (RetOpcode == PPC::BCCLR) { |
1820 | IsConditional = true; |
1821 | } else if (RetOpcode == PPC::TCRETURNdi8 || RetOpcode == PPC::TCRETURNri8 || |
1822 | RetOpcode == PPC::TCRETURNai8) { |
1823 | break; |
1824 | } else if (RetOpcode == PPC::BLR8 || RetOpcode == PPC::TAILB8) { |
1825 | IsConditional = false; |
1826 | } else { |
1827 | EmitToStreamer(S&: *OutStreamer, Inst: RetInst); |
1828 | break; |
1829 | } |
1830 | |
1831 | MCSymbol *FallthroughLabel; |
1832 | if (IsConditional) { |
1833 | // Before: |
1834 | // bgtlr cr0 |
1835 | // |
1836 | // After: |
1837 | // ble cr0, .end |
1838 | // .p2align 3 |
1839 | // .begin: |
1840 | // blr # lis 0, FuncId[16..32] |
1841 | // nop # li 0, FuncId[0..15] |
1842 | // std 0, -8(1) |
1843 | // mflr 0 |
1844 | // bl __xray_FunctionExit |
1845 | // mtlr 0 |
1846 | // blr |
1847 | // .end: |
1848 | // |
1849 | // Update compiler-rt/lib/xray/xray_powerpc64.cc accordingly when number |
1850 | // of instructions change. |
1851 | FallthroughLabel = OutContext.createTempSymbol(); |
1852 | EmitToStreamer( |
1853 | *OutStreamer, |
1854 | MCInstBuilder(PPC::BCC) |
1855 | .addImm(PPC::InvertPredicate( |
1856 | static_cast<PPC::Predicate>(MI->getOperand(1).getImm()))) |
1857 | .addReg(MI->getOperand(2).getReg()) |
1858 | .addExpr(MCSymbolRefExpr::create(FallthroughLabel, OutContext))); |
1859 | RetInst = MCInst(); |
1860 | RetInst.setOpcode(PPC::BLR8); |
1861 | } |
1862 | // .p2align 3 |
1863 | // .begin: |
1864 | // b(lr)? # lis 0, FuncId[16..32] |
1865 | // nop # li 0, FuncId[0..15] |
1866 | // std 0, -8(1) |
1867 | // mflr 0 |
1868 | // bl __xray_FunctionExit |
1869 | // mtlr 0 |
1870 | // b(lr)? |
1871 | // |
1872 | // Update compiler-rt/lib/xray/xray_powerpc64.cc accordingly when number |
1873 | // of instructions change. |
1874 | OutStreamer->emitCodeAlignment(Alignment: Align(8), STI: &getSubtargetInfo()); |
1875 | MCSymbol *BeginOfSled = OutContext.createTempSymbol(); |
1876 | OutStreamer->emitLabel(Symbol: BeginOfSled); |
1877 | EmitToStreamer(S&: *OutStreamer, Inst: RetInst); |
1878 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::NOP)); |
1879 | EmitToStreamer( |
1880 | *OutStreamer, |
1881 | MCInstBuilder(PPC::STD).addReg(PPC::X0).addImm(-8).addReg(PPC::X1)); |
1882 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MFLR8).addReg(PPC::X0)); |
1883 | EmitToStreamer(*OutStreamer, |
1884 | MCInstBuilder(PPC::BL8_NOP) |
1885 | .addExpr(MCSymbolRefExpr::create( |
1886 | OutContext.getOrCreateSymbol("__xray_FunctionExit" ), |
1887 | OutContext))); |
1888 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MTLR8).addReg(PPC::X0)); |
1889 | EmitToStreamer(S&: *OutStreamer, Inst: RetInst); |
1890 | if (IsConditional) |
1891 | OutStreamer->emitLabel(Symbol: FallthroughLabel); |
1892 | recordSled(Sled: BeginOfSled, MI: *MI, Kind: SledKind::FUNCTION_EXIT, Version: 2); |
1893 | break; |
1894 | } |
1895 | case TargetOpcode::PATCHABLE_FUNCTION_EXIT: |
1896 | llvm_unreachable("PATCHABLE_FUNCTION_EXIT should never be emitted" ); |
1897 | case TargetOpcode::PATCHABLE_TAIL_CALL: |
1898 | // TODO: Define a trampoline `__xray_FunctionTailExit` and differentiate a |
1899 | // normal function exit from a tail exit. |
1900 | llvm_unreachable("Tail call is handled in the normal case. See comments " |
1901 | "around this assert." ); |
1902 | } |
1903 | } |
1904 | |
1905 | void PPCLinuxAsmPrinter::emitStartOfAsmFile(Module &M) { |
1906 | if (static_cast<const PPCTargetMachine &>(TM).isELFv2ABI()) { |
1907 | PPCTargetStreamer *TS = |
1908 | static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer()); |
1909 | TS->emitAbiVersion(AbiVersion: 2); |
1910 | } |
1911 | |
1912 | if (static_cast<const PPCTargetMachine &>(TM).isPPC64() || |
1913 | !isPositionIndependent()) |
1914 | return AsmPrinter::emitStartOfAsmFile(M); |
1915 | |
1916 | if (M.getPICLevel() == PICLevel::SmallPIC) |
1917 | return AsmPrinter::emitStartOfAsmFile(M); |
1918 | |
1919 | OutStreamer->switchSection(Section: OutContext.getELFSection( |
1920 | Section: ".got2" , Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_WRITE | ELF::SHF_ALLOC)); |
1921 | |
1922 | MCSymbol *TOCSym = OutContext.getOrCreateSymbol(Name: Twine(".LTOC" )); |
1923 | MCSymbol *CurrentPos = OutContext.createTempSymbol(); |
1924 | |
1925 | OutStreamer->emitLabel(Symbol: CurrentPos); |
1926 | |
1927 | // The GOT pointer points to the middle of the GOT, in order to reference the |
1928 | // entire 64kB range. 0x8000 is the midpoint. |
1929 | const MCExpr *tocExpr = |
1930 | MCBinaryExpr::createAdd(LHS: MCSymbolRefExpr::create(Symbol: CurrentPos, Ctx&: OutContext), |
1931 | RHS: MCConstantExpr::create(Value: 0x8000, Ctx&: OutContext), |
1932 | Ctx&: OutContext); |
1933 | |
1934 | OutStreamer->emitAssignment(Symbol: TOCSym, Value: tocExpr); |
1935 | |
1936 | OutStreamer->switchSection(Section: getObjFileLowering().getTextSection()); |
1937 | } |
1938 | |
1939 | void PPCLinuxAsmPrinter::emitFunctionEntryLabel() { |
1940 | // linux/ppc32 - Normal entry label. |
1941 | if (!Subtarget->isPPC64() && |
1942 | (!isPositionIndependent() || |
1943 | MF->getFunction().getParent()->getPICLevel() == PICLevel::SmallPIC)) |
1944 | return AsmPrinter::emitFunctionEntryLabel(); |
1945 | |
1946 | if (!Subtarget->isPPC64()) { |
1947 | const PPCFunctionInfo *PPCFI = MF->getInfo<PPCFunctionInfo>(); |
1948 | if (PPCFI->usesPICBase() && !Subtarget->isSecurePlt()) { |
1949 | MCSymbol *RelocSymbol = PPCFI->getPICOffsetSymbol(MF&: *MF); |
1950 | MCSymbol *PICBase = MF->getPICBaseSymbol(); |
1951 | OutStreamer->emitLabel(Symbol: RelocSymbol); |
1952 | |
1953 | const MCExpr *OffsExpr = |
1954 | MCBinaryExpr::createSub( |
1955 | LHS: MCSymbolRefExpr::create(Symbol: OutContext.getOrCreateSymbol(Name: Twine(".LTOC" )), |
1956 | Ctx&: OutContext), |
1957 | RHS: MCSymbolRefExpr::create(Symbol: PICBase, Ctx&: OutContext), |
1958 | Ctx&: OutContext); |
1959 | OutStreamer->emitValue(Value: OffsExpr, Size: 4); |
1960 | OutStreamer->emitLabel(Symbol: CurrentFnSym); |
1961 | return; |
1962 | } else |
1963 | return AsmPrinter::emitFunctionEntryLabel(); |
1964 | } |
1965 | |
1966 | // ELFv2 ABI - Normal entry label. |
1967 | if (Subtarget->isELFv2ABI()) { |
1968 | // In the Large code model, we allow arbitrary displacements between |
1969 | // the text section and its associated TOC section. We place the |
1970 | // full 8-byte offset to the TOC in memory immediately preceding |
1971 | // the function global entry point. |
1972 | if (TM.getCodeModel() == CodeModel::Large |
1973 | && !MF->getRegInfo().use_empty(PPC::X2)) { |
1974 | const PPCFunctionInfo *PPCFI = MF->getInfo<PPCFunctionInfo>(); |
1975 | |
1976 | MCSymbol *TOCSymbol = OutContext.getOrCreateSymbol(Name: StringRef(".TOC." )); |
1977 | MCSymbol *GlobalEPSymbol = PPCFI->getGlobalEPSymbol(MF&: *MF); |
1978 | const MCExpr *TOCDeltaExpr = |
1979 | MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: TOCSymbol, Ctx&: OutContext), |
1980 | RHS: MCSymbolRefExpr::create(Symbol: GlobalEPSymbol, |
1981 | Ctx&: OutContext), |
1982 | Ctx&: OutContext); |
1983 | |
1984 | OutStreamer->emitLabel(Symbol: PPCFI->getTOCOffsetSymbol(MF&: *MF)); |
1985 | OutStreamer->emitValue(Value: TOCDeltaExpr, Size: 8); |
1986 | } |
1987 | return AsmPrinter::emitFunctionEntryLabel(); |
1988 | } |
1989 | |
1990 | // Emit an official procedure descriptor. |
1991 | MCSectionSubPair Current = OutStreamer->getCurrentSection(); |
1992 | MCSectionELF *Section = OutStreamer->getContext().getELFSection( |
1993 | Section: ".opd" , Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_WRITE | ELF::SHF_ALLOC); |
1994 | OutStreamer->switchSection(Section); |
1995 | OutStreamer->emitLabel(Symbol: CurrentFnSym); |
1996 | OutStreamer->emitValueToAlignment(Alignment: Align(8)); |
1997 | MCSymbol *Symbol1 = CurrentFnSymForSize; |
1998 | // Generates a R_PPC64_ADDR64 (from FK_DATA_8) relocation for the function |
1999 | // entry point. |
2000 | OutStreamer->emitValue(Value: MCSymbolRefExpr::create(Symbol: Symbol1, Ctx&: OutContext), |
2001 | Size: 8 /*size*/); |
2002 | MCSymbol *Symbol2 = OutContext.getOrCreateSymbol(Name: StringRef(".TOC." )); |
2003 | // Generates a R_PPC64_TOC relocation for TOC base insertion. |
2004 | OutStreamer->emitValue( |
2005 | Value: MCSymbolRefExpr::create(Symbol: Symbol2, Kind: MCSymbolRefExpr::VK_PPC_TOCBASE, Ctx&: OutContext), |
2006 | Size: 8/*size*/); |
2007 | // Emit a null environment pointer. |
2008 | OutStreamer->emitIntValue(Value: 0, Size: 8 /* size */); |
2009 | OutStreamer->switchSection(Section: Current.first, Subsection: Current.second); |
2010 | } |
2011 | |
2012 | void PPCLinuxAsmPrinter::emitEndOfAsmFile(Module &M) { |
2013 | const DataLayout &DL = getDataLayout(); |
2014 | |
2015 | bool isPPC64 = DL.getPointerSizeInBits() == 64; |
2016 | |
2017 | PPCTargetStreamer *TS = |
2018 | static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer()); |
2019 | |
2020 | // If we are using any values provided by Glibc at fixed addresses, |
2021 | // we need to ensure that the Glibc used at link time actually provides |
2022 | // those values. All versions of Glibc that do will define the symbol |
2023 | // named "__parse_hwcap_and_convert_at_platform". |
2024 | if (static_cast<const PPCTargetMachine &>(TM).hasGlibcHWCAPAccess()) |
2025 | OutStreamer->emitSymbolValue( |
2026 | Sym: GetExternalSymbolSymbol(Sym: "__parse_hwcap_and_convert_at_platform" ), |
2027 | Size: MAI->getCodePointerSize()); |
2028 | emitGNUAttributes(M); |
2029 | |
2030 | if (!TOC.empty()) { |
2031 | const char *Name = isPPC64 ? ".toc" : ".got2" ; |
2032 | MCSectionELF *Section = OutContext.getELFSection( |
2033 | Section: Name, Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_WRITE | ELF::SHF_ALLOC); |
2034 | OutStreamer->switchSection(Section); |
2035 | if (!isPPC64) |
2036 | OutStreamer->emitValueToAlignment(Alignment: Align(4)); |
2037 | |
2038 | for (const auto &TOCMapPair : TOC) { |
2039 | const MCSymbol *const TOCEntryTarget = TOCMapPair.first.first; |
2040 | MCSymbol *const TOCEntryLabel = TOCMapPair.second; |
2041 | |
2042 | OutStreamer->emitLabel(Symbol: TOCEntryLabel); |
2043 | if (isPPC64) |
2044 | TS->emitTCEntry(S: *TOCEntryTarget, Kind: TOCMapPair.first.second); |
2045 | else |
2046 | OutStreamer->emitSymbolValue(Sym: TOCEntryTarget, Size: 4); |
2047 | } |
2048 | } |
2049 | |
2050 | PPCAsmPrinter::emitEndOfAsmFile(M); |
2051 | } |
2052 | |
2053 | /// EmitFunctionBodyStart - Emit a global entry point prefix for ELFv2. |
2054 | void PPCLinuxAsmPrinter::emitFunctionBodyStart() { |
2055 | // In the ELFv2 ABI, in functions that use the TOC register, we need to |
2056 | // provide two entry points. The ABI guarantees that when calling the |
2057 | // local entry point, r2 is set up by the caller to contain the TOC base |
2058 | // for this function, and when calling the global entry point, r12 is set |
2059 | // up by the caller to hold the address of the global entry point. We |
2060 | // thus emit a prefix sequence along the following lines: |
2061 | // |
2062 | // func: |
2063 | // .Lfunc_gepNN: |
2064 | // # global entry point |
2065 | // addis r2,r12,(.TOC.-.Lfunc_gepNN)@ha |
2066 | // addi r2,r2,(.TOC.-.Lfunc_gepNN)@l |
2067 | // .Lfunc_lepNN: |
2068 | // .localentry func, .Lfunc_lepNN-.Lfunc_gepNN |
2069 | // # local entry point, followed by function body |
2070 | // |
2071 | // For the Large code model, we create |
2072 | // |
2073 | // .Lfunc_tocNN: |
2074 | // .quad .TOC.-.Lfunc_gepNN # done by EmitFunctionEntryLabel |
2075 | // func: |
2076 | // .Lfunc_gepNN: |
2077 | // # global entry point |
2078 | // ld r2,.Lfunc_tocNN-.Lfunc_gepNN(r12) |
2079 | // add r2,r2,r12 |
2080 | // .Lfunc_lepNN: |
2081 | // .localentry func, .Lfunc_lepNN-.Lfunc_gepNN |
2082 | // # local entry point, followed by function body |
2083 | // |
2084 | // This ensures we have r2 set up correctly while executing the function |
2085 | // body, no matter which entry point is called. |
2086 | const PPCFunctionInfo *PPCFI = MF->getInfo<PPCFunctionInfo>(); |
2087 | const bool UsesX2OrR2 = !MF->getRegInfo().use_empty(PPC::X2) || |
2088 | !MF->getRegInfo().use_empty(PPC::R2); |
2089 | const bool PCrelGEPRequired = Subtarget->isUsingPCRelativeCalls() && |
2090 | UsesX2OrR2 && PPCFI->usesTOCBasePtr(); |
2091 | const bool NonPCrelGEPRequired = !Subtarget->isUsingPCRelativeCalls() && |
2092 | Subtarget->isELFv2ABI() && UsesX2OrR2; |
2093 | |
2094 | // Only do all that if the function uses R2 as the TOC pointer |
2095 | // in the first place. We don't need the global entry point if the |
2096 | // function uses R2 as an allocatable register. |
2097 | if (NonPCrelGEPRequired || PCrelGEPRequired) { |
2098 | // Note: The logic here must be synchronized with the code in the |
2099 | // branch-selection pass which sets the offset of the first block in the |
2100 | // function. This matters because it affects the alignment. |
2101 | MCSymbol *GlobalEntryLabel = PPCFI->getGlobalEPSymbol(MF&: *MF); |
2102 | OutStreamer->emitLabel(Symbol: GlobalEntryLabel); |
2103 | const MCSymbolRefExpr *GlobalEntryLabelExp = |
2104 | MCSymbolRefExpr::create(Symbol: GlobalEntryLabel, Ctx&: OutContext); |
2105 | |
2106 | if (TM.getCodeModel() != CodeModel::Large) { |
2107 | MCSymbol *TOCSymbol = OutContext.getOrCreateSymbol(Name: StringRef(".TOC." )); |
2108 | const MCExpr *TOCDeltaExpr = |
2109 | MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: TOCSymbol, Ctx&: OutContext), |
2110 | RHS: GlobalEntryLabelExp, Ctx&: OutContext); |
2111 | |
2112 | const MCExpr *TOCDeltaHi = PPCMCExpr::createHa(Expr: TOCDeltaExpr, Ctx&: OutContext); |
2113 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS) |
2114 | .addReg(PPC::X2) |
2115 | .addReg(PPC::X12) |
2116 | .addExpr(TOCDeltaHi)); |
2117 | |
2118 | const MCExpr *TOCDeltaLo = PPCMCExpr::createLo(Expr: TOCDeltaExpr, Ctx&: OutContext); |
2119 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDI) |
2120 | .addReg(PPC::X2) |
2121 | .addReg(PPC::X2) |
2122 | .addExpr(TOCDeltaLo)); |
2123 | } else { |
2124 | MCSymbol *TOCOffset = PPCFI->getTOCOffsetSymbol(MF&: *MF); |
2125 | const MCExpr *TOCOffsetDeltaExpr = |
2126 | MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: TOCOffset, Ctx&: OutContext), |
2127 | RHS: GlobalEntryLabelExp, Ctx&: OutContext); |
2128 | |
2129 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LD) |
2130 | .addReg(PPC::X2) |
2131 | .addExpr(TOCOffsetDeltaExpr) |
2132 | .addReg(PPC::X12)); |
2133 | EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADD8) |
2134 | .addReg(PPC::X2) |
2135 | .addReg(PPC::X2) |
2136 | .addReg(PPC::X12)); |
2137 | } |
2138 | |
2139 | MCSymbol *LocalEntryLabel = PPCFI->getLocalEPSymbol(MF&: *MF); |
2140 | OutStreamer->emitLabel(Symbol: LocalEntryLabel); |
2141 | const MCSymbolRefExpr *LocalEntryLabelExp = |
2142 | MCSymbolRefExpr::create(Symbol: LocalEntryLabel, Ctx&: OutContext); |
2143 | const MCExpr *LocalOffsetExp = |
2144 | MCBinaryExpr::createSub(LHS: LocalEntryLabelExp, |
2145 | RHS: GlobalEntryLabelExp, Ctx&: OutContext); |
2146 | |
2147 | PPCTargetStreamer *TS = |
2148 | static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer()); |
2149 | TS->emitLocalEntry(S: cast<MCSymbolELF>(Val: CurrentFnSym), LocalOffset: LocalOffsetExp); |
2150 | } else if (Subtarget->isUsingPCRelativeCalls()) { |
2151 | // When generating the entry point for a function we have a few scenarios |
2152 | // based on whether or not that function uses R2 and whether or not that |
2153 | // function makes calls (or is a leaf function). |
2154 | // 1) A leaf function that does not use R2 (or treats it as callee-saved |
2155 | // and preserves it). In this case st_other=0 and both |
2156 | // the local and global entry points for the function are the same. |
2157 | // No special entry point code is required. |
2158 | // 2) A function uses the TOC pointer R2. This function may or may not have |
2159 | // calls. In this case st_other=[2,6] and the global and local entry |
2160 | // points are different. Code to correctly setup the TOC pointer in R2 |
2161 | // is put between the global and local entry points. This case is |
2162 | // covered by the if statatement above. |
2163 | // 3) A function does not use the TOC pointer R2 but does have calls. |
2164 | // In this case st_other=1 since we do not know whether or not any |
2165 | // of the callees clobber R2. This case is dealt with in this else if |
2166 | // block. Tail calls are considered calls and the st_other should also |
2167 | // be set to 1 in that case as well. |
2168 | // 4) The function does not use the TOC pointer but R2 is used inside |
2169 | // the function. In this case st_other=1 once again. |
2170 | // 5) This function uses inline asm. We mark R2 as reserved if the function |
2171 | // has inline asm as we have to assume that it may be used. |
2172 | if (MF->getFrameInfo().hasCalls() || MF->getFrameInfo().hasTailCall() || |
2173 | MF->hasInlineAsm() || (!PPCFI->usesTOCBasePtr() && UsesX2OrR2)) { |
2174 | PPCTargetStreamer *TS = |
2175 | static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer()); |
2176 | TS->emitLocalEntry(S: cast<MCSymbolELF>(Val: CurrentFnSym), |
2177 | LocalOffset: MCConstantExpr::create(Value: 1, Ctx&: OutContext)); |
2178 | } |
2179 | } |
2180 | } |
2181 | |
2182 | /// EmitFunctionBodyEnd - Print the traceback table before the .size |
2183 | /// directive. |
2184 | /// |
2185 | void PPCLinuxAsmPrinter::emitFunctionBodyEnd() { |
2186 | // Only the 64-bit target requires a traceback table. For now, |
2187 | // we only emit the word of zeroes that GDB requires to find |
2188 | // the end of the function, and zeroes for the eight-byte |
2189 | // mandatory fields. |
2190 | // FIXME: We should fill in the eight-byte mandatory fields as described in |
2191 | // the PPC64 ELF ABI (this is a low-priority item because GDB does not |
2192 | // currently make use of these fields). |
2193 | if (Subtarget->isPPC64()) { |
2194 | OutStreamer->emitIntValue(Value: 0, Size: 4/*size*/); |
2195 | OutStreamer->emitIntValue(Value: 0, Size: 8/*size*/); |
2196 | } |
2197 | } |
2198 | |
2199 | void PPCAIXAsmPrinter::emitLinkage(const GlobalValue *GV, |
2200 | MCSymbol *GVSym) const { |
2201 | |
2202 | assert(MAI->hasVisibilityOnlyWithLinkage() && |
2203 | "AIX's linkage directives take a visibility setting." ); |
2204 | |
2205 | MCSymbolAttr LinkageAttr = MCSA_Invalid; |
2206 | switch (GV->getLinkage()) { |
2207 | case GlobalValue::ExternalLinkage: |
2208 | LinkageAttr = GV->isDeclaration() ? MCSA_Extern : MCSA_Global; |
2209 | break; |
2210 | case GlobalValue::LinkOnceAnyLinkage: |
2211 | case GlobalValue::LinkOnceODRLinkage: |
2212 | case GlobalValue::WeakAnyLinkage: |
2213 | case GlobalValue::WeakODRLinkage: |
2214 | case GlobalValue::ExternalWeakLinkage: |
2215 | LinkageAttr = MCSA_Weak; |
2216 | break; |
2217 | case GlobalValue::AvailableExternallyLinkage: |
2218 | LinkageAttr = MCSA_Extern; |
2219 | break; |
2220 | case GlobalValue::PrivateLinkage: |
2221 | return; |
2222 | case GlobalValue::InternalLinkage: |
2223 | assert(GV->getVisibility() == GlobalValue::DefaultVisibility && |
2224 | "InternalLinkage should not have other visibility setting." ); |
2225 | LinkageAttr = MCSA_LGlobal; |
2226 | break; |
2227 | case GlobalValue::AppendingLinkage: |
2228 | llvm_unreachable("Should never emit this" ); |
2229 | case GlobalValue::CommonLinkage: |
2230 | llvm_unreachable("CommonLinkage of XCOFF should not come to this path" ); |
2231 | } |
2232 | |
2233 | assert(LinkageAttr != MCSA_Invalid && "LinkageAttr should not MCSA_Invalid." ); |
2234 | |
2235 | MCSymbolAttr VisibilityAttr = MCSA_Invalid; |
2236 | if (!TM.getIgnoreXCOFFVisibility()) { |
2237 | if (GV->hasDLLExportStorageClass() && !GV->hasDefaultVisibility()) |
2238 | report_fatal_error( |
2239 | reason: "Cannot not be both dllexport and non-default visibility" ); |
2240 | switch (GV->getVisibility()) { |
2241 | |
2242 | // TODO: "internal" Visibility needs to go here. |
2243 | case GlobalValue::DefaultVisibility: |
2244 | if (GV->hasDLLExportStorageClass()) |
2245 | VisibilityAttr = MAI->getExportedVisibilityAttr(); |
2246 | break; |
2247 | case GlobalValue::HiddenVisibility: |
2248 | VisibilityAttr = MAI->getHiddenVisibilityAttr(); |
2249 | break; |
2250 | case GlobalValue::ProtectedVisibility: |
2251 | VisibilityAttr = MAI->getProtectedVisibilityAttr(); |
2252 | break; |
2253 | } |
2254 | } |
2255 | |
2256 | // Do not emit the _$TLSML symbol. |
2257 | if (GV->getThreadLocalMode() == GlobalVariable::LocalDynamicTLSModel && |
2258 | GV->hasName() && GV->getName() == "_$TLSML" ) |
2259 | return; |
2260 | |
2261 | OutStreamer->emitXCOFFSymbolLinkageWithVisibility(Symbol: GVSym, Linkage: LinkageAttr, |
2262 | Visibility: VisibilityAttr); |
2263 | } |
2264 | |
2265 | void PPCAIXAsmPrinter::SetupMachineFunction(MachineFunction &MF) { |
2266 | // Setup CurrentFnDescSym and its containing csect. |
2267 | MCSectionXCOFF *FnDescSec = |
2268 | cast<MCSectionXCOFF>(Val: getObjFileLowering().getSectionForFunctionDescriptor( |
2269 | F: &MF.getFunction(), TM)); |
2270 | FnDescSec->setAlignment(Align(Subtarget->isPPC64() ? 8 : 4)); |
2271 | |
2272 | CurrentFnDescSym = FnDescSec->getQualNameSymbol(); |
2273 | |
2274 | return AsmPrinter::SetupMachineFunction(MF); |
2275 | } |
2276 | |
2277 | uint16_t PPCAIXAsmPrinter::getNumberOfVRSaved() { |
2278 | // Calculate the number of VRs be saved. |
2279 | // Vector registers 20 through 31 are marked as reserved and cannot be used |
2280 | // in the default ABI. |
2281 | const PPCSubtarget &Subtarget = MF->getSubtarget<PPCSubtarget>(); |
2282 | if (Subtarget.isAIXABI() && Subtarget.hasAltivec() && |
2283 | TM.getAIXExtendedAltivecABI()) { |
2284 | const MachineRegisterInfo &MRI = MF->getRegInfo(); |
2285 | for (unsigned Reg = PPC::V20; Reg <= PPC::V31; ++Reg) |
2286 | if (MRI.isPhysRegModified(Reg)) |
2287 | // Number of VRs saved. |
2288 | return PPC::V31 - Reg + 1; |
2289 | } |
2290 | return 0; |
2291 | } |
2292 | |
2293 | void PPCAIXAsmPrinter::emitFunctionBodyEnd() { |
2294 | |
2295 | if (!TM.getXCOFFTracebackTable()) |
2296 | return; |
2297 | |
2298 | emitTracebackTable(); |
2299 | |
2300 | // If ShouldEmitEHBlock returns true, then the eh info table |
2301 | // will be emitted via `AIXException::endFunction`. Otherwise, we |
2302 | // need to emit a dumy eh info table when VRs are saved. We could not |
2303 | // consolidate these two places into one because there is no easy way |
2304 | // to access register information in `AIXException` class. |
2305 | if (!TargetLoweringObjectFileXCOFF::ShouldEmitEHBlock(MF) && |
2306 | (getNumberOfVRSaved() > 0)) { |
2307 | // Emit dummy EH Info Table. |
2308 | OutStreamer->switchSection(Section: getObjFileLowering().getCompactUnwindSection()); |
2309 | MCSymbol *EHInfoLabel = |
2310 | TargetLoweringObjectFileXCOFF::getEHInfoTableSymbol(MF); |
2311 | OutStreamer->emitLabel(Symbol: EHInfoLabel); |
2312 | |
2313 | // Version number. |
2314 | OutStreamer->emitInt32(Value: 0); |
2315 | |
2316 | const DataLayout &DL = MMI->getModule()->getDataLayout(); |
2317 | const unsigned PointerSize = DL.getPointerSize(); |
2318 | // Add necessary paddings in 64 bit mode. |
2319 | OutStreamer->emitValueToAlignment(Alignment: Align(PointerSize)); |
2320 | |
2321 | OutStreamer->emitIntValue(Value: 0, Size: PointerSize); |
2322 | OutStreamer->emitIntValue(Value: 0, Size: PointerSize); |
2323 | OutStreamer->switchSection(Section: MF->getSection()); |
2324 | } |
2325 | } |
2326 | |
2327 | void PPCAIXAsmPrinter::emitTracebackTable() { |
2328 | |
2329 | // Create a symbol for the end of function. |
2330 | MCSymbol *FuncEnd = createTempSymbol(Name: MF->getName()); |
2331 | OutStreamer->emitLabel(Symbol: FuncEnd); |
2332 | |
2333 | OutStreamer->AddComment(T: "Traceback table begin" ); |
2334 | // Begin with a fullword of zero. |
2335 | OutStreamer->emitIntValueInHexWithPadding(Value: 0, Size: 4 /*size*/); |
2336 | |
2337 | SmallString<128> ; |
2338 | raw_svector_ostream (CommentString); |
2339 | |
2340 | auto = [&]() { |
2341 | OutStreamer->AddComment(T: CommentOS.str()); |
2342 | CommentString.clear(); |
2343 | }; |
2344 | |
2345 | auto EmitCommentAndValue = [&](uint64_t Value, int Size) { |
2346 | EmitComment(); |
2347 | OutStreamer->emitIntValueInHexWithPadding(Value, Size); |
2348 | }; |
2349 | |
2350 | unsigned int Version = 0; |
2351 | CommentOS << "Version = " << Version; |
2352 | EmitCommentAndValue(Version, 1); |
2353 | |
2354 | // There is a lack of information in the IR to assist with determining the |
2355 | // source language. AIX exception handling mechanism would only search for |
2356 | // personality routine and LSDA area when such language supports exception |
2357 | // handling. So to be conservatively correct and allow runtime to do its job, |
2358 | // we need to set it to C++ for now. |
2359 | TracebackTable::LanguageID LanguageIdentifier = |
2360 | TracebackTable::CPlusPlus; // C++ |
2361 | |
2362 | CommentOS << "Language = " |
2363 | << getNameForTracebackTableLanguageId(LangId: LanguageIdentifier); |
2364 | EmitCommentAndValue(LanguageIdentifier, 1); |
2365 | |
2366 | // This is only populated for the third and fourth bytes. |
2367 | uint32_t FirstHalfOfMandatoryField = 0; |
2368 | |
2369 | // Emit the 3rd byte of the mandatory field. |
2370 | |
2371 | // We always set traceback offset bit to true. |
2372 | FirstHalfOfMandatoryField |= TracebackTable::HasTraceBackTableOffsetMask; |
2373 | |
2374 | const PPCFunctionInfo *FI = MF->getInfo<PPCFunctionInfo>(); |
2375 | const MachineRegisterInfo &MRI = MF->getRegInfo(); |
2376 | |
2377 | // Check the function uses floating-point processor instructions or not |
2378 | for (unsigned Reg = PPC::F0; Reg <= PPC::F31; ++Reg) { |
2379 | if (MRI.isPhysRegUsed(Reg, /* SkipRegMaskTest */ true)) { |
2380 | FirstHalfOfMandatoryField |= TracebackTable::IsFloatingPointPresentMask; |
2381 | break; |
2382 | } |
2383 | } |
2384 | |
2385 | #define (Prefix, V, Field) \ |
2386 | CommentOS << (Prefix) << ((V) & (TracebackTable::Field##Mask) ? "+" : "-") \ |
2387 | << #Field |
2388 | |
2389 | #define (PrefixAndName, V, Field) \ |
2390 | CommentOS << (PrefixAndName) << " = " \ |
2391 | << static_cast<unsigned>(((V) & (TracebackTable::Field##Mask)) >> \ |
2392 | (TracebackTable::Field##Shift)) |
2393 | |
2394 | GENBOOLCOMMENT("" , FirstHalfOfMandatoryField, IsGlobaLinkage); |
2395 | GENBOOLCOMMENT(", " , FirstHalfOfMandatoryField, IsOutOfLineEpilogOrPrologue); |
2396 | EmitComment(); |
2397 | |
2398 | GENBOOLCOMMENT("" , FirstHalfOfMandatoryField, HasTraceBackTableOffset); |
2399 | GENBOOLCOMMENT(", " , FirstHalfOfMandatoryField, IsInternalProcedure); |
2400 | EmitComment(); |
2401 | |
2402 | GENBOOLCOMMENT("" , FirstHalfOfMandatoryField, HasControlledStorage); |
2403 | GENBOOLCOMMENT(", " , FirstHalfOfMandatoryField, IsTOCless); |
2404 | EmitComment(); |
2405 | |
2406 | GENBOOLCOMMENT("" , FirstHalfOfMandatoryField, IsFloatingPointPresent); |
2407 | EmitComment(); |
2408 | GENBOOLCOMMENT("" , FirstHalfOfMandatoryField, |
2409 | IsFloatingPointOperationLogOrAbortEnabled); |
2410 | EmitComment(); |
2411 | |
2412 | OutStreamer->emitIntValueInHexWithPadding( |
2413 | Value: (FirstHalfOfMandatoryField & 0x0000ff00) >> 8, Size: 1); |
2414 | |
2415 | // Set the 4th byte of the mandatory field. |
2416 | FirstHalfOfMandatoryField |= TracebackTable::IsFunctionNamePresentMask; |
2417 | |
2418 | const PPCRegisterInfo *RegInfo = |
2419 | static_cast<const PPCRegisterInfo *>(Subtarget->getRegisterInfo()); |
2420 | Register FrameReg = RegInfo->getFrameRegister(*MF); |
2421 | if (FrameReg == (Subtarget->isPPC64() ? PPC::X31 : PPC::R31)) |
2422 | FirstHalfOfMandatoryField |= TracebackTable::IsAllocaUsedMask; |
2423 | |
2424 | const SmallVectorImpl<Register> &MustSaveCRs = FI->getMustSaveCRs(); |
2425 | if (!MustSaveCRs.empty()) |
2426 | FirstHalfOfMandatoryField |= TracebackTable::IsCRSavedMask; |
2427 | |
2428 | if (FI->mustSaveLR()) |
2429 | FirstHalfOfMandatoryField |= TracebackTable::IsLRSavedMask; |
2430 | |
2431 | GENBOOLCOMMENT("" , FirstHalfOfMandatoryField, IsInterruptHandler); |
2432 | GENBOOLCOMMENT(", " , FirstHalfOfMandatoryField, IsFunctionNamePresent); |
2433 | GENBOOLCOMMENT(", " , FirstHalfOfMandatoryField, IsAllocaUsed); |
2434 | EmitComment(); |
2435 | GENVALUECOMMENT("OnConditionDirective" , FirstHalfOfMandatoryField, |
2436 | OnConditionDirective); |
2437 | GENBOOLCOMMENT(", " , FirstHalfOfMandatoryField, IsCRSaved); |
2438 | GENBOOLCOMMENT(", " , FirstHalfOfMandatoryField, IsLRSaved); |
2439 | EmitComment(); |
2440 | OutStreamer->emitIntValueInHexWithPadding(Value: (FirstHalfOfMandatoryField & 0xff), |
2441 | Size: 1); |
2442 | |
2443 | // Set the 5th byte of mandatory field. |
2444 | uint32_t SecondHalfOfMandatoryField = 0; |
2445 | |
2446 | SecondHalfOfMandatoryField |= MF->getFrameInfo().getStackSize() |
2447 | ? TracebackTable::IsBackChainStoredMask |
2448 | : 0; |
2449 | |
2450 | uint32_t FPRSaved = 0; |
2451 | for (unsigned Reg = PPC::F14; Reg <= PPC::F31; ++Reg) { |
2452 | if (MRI.isPhysRegModified(Reg)) { |
2453 | FPRSaved = PPC::F31 - Reg + 1; |
2454 | break; |
2455 | } |
2456 | } |
2457 | SecondHalfOfMandatoryField |= (FPRSaved << TracebackTable::FPRSavedShift) & |
2458 | TracebackTable::FPRSavedMask; |
2459 | GENBOOLCOMMENT("" , SecondHalfOfMandatoryField, IsBackChainStored); |
2460 | GENBOOLCOMMENT(", " , SecondHalfOfMandatoryField, IsFixup); |
2461 | GENVALUECOMMENT(", NumOfFPRsSaved" , SecondHalfOfMandatoryField, FPRSaved); |
2462 | EmitComment(); |
2463 | OutStreamer->emitIntValueInHexWithPadding( |
2464 | Value: (SecondHalfOfMandatoryField & 0xff000000) >> 24, Size: 1); |
2465 | |
2466 | // Set the 6th byte of mandatory field. |
2467 | |
2468 | // Check whether has Vector Instruction,We only treat instructions uses vector |
2469 | // register as vector instructions. |
2470 | bool HasVectorInst = false; |
2471 | for (unsigned Reg = PPC::V0; Reg <= PPC::V31; ++Reg) |
2472 | if (MRI.isPhysRegUsed(Reg, /* SkipRegMaskTest */ true)) { |
2473 | // Has VMX instruction. |
2474 | HasVectorInst = true; |
2475 | break; |
2476 | } |
2477 | |
2478 | if (FI->hasVectorParms() || HasVectorInst) |
2479 | SecondHalfOfMandatoryField |= TracebackTable::HasVectorInfoMask; |
2480 | |
2481 | uint16_t NumOfVRSaved = getNumberOfVRSaved(); |
2482 | bool ShouldEmitEHBlock = |
2483 | TargetLoweringObjectFileXCOFF::ShouldEmitEHBlock(MF) || NumOfVRSaved > 0; |
2484 | |
2485 | if (ShouldEmitEHBlock) |
2486 | SecondHalfOfMandatoryField |= TracebackTable::HasExtensionTableMask; |
2487 | |
2488 | uint32_t GPRSaved = 0; |
2489 | |
2490 | // X13 is reserved under 64-bit environment. |
2491 | unsigned GPRBegin = Subtarget->isPPC64() ? PPC::X14 : PPC::R13; |
2492 | unsigned GPREnd = Subtarget->isPPC64() ? PPC::X31 : PPC::R31; |
2493 | |
2494 | for (unsigned Reg = GPRBegin; Reg <= GPREnd; ++Reg) { |
2495 | if (MRI.isPhysRegModified(PhysReg: Reg)) { |
2496 | GPRSaved = GPREnd - Reg + 1; |
2497 | break; |
2498 | } |
2499 | } |
2500 | |
2501 | SecondHalfOfMandatoryField |= (GPRSaved << TracebackTable::GPRSavedShift) & |
2502 | TracebackTable::GPRSavedMask; |
2503 | |
2504 | GENBOOLCOMMENT("" , SecondHalfOfMandatoryField, HasExtensionTable); |
2505 | GENBOOLCOMMENT(", " , SecondHalfOfMandatoryField, HasVectorInfo); |
2506 | GENVALUECOMMENT(", NumOfGPRsSaved" , SecondHalfOfMandatoryField, GPRSaved); |
2507 | EmitComment(); |
2508 | OutStreamer->emitIntValueInHexWithPadding( |
2509 | Value: (SecondHalfOfMandatoryField & 0x00ff0000) >> 16, Size: 1); |
2510 | |
2511 | // Set the 7th byte of mandatory field. |
2512 | uint32_t NumberOfFixedParms = FI->getFixedParmsNum(); |
2513 | SecondHalfOfMandatoryField |= |
2514 | (NumberOfFixedParms << TracebackTable::NumberOfFixedParmsShift) & |
2515 | TracebackTable::NumberOfFixedParmsMask; |
2516 | GENVALUECOMMENT("NumberOfFixedParms" , SecondHalfOfMandatoryField, |
2517 | NumberOfFixedParms); |
2518 | EmitComment(); |
2519 | OutStreamer->emitIntValueInHexWithPadding( |
2520 | Value: (SecondHalfOfMandatoryField & 0x0000ff00) >> 8, Size: 1); |
2521 | |
2522 | // Set the 8th byte of mandatory field. |
2523 | |
2524 | // Always set parameter on stack. |
2525 | SecondHalfOfMandatoryField |= TracebackTable::HasParmsOnStackMask; |
2526 | |
2527 | uint32_t NumberOfFPParms = FI->getFloatingPointParmsNum(); |
2528 | SecondHalfOfMandatoryField |= |
2529 | (NumberOfFPParms << TracebackTable::NumberOfFloatingPointParmsShift) & |
2530 | TracebackTable::NumberOfFloatingPointParmsMask; |
2531 | |
2532 | GENVALUECOMMENT("NumberOfFPParms" , SecondHalfOfMandatoryField, |
2533 | NumberOfFloatingPointParms); |
2534 | GENBOOLCOMMENT(", " , SecondHalfOfMandatoryField, HasParmsOnStack); |
2535 | EmitComment(); |
2536 | OutStreamer->emitIntValueInHexWithPadding(Value: SecondHalfOfMandatoryField & 0xff, |
2537 | Size: 1); |
2538 | |
2539 | // Generate the optional fields of traceback table. |
2540 | |
2541 | // Parameter type. |
2542 | if (NumberOfFixedParms || NumberOfFPParms) { |
2543 | uint32_t ParmsTypeValue = FI->getParmsType(); |
2544 | |
2545 | Expected<SmallString<32>> ParmsType = |
2546 | FI->hasVectorParms() |
2547 | ? XCOFF::parseParmsTypeWithVecInfo( |
2548 | Value: ParmsTypeValue, FixedParmsNum: NumberOfFixedParms, FloatingParmsNum: NumberOfFPParms, |
2549 | VectorParmsNum: FI->getVectorParmsNum()) |
2550 | : XCOFF::parseParmsType(Value: ParmsTypeValue, FixedParmsNum: NumberOfFixedParms, |
2551 | FloatingParmsNum: NumberOfFPParms); |
2552 | |
2553 | assert(ParmsType && toString(ParmsType.takeError()).c_str()); |
2554 | if (ParmsType) { |
2555 | CommentOS << "Parameter type = " << ParmsType.get(); |
2556 | EmitComment(); |
2557 | } |
2558 | OutStreamer->emitIntValueInHexWithPadding(Value: ParmsTypeValue, |
2559 | Size: sizeof(ParmsTypeValue)); |
2560 | } |
2561 | // Traceback table offset. |
2562 | OutStreamer->AddComment(T: "Function size" ); |
2563 | if (FirstHalfOfMandatoryField & TracebackTable::HasTraceBackTableOffsetMask) { |
2564 | MCSymbol *FuncSectSym = getObjFileLowering().getFunctionEntryPointSymbol( |
2565 | Func: &(MF->getFunction()), TM); |
2566 | OutStreamer->emitAbsoluteSymbolDiff(Hi: FuncEnd, Lo: FuncSectSym, Size: 4); |
2567 | } |
2568 | |
2569 | // Since we unset the Int_Handler. |
2570 | if (FirstHalfOfMandatoryField & TracebackTable::IsInterruptHandlerMask) |
2571 | report_fatal_error(reason: "Hand_Mask not implement yet" ); |
2572 | |
2573 | if (FirstHalfOfMandatoryField & TracebackTable::HasControlledStorageMask) |
2574 | report_fatal_error(reason: "Ctl_Info not implement yet" ); |
2575 | |
2576 | if (FirstHalfOfMandatoryField & TracebackTable::IsFunctionNamePresentMask) { |
2577 | StringRef Name = MF->getName().substr(Start: 0, INT16_MAX); |
2578 | int16_t NameLength = Name.size(); |
2579 | CommentOS << "Function name len = " |
2580 | << static_cast<unsigned int>(NameLength); |
2581 | EmitCommentAndValue(NameLength, 2); |
2582 | OutStreamer->AddComment(T: "Function Name" ); |
2583 | OutStreamer->emitBytes(Data: Name); |
2584 | } |
2585 | |
2586 | if (FirstHalfOfMandatoryField & TracebackTable::IsAllocaUsedMask) { |
2587 | uint8_t AllocReg = XCOFF::AllocRegNo; |
2588 | OutStreamer->AddComment(T: "AllocaUsed" ); |
2589 | OutStreamer->emitIntValueInHex(Value: AllocReg, Size: sizeof(AllocReg)); |
2590 | } |
2591 | |
2592 | if (SecondHalfOfMandatoryField & TracebackTable::HasVectorInfoMask) { |
2593 | uint16_t VRData = 0; |
2594 | if (NumOfVRSaved) { |
2595 | // Number of VRs saved. |
2596 | VRData |= (NumOfVRSaved << TracebackTable::NumberOfVRSavedShift) & |
2597 | TracebackTable::NumberOfVRSavedMask; |
2598 | // This bit is supposed to set only when the special register |
2599 | // VRSAVE is saved on stack. |
2600 | // However, IBM XL compiler sets the bit when any vector registers |
2601 | // are saved on the stack. We will follow XL's behavior on AIX |
2602 | // so that we don't get surprise behavior change for C code. |
2603 | VRData |= TracebackTable::IsVRSavedOnStackMask; |
2604 | } |
2605 | |
2606 | // Set has_varargs. |
2607 | if (FI->getVarArgsFrameIndex()) |
2608 | VRData |= TracebackTable::HasVarArgsMask; |
2609 | |
2610 | // Vector parameters number. |
2611 | unsigned VectorParmsNum = FI->getVectorParmsNum(); |
2612 | VRData |= (VectorParmsNum << TracebackTable::NumberOfVectorParmsShift) & |
2613 | TracebackTable::NumberOfVectorParmsMask; |
2614 | |
2615 | if (HasVectorInst) |
2616 | VRData |= TracebackTable::HasVMXInstructionMask; |
2617 | |
2618 | GENVALUECOMMENT("NumOfVRsSaved" , VRData, NumberOfVRSaved); |
2619 | GENBOOLCOMMENT(", " , VRData, IsVRSavedOnStack); |
2620 | GENBOOLCOMMENT(", " , VRData, HasVarArgs); |
2621 | EmitComment(); |
2622 | OutStreamer->emitIntValueInHexWithPadding(Value: (VRData & 0xff00) >> 8, Size: 1); |
2623 | |
2624 | GENVALUECOMMENT("NumOfVectorParams" , VRData, NumberOfVectorParms); |
2625 | GENBOOLCOMMENT(", " , VRData, HasVMXInstruction); |
2626 | EmitComment(); |
2627 | OutStreamer->emitIntValueInHexWithPadding(Value: VRData & 0x00ff, Size: 1); |
2628 | |
2629 | uint32_t VecParmTypeValue = FI->getVecExtParmsType(); |
2630 | |
2631 | Expected<SmallString<32>> VecParmsType = |
2632 | XCOFF::parseVectorParmsType(Value: VecParmTypeValue, ParmsNum: VectorParmsNum); |
2633 | assert(VecParmsType && toString(VecParmsType.takeError()).c_str()); |
2634 | if (VecParmsType) { |
2635 | CommentOS << "Vector Parameter type = " << VecParmsType.get(); |
2636 | EmitComment(); |
2637 | } |
2638 | OutStreamer->emitIntValueInHexWithPadding(Value: VecParmTypeValue, |
2639 | Size: sizeof(VecParmTypeValue)); |
2640 | // Padding 2 bytes. |
2641 | CommentOS << "Padding" ; |
2642 | EmitCommentAndValue(0, 2); |
2643 | } |
2644 | |
2645 | uint8_t ExtensionTableFlag = 0; |
2646 | if (SecondHalfOfMandatoryField & TracebackTable::HasExtensionTableMask) { |
2647 | if (ShouldEmitEHBlock) |
2648 | ExtensionTableFlag |= ExtendedTBTableFlag::TB_EH_INFO; |
2649 | if (EnableSSPCanaryBitInTB && |
2650 | TargetLoweringObjectFileXCOFF::ShouldSetSSPCanaryBitInTB(MF)) |
2651 | ExtensionTableFlag |= ExtendedTBTableFlag::TB_SSP_CANARY; |
2652 | |
2653 | CommentOS << "ExtensionTableFlag = " |
2654 | << getExtendedTBTableFlagString(Flag: ExtensionTableFlag); |
2655 | EmitCommentAndValue(ExtensionTableFlag, sizeof(ExtensionTableFlag)); |
2656 | } |
2657 | |
2658 | if (ExtensionTableFlag & ExtendedTBTableFlag::TB_EH_INFO) { |
2659 | auto &Ctx = OutStreamer->getContext(); |
2660 | MCSymbol *EHInfoSym = |
2661 | TargetLoweringObjectFileXCOFF::getEHInfoTableSymbol(MF); |
2662 | MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(Sym: EHInfoSym, Type: TOCType_EHBlock); |
2663 | const MCSymbol *TOCBaseSym = |
2664 | cast<MCSectionXCOFF>(Val: getObjFileLowering().getTOCBaseSection()) |
2665 | ->getQualNameSymbol(); |
2666 | const MCExpr *Exp = |
2667 | MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: TOCEntry, Ctx), |
2668 | RHS: MCSymbolRefExpr::create(Symbol: TOCBaseSym, Ctx), Ctx); |
2669 | |
2670 | const DataLayout &DL = getDataLayout(); |
2671 | OutStreamer->emitValueToAlignment(Alignment: Align(4)); |
2672 | OutStreamer->AddComment(T: "EHInfo Table" ); |
2673 | OutStreamer->emitValue(Value: Exp, Size: DL.getPointerSize()); |
2674 | } |
2675 | #undef GENBOOLCOMMENT |
2676 | #undef GENVALUECOMMENT |
2677 | } |
2678 | |
2679 | static bool isSpecialLLVMGlobalArrayToSkip(const GlobalVariable *GV) { |
2680 | return GV->hasAppendingLinkage() && |
2681 | StringSwitch<bool>(GV->getName()) |
2682 | // TODO: Linker could still eliminate the GV if we just skip |
2683 | // handling llvm.used array. Skipping them for now until we or the |
2684 | // AIX OS team come up with a good solution. |
2685 | .Case(S: "llvm.used" , Value: true) |
2686 | // It's correct to just skip llvm.compiler.used array here. |
2687 | .Case(S: "llvm.compiler.used" , Value: true) |
2688 | .Default(Value: false); |
2689 | } |
2690 | |
2691 | static bool isSpecialLLVMGlobalArrayForStaticInit(const GlobalVariable *GV) { |
2692 | return StringSwitch<bool>(GV->getName()) |
2693 | .Cases(S0: "llvm.global_ctors" , S1: "llvm.global_dtors" , Value: true) |
2694 | .Default(Value: false); |
2695 | } |
2696 | |
2697 | uint64_t PPCAIXAsmPrinter::getAliasOffset(const Constant *C) { |
2698 | if (auto *GA = dyn_cast<GlobalAlias>(Val: C)) |
2699 | return getAliasOffset(C: GA->getAliasee()); |
2700 | if (auto *CE = dyn_cast<ConstantExpr>(Val: C)) { |
2701 | const MCExpr *LowC = lowerConstant(CV: CE); |
2702 | const MCBinaryExpr *CBE = dyn_cast<MCBinaryExpr>(Val: LowC); |
2703 | if (!CBE) |
2704 | return 0; |
2705 | if (CBE->getOpcode() != MCBinaryExpr::Add) |
2706 | report_fatal_error(reason: "Only adding an offset is supported now." ); |
2707 | auto *RHS = dyn_cast<MCConstantExpr>(Val: CBE->getRHS()); |
2708 | if (!RHS) |
2709 | report_fatal_error(reason: "Unable to get the offset of alias." ); |
2710 | return RHS->getValue(); |
2711 | } |
2712 | return 0; |
2713 | } |
2714 | |
2715 | static void tocDataChecks(unsigned PointerSize, const GlobalVariable *GV) { |
2716 | // TODO: These asserts should be updated as more support for the toc data |
2717 | // transformation is added (struct support, etc.). |
2718 | assert( |
2719 | PointerSize >= GV->getAlign().valueOrOne().value() && |
2720 | "GlobalVariables with an alignment requirement stricter than TOC entry " |
2721 | "size not supported by the toc data transformation." ); |
2722 | |
2723 | Type *GVType = GV->getValueType(); |
2724 | assert(GVType->isSized() && "A GlobalVariable's size must be known to be " |
2725 | "supported by the toc data transformation." ); |
2726 | if (GV->getParent()->getDataLayout().getTypeSizeInBits(Ty: GVType) > |
2727 | PointerSize * 8) |
2728 | report_fatal_error( |
2729 | reason: "A GlobalVariable with size larger than a TOC entry is not currently " |
2730 | "supported by the toc data transformation." ); |
2731 | if (GV->hasPrivateLinkage()) |
2732 | report_fatal_error(reason: "A GlobalVariable with private linkage is not " |
2733 | "currently supported by the toc data transformation." ); |
2734 | } |
2735 | |
2736 | void PPCAIXAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { |
2737 | // Special LLVM global arrays have been handled at the initialization. |
2738 | if (isSpecialLLVMGlobalArrayToSkip(GV) || isSpecialLLVMGlobalArrayForStaticInit(GV)) |
2739 | return; |
2740 | |
2741 | // If the Global Variable has the toc-data attribute, it needs to be emitted |
2742 | // when we emit the .toc section. |
2743 | if (GV->hasAttribute(Kind: "toc-data" )) { |
2744 | unsigned PointerSize = GV->getParent()->getDataLayout().getPointerSize(); |
2745 | tocDataChecks(PointerSize, GV); |
2746 | TOCDataGlobalVars.push_back(Elt: GV); |
2747 | return; |
2748 | } |
2749 | |
2750 | emitGlobalVariableHelper(GV); |
2751 | } |
2752 | |
2753 | void PPCAIXAsmPrinter::emitGlobalVariableHelper(const GlobalVariable *GV) { |
2754 | assert(!GV->getName().starts_with("llvm." ) && |
2755 | "Unhandled intrinsic global variable." ); |
2756 | |
2757 | if (GV->hasComdat()) |
2758 | report_fatal_error(reason: "COMDAT not yet supported by AIX." ); |
2759 | |
2760 | MCSymbolXCOFF *GVSym = cast<MCSymbolXCOFF>(Val: getSymbol(GV)); |
2761 | |
2762 | if (GV->isDeclarationForLinker()) { |
2763 | emitLinkage(GV, GVSym); |
2764 | return; |
2765 | } |
2766 | |
2767 | SectionKind GVKind = getObjFileLowering().getKindForGlobal(GO: GV, TM); |
2768 | if (!GVKind.isGlobalWriteableData() && !GVKind.isReadOnly() && |
2769 | !GVKind.isThreadLocal()) // Checks for both ThreadData and ThreadBSS. |
2770 | report_fatal_error(reason: "Encountered a global variable kind that is " |
2771 | "not supported yet." ); |
2772 | |
2773 | // Print GV in verbose mode |
2774 | if (isVerbose()) { |
2775 | if (GV->hasInitializer()) { |
2776 | GV->printAsOperand(O&: OutStreamer->getCommentOS(), |
2777 | /*PrintType=*/false, M: GV->getParent()); |
2778 | OutStreamer->getCommentOS() << '\n'; |
2779 | } |
2780 | } |
2781 | |
2782 | MCSectionXCOFF *Csect = cast<MCSectionXCOFF>( |
2783 | Val: getObjFileLowering().SectionForGlobal(GO: GV, Kind: GVKind, TM)); |
2784 | |
2785 | // Switch to the containing csect. |
2786 | OutStreamer->switchSection(Section: Csect); |
2787 | |
2788 | const DataLayout &DL = GV->getParent()->getDataLayout(); |
2789 | |
2790 | // Handle common and zero-initialized local symbols. |
2791 | if (GV->hasCommonLinkage() || GVKind.isBSSLocal() || |
2792 | GVKind.isThreadBSSLocal()) { |
2793 | Align Alignment = GV->getAlign().value_or(u: DL.getPreferredAlign(GV)); |
2794 | uint64_t Size = DL.getTypeAllocSize(Ty: GV->getValueType()); |
2795 | GVSym->setStorageClass( |
2796 | TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GV)); |
2797 | |
2798 | if (GVKind.isBSSLocal() && Csect->getMappingClass() == XCOFF::XMC_TD) { |
2799 | OutStreamer->emitZeros(NumBytes: Size); |
2800 | } else if (GVKind.isBSSLocal() || GVKind.isThreadBSSLocal()) { |
2801 | assert(Csect->getMappingClass() != XCOFF::XMC_TD && |
2802 | "BSS local toc-data already handled and TLS variables " |
2803 | "incompatible with XMC_TD" ); |
2804 | OutStreamer->emitXCOFFLocalCommonSymbol( |
2805 | LabelSym: OutContext.getOrCreateSymbol(Name: GVSym->getSymbolTableName()), Size, |
2806 | CsectSym: GVSym, Alignment); |
2807 | } else { |
2808 | OutStreamer->emitCommonSymbol(Symbol: GVSym, Size, ByteAlignment: Alignment); |
2809 | } |
2810 | return; |
2811 | } |
2812 | |
2813 | MCSymbol *EmittedInitSym = GVSym; |
2814 | |
2815 | // Emit linkage for the global variable and its aliases. |
2816 | emitLinkage(GV, GVSym: EmittedInitSym); |
2817 | for (const GlobalAlias *GA : GOAliasMap[GV]) |
2818 | emitLinkage(GV: GA, GVSym: getSymbol(GV: GA)); |
2819 | |
2820 | emitAlignment(Alignment: getGVAlignment(GV, DL), GV); |
2821 | |
2822 | // When -fdata-sections is enabled, every GlobalVariable will |
2823 | // be put into its own csect; therefore, label is not necessary here. |
2824 | if (!TM.getDataSections() || GV->hasSection()) |
2825 | OutStreamer->emitLabel(Symbol: EmittedInitSym); |
2826 | |
2827 | // No alias to emit. |
2828 | if (!GOAliasMap[GV].size()) { |
2829 | emitGlobalConstant(DL: GV->getParent()->getDataLayout(), CV: GV->getInitializer()); |
2830 | return; |
2831 | } |
2832 | |
2833 | // Aliases with the same offset should be aligned. Record the list of aliases |
2834 | // associated with the offset. |
2835 | AliasMapTy AliasList; |
2836 | for (const GlobalAlias *GA : GOAliasMap[GV]) |
2837 | AliasList[getAliasOffset(C: GA->getAliasee())].push_back(Elt: GA); |
2838 | |
2839 | // Emit alias label and element value for global variable. |
2840 | emitGlobalConstant(DL: GV->getParent()->getDataLayout(), CV: GV->getInitializer(), |
2841 | AliasList: &AliasList); |
2842 | } |
2843 | |
2844 | void PPCAIXAsmPrinter::emitFunctionDescriptor() { |
2845 | const DataLayout &DL = getDataLayout(); |
2846 | const unsigned PointerSize = DL.getPointerSizeInBits() == 64 ? 8 : 4; |
2847 | |
2848 | MCSectionSubPair Current = OutStreamer->getCurrentSection(); |
2849 | // Emit function descriptor. |
2850 | OutStreamer->switchSection( |
2851 | Section: cast<MCSymbolXCOFF>(Val: CurrentFnDescSym)->getRepresentedCsect()); |
2852 | |
2853 | // Emit aliasing label for function descriptor csect. |
2854 | for (const GlobalAlias *Alias : GOAliasMap[&MF->getFunction()]) |
2855 | OutStreamer->emitLabel(Symbol: getSymbol(GV: Alias)); |
2856 | |
2857 | // Emit function entry point address. |
2858 | OutStreamer->emitValue(Value: MCSymbolRefExpr::create(Symbol: CurrentFnSym, Ctx&: OutContext), |
2859 | Size: PointerSize); |
2860 | // Emit TOC base address. |
2861 | const MCSymbol *TOCBaseSym = |
2862 | cast<MCSectionXCOFF>(Val: getObjFileLowering().getTOCBaseSection()) |
2863 | ->getQualNameSymbol(); |
2864 | OutStreamer->emitValue(Value: MCSymbolRefExpr::create(Symbol: TOCBaseSym, Ctx&: OutContext), |
2865 | Size: PointerSize); |
2866 | // Emit a null environment pointer. |
2867 | OutStreamer->emitIntValue(Value: 0, Size: PointerSize); |
2868 | |
2869 | OutStreamer->switchSection(Section: Current.first, Subsection: Current.second); |
2870 | } |
2871 | |
2872 | void PPCAIXAsmPrinter::emitFunctionEntryLabel() { |
2873 | // For functions without user defined section, it's not necessary to emit the |
2874 | // label when we have individual function in its own csect. |
2875 | if (!TM.getFunctionSections() || MF->getFunction().hasSection()) |
2876 | PPCAsmPrinter::emitFunctionEntryLabel(); |
2877 | |
2878 | // Emit aliasing label for function entry point label. |
2879 | for (const GlobalAlias *Alias : GOAliasMap[&MF->getFunction()]) |
2880 | OutStreamer->emitLabel( |
2881 | Symbol: getObjFileLowering().getFunctionEntryPointSymbol(Func: Alias, TM)); |
2882 | } |
2883 | |
2884 | void PPCAIXAsmPrinter::emitPGORefs(Module &M) { |
2885 | if (!OutContext.hasXCOFFSection( |
2886 | Section: "__llvm_prf_cnts" , |
2887 | CsectProp: XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD))) |
2888 | return; |
2889 | |
2890 | // When inside a csect `foo`, a .ref directive referring to a csect `bar` |
2891 | // translates into a relocation entry from `foo` to` bar`. The referring |
2892 | // csect, `foo`, is identified by its address. If multiple csects have the |
2893 | // same address (because one or more of them are zero-length), the referring |
2894 | // csect cannot be determined. Hence, we don't generate the .ref directives |
2895 | // if `__llvm_prf_cnts` is an empty section. |
2896 | bool HasNonZeroLengthPrfCntsSection = false; |
2897 | const DataLayout &DL = M.getDataLayout(); |
2898 | for (GlobalVariable &GV : M.globals()) |
2899 | if (GV.hasSection() && GV.getSection().equals(RHS: "__llvm_prf_cnts" ) && |
2900 | DL.getTypeAllocSize(Ty: GV.getValueType()) > 0) { |
2901 | HasNonZeroLengthPrfCntsSection = true; |
2902 | break; |
2903 | } |
2904 | |
2905 | if (HasNonZeroLengthPrfCntsSection) { |
2906 | MCSection *CntsSection = OutContext.getXCOFFSection( |
2907 | Section: "__llvm_prf_cnts" , K: SectionKind::getData(), |
2908 | CsectProp: XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD), |
2909 | /*MultiSymbolsAllowed*/ true); |
2910 | |
2911 | OutStreamer->switchSection(Section: CntsSection); |
2912 | if (OutContext.hasXCOFFSection( |
2913 | Section: "__llvm_prf_data" , |
2914 | CsectProp: XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD))) { |
2915 | MCSymbol *S = OutContext.getOrCreateSymbol(Name: "__llvm_prf_data[RW]" ); |
2916 | OutStreamer->emitXCOFFRefDirective(Symbol: S); |
2917 | } |
2918 | if (OutContext.hasXCOFFSection( |
2919 | Section: "__llvm_prf_names" , |
2920 | CsectProp: XCOFF::CsectProperties(XCOFF::XMC_RO, XCOFF::XTY_SD))) { |
2921 | MCSymbol *S = OutContext.getOrCreateSymbol(Name: "__llvm_prf_names[RO]" ); |
2922 | OutStreamer->emitXCOFFRefDirective(Symbol: S); |
2923 | } |
2924 | if (OutContext.hasXCOFFSection( |
2925 | Section: "__llvm_prf_vnds" , |
2926 | CsectProp: XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD))) { |
2927 | MCSymbol *S = OutContext.getOrCreateSymbol(Name: "__llvm_prf_vnds[RW]" ); |
2928 | OutStreamer->emitXCOFFRefDirective(Symbol: S); |
2929 | } |
2930 | } |
2931 | } |
2932 | |
2933 | void PPCAIXAsmPrinter::emitEndOfAsmFile(Module &M) { |
2934 | // If there are no functions and there are no toc-data definitions in this |
2935 | // module, we will never need to reference the TOC base. |
2936 | if (M.empty() && TOCDataGlobalVars.empty()) |
2937 | return; |
2938 | |
2939 | emitPGORefs(M); |
2940 | |
2941 | // Switch to section to emit TOC base. |
2942 | OutStreamer->switchSection(Section: getObjFileLowering().getTOCBaseSection()); |
2943 | |
2944 | PPCTargetStreamer *TS = |
2945 | static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer()); |
2946 | |
2947 | for (auto &I : TOC) { |
2948 | MCSectionXCOFF *TCEntry; |
2949 | // Setup the csect for the current TC entry. If the variant kind is |
2950 | // VK_PPC_AIX_TLSGDM the entry represents the region handle, we create a |
2951 | // new symbol to prefix the name with a dot. |
2952 | if (I.first.second == MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSGDM) { |
2953 | SmallString<128> Name; |
2954 | StringRef Prefix = "." ; |
2955 | Name += Prefix; |
2956 | Name += cast<MCSymbolXCOFF>(Val: I.first.first)->getSymbolTableName(); |
2957 | MCSymbol *S = OutContext.getOrCreateSymbol(Name); |
2958 | TCEntry = cast<MCSectionXCOFF>( |
2959 | Val: getObjFileLowering().getSectionForTOCEntry(S, TM)); |
2960 | } else { |
2961 | TCEntry = cast<MCSectionXCOFF>( |
2962 | Val: getObjFileLowering().getSectionForTOCEntry(S: I.first.first, TM)); |
2963 | } |
2964 | OutStreamer->switchSection(Section: TCEntry); |
2965 | |
2966 | OutStreamer->emitLabel(Symbol: I.second); |
2967 | TS->emitTCEntry(S: *I.first.first, Kind: I.first.second); |
2968 | } |
2969 | |
2970 | // Traverse the list of global variables twice, emitting all of the |
2971 | // non-common global variables before the common ones, as emitting a |
2972 | // .comm directive changes the scope from .toc to the common symbol. |
2973 | for (const auto *GV : TOCDataGlobalVars) { |
2974 | if (!GV->hasCommonLinkage()) |
2975 | emitGlobalVariableHelper(GV); |
2976 | } |
2977 | for (const auto *GV : TOCDataGlobalVars) { |
2978 | if (GV->hasCommonLinkage()) |
2979 | emitGlobalVariableHelper(GV); |
2980 | } |
2981 | } |
2982 | |
2983 | bool PPCAIXAsmPrinter::doInitialization(Module &M) { |
2984 | const bool Result = PPCAsmPrinter::doInitialization(M); |
2985 | |
2986 | auto setCsectAlignment = [this](const GlobalObject *GO) { |
2987 | // Declarations have 0 alignment which is set by default. |
2988 | if (GO->isDeclarationForLinker()) |
2989 | return; |
2990 | |
2991 | SectionKind GOKind = getObjFileLowering().getKindForGlobal(GO, TM); |
2992 | MCSectionXCOFF *Csect = cast<MCSectionXCOFF>( |
2993 | Val: getObjFileLowering().SectionForGlobal(GO, Kind: GOKind, TM)); |
2994 | |
2995 | Align GOAlign = getGVAlignment(GV: GO, DL: GO->getParent()->getDataLayout()); |
2996 | Csect->ensureMinAlignment(MinAlignment: GOAlign); |
2997 | }; |
2998 | |
2999 | // For all TLS variables, calculate their corresponding addresses and store |
3000 | // them into TLSVarsToAddressMapping, which will be used to determine whether |
3001 | // or not local-exec TLS variables require special assembly printing. |
3002 | uint64_t TLSVarAddress = 0; |
3003 | auto DL = M.getDataLayout(); |
3004 | for (const auto &G : M.globals()) { |
3005 | if (G.isThreadLocal() && !G.isDeclaration()) { |
3006 | TLSVarAddress = alignTo(Size: TLSVarAddress, A: getGVAlignment(GV: &G, DL)); |
3007 | TLSVarsToAddressMapping[&G] = TLSVarAddress; |
3008 | TLSVarAddress += DL.getTypeAllocSize(Ty: G.getValueType()); |
3009 | } |
3010 | } |
3011 | |
3012 | // We need to know, up front, the alignment of csects for the assembly path, |
3013 | // because once a .csect directive gets emitted, we could not change the |
3014 | // alignment value on it. |
3015 | for (const auto &G : M.globals()) { |
3016 | if (isSpecialLLVMGlobalArrayToSkip(GV: &G)) |
3017 | continue; |
3018 | |
3019 | if (isSpecialLLVMGlobalArrayForStaticInit(GV: &G)) { |
3020 | // Generate a format indicator and a unique module id to be a part of |
3021 | // the sinit and sterm function names. |
3022 | if (FormatIndicatorAndUniqueModId.empty()) { |
3023 | std::string UniqueModuleId = getUniqueModuleId(M: &M); |
3024 | if (UniqueModuleId != "" ) |
3025 | // TODO: Use source file full path to generate the unique module id |
3026 | // and add a format indicator as a part of function name in case we |
3027 | // will support more than one format. |
3028 | FormatIndicatorAndUniqueModId = "clang_" + UniqueModuleId.substr(pos: 1); |
3029 | else { |
3030 | // Use threadId, Pid, and current time as the unique module id when we |
3031 | // cannot generate one based on a module's strong external symbols. |
3032 | auto CurTime = |
3033 | std::chrono::duration_cast<std::chrono::nanoseconds>( |
3034 | d: std::chrono::steady_clock::now().time_since_epoch()) |
3035 | .count(); |
3036 | FormatIndicatorAndUniqueModId = |
3037 | "clangPidTidTime_" + llvm::itostr(X: sys::Process::getProcessId()) + |
3038 | "_" + llvm::itostr(X: llvm::get_threadid()) + "_" + |
3039 | llvm::itostr(X: CurTime); |
3040 | } |
3041 | } |
3042 | |
3043 | emitSpecialLLVMGlobal(GV: &G); |
3044 | continue; |
3045 | } |
3046 | |
3047 | setCsectAlignment(&G); |
3048 | std::optional<CodeModel::Model> OptionalCodeModel = G.getCodeModel(); |
3049 | if (OptionalCodeModel) |
3050 | setOptionalCodeModel(XSym: cast<MCSymbolXCOFF>(Val: getSymbol(GV: &G)), |
3051 | CM: *OptionalCodeModel); |
3052 | } |
3053 | |
3054 | for (const auto &F : M) |
3055 | setCsectAlignment(&F); |
3056 | |
3057 | // Construct an aliasing list for each GlobalObject. |
3058 | for (const auto &Alias : M.aliases()) { |
3059 | const GlobalObject *Aliasee = Alias.getAliaseeObject(); |
3060 | if (!Aliasee) |
3061 | report_fatal_error( |
3062 | reason: "alias without a base object is not yet supported on AIX" ); |
3063 | |
3064 | if (Aliasee->hasCommonLinkage()) { |
3065 | report_fatal_error(reason: "Aliases to common variables are not allowed on AIX:" |
3066 | "\n\tAlias attribute for " + |
3067 | Alias.getGlobalIdentifier() + |
3068 | " is invalid because " + Aliasee->getName() + |
3069 | " is common." , |
3070 | gen_crash_diag: false); |
3071 | } |
3072 | |
3073 | const GlobalVariable *GVar = |
3074 | dyn_cast_or_null<GlobalVariable>(Val: Alias.getAliaseeObject()); |
3075 | if (GVar) { |
3076 | std::optional<CodeModel::Model> OptionalCodeModel = GVar->getCodeModel(); |
3077 | if (OptionalCodeModel) |
3078 | setOptionalCodeModel(XSym: cast<MCSymbolXCOFF>(Val: getSymbol(GV: &Alias)), |
3079 | CM: *OptionalCodeModel); |
3080 | } |
3081 | |
3082 | GOAliasMap[Aliasee].push_back(Elt: &Alias); |
3083 | } |
3084 | |
3085 | return Result; |
3086 | } |
3087 | |
3088 | void PPCAIXAsmPrinter::emitInstruction(const MachineInstr *MI) { |
3089 | switch (MI->getOpcode()) { |
3090 | default: |
3091 | break; |
3092 | case PPC::TW: |
3093 | case PPC::TWI: |
3094 | case PPC::TD: |
3095 | case PPC::TDI: { |
3096 | if (MI->getNumOperands() < 5) |
3097 | break; |
3098 | const MachineOperand &LangMO = MI->getOperand(i: 3); |
3099 | const MachineOperand &ReasonMO = MI->getOperand(i: 4); |
3100 | if (!LangMO.isImm() || !ReasonMO.isImm()) |
3101 | break; |
3102 | MCSymbol *TempSym = OutContext.createNamedTempSymbol(); |
3103 | OutStreamer->emitLabel(Symbol: TempSym); |
3104 | OutStreamer->emitXCOFFExceptDirective(Symbol: CurrentFnSym, Trap: TempSym, |
3105 | Lang: LangMO.getImm(), Reason: ReasonMO.getImm(), |
3106 | FunctionSize: Subtarget->isPPC64() ? MI->getMF()->getInstructionCount() * 8 : |
3107 | MI->getMF()->getInstructionCount() * 4, |
3108 | hasDebug: MMI->hasDebugInfo()); |
3109 | break; |
3110 | } |
3111 | case PPC::GETtlsMOD32AIX: |
3112 | case PPC::GETtlsMOD64AIX: |
3113 | case PPC::GETtlsTpointer32AIX: |
3114 | case PPC::GETtlsADDR64AIX: |
3115 | case PPC::GETtlsADDR32AIX: { |
3116 | // A reference to .__tls_get_mod/.__tls_get_addr/.__get_tpointer is unknown |
3117 | // to the assembler so we need to emit an external symbol reference. |
3118 | MCSymbol *TlsGetAddr = |
3119 | createMCSymbolForTlsGetAddr(Ctx&: OutContext, MIOpc: MI->getOpcode()); |
3120 | ExtSymSDNodeSymbols.insert(Ptr: TlsGetAddr); |
3121 | break; |
3122 | } |
3123 | case PPC::BL8: |
3124 | case PPC::BL: |
3125 | case PPC::BL8_NOP: |
3126 | case PPC::BL_NOP: { |
3127 | const MachineOperand &MO = MI->getOperand(i: 0); |
3128 | if (MO.isSymbol()) { |
3129 | MCSymbolXCOFF *S = |
3130 | cast<MCSymbolXCOFF>(Val: OutContext.getOrCreateSymbol(Name: MO.getSymbolName())); |
3131 | ExtSymSDNodeSymbols.insert(Ptr: S); |
3132 | } |
3133 | } break; |
3134 | case PPC::BL_TLS: |
3135 | case PPC::BL8_TLS: |
3136 | case PPC::BL8_TLS_: |
3137 | case PPC::BL8_NOP_TLS: |
3138 | report_fatal_error(reason: "TLS call not yet implemented" ); |
3139 | case PPC::TAILB: |
3140 | case PPC::TAILB8: |
3141 | case PPC::TAILBA: |
3142 | case PPC::TAILBA8: |
3143 | case PPC::TAILBCTR: |
3144 | case PPC::TAILBCTR8: |
3145 | if (MI->getOperand(i: 0).isSymbol()) |
3146 | report_fatal_error(reason: "Tail call for extern symbol not yet supported." ); |
3147 | break; |
3148 | case PPC::DST: |
3149 | case PPC::DST64: |
3150 | case PPC::DSTT: |
3151 | case PPC::DSTT64: |
3152 | case PPC::DSTST: |
3153 | case PPC::DSTST64: |
3154 | case PPC::DSTSTT: |
3155 | case PPC::DSTSTT64: |
3156 | EmitToStreamer( |
3157 | *OutStreamer, |
3158 | MCInstBuilder(PPC::ORI).addReg(PPC::R0).addReg(PPC::R0).addImm(0)); |
3159 | return; |
3160 | } |
3161 | return PPCAsmPrinter::emitInstruction(MI); |
3162 | } |
3163 | |
3164 | bool PPCAIXAsmPrinter::doFinalization(Module &M) { |
3165 | // Do streamer related finalization for DWARF. |
3166 | if (!MAI->usesDwarfFileAndLocDirectives() && MMI->hasDebugInfo()) |
3167 | OutStreamer->doFinalizationAtSectionEnd( |
3168 | Section: OutStreamer->getContext().getObjectFileInfo()->getTextSection()); |
3169 | |
3170 | for (MCSymbol *Sym : ExtSymSDNodeSymbols) |
3171 | OutStreamer->emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_Extern); |
3172 | return PPCAsmPrinter::doFinalization(M); |
3173 | } |
3174 | |
3175 | static unsigned mapToSinitPriority(int P) { |
3176 | if (P < 0 || P > 65535) |
3177 | report_fatal_error(reason: "invalid init priority" ); |
3178 | |
3179 | if (P <= 20) |
3180 | return P; |
3181 | |
3182 | if (P < 81) |
3183 | return 20 + (P - 20) * 16; |
3184 | |
3185 | if (P <= 1124) |
3186 | return 1004 + (P - 81); |
3187 | |
3188 | if (P < 64512) |
3189 | return 2047 + (P - 1124) * 33878; |
3190 | |
3191 | return 2147482625u + (P - 64512); |
3192 | } |
3193 | |
3194 | static std::string convertToSinitPriority(int Priority) { |
3195 | // This helper function converts clang init priority to values used in sinit |
3196 | // and sterm functions. |
3197 | // |
3198 | // The conversion strategies are: |
3199 | // We map the reserved clang/gnu priority range [0, 100] into the sinit/sterm |
3200 | // reserved priority range [0, 1023] by |
3201 | // - directly mapping the first 21 and the last 20 elements of the ranges |
3202 | // - linear interpolating the intermediate values with a step size of 16. |
3203 | // |
3204 | // We map the non reserved clang/gnu priority range of [101, 65535] into the |
3205 | // sinit/sterm priority range [1024, 2147483648] by: |
3206 | // - directly mapping the first and the last 1024 elements of the ranges |
3207 | // - linear interpolating the intermediate values with a step size of 33878. |
3208 | unsigned int P = mapToSinitPriority(P: Priority); |
3209 | |
3210 | std::string PrioritySuffix; |
3211 | llvm::raw_string_ostream os(PrioritySuffix); |
3212 | os << llvm::format_hex_no_prefix(N: P, Width: 8); |
3213 | os.flush(); |
3214 | return PrioritySuffix; |
3215 | } |
3216 | |
3217 | void PPCAIXAsmPrinter::emitXXStructorList(const DataLayout &DL, |
3218 | const Constant *List, bool IsCtor) { |
3219 | SmallVector<Structor, 8> Structors; |
3220 | preprocessXXStructorList(DL, List, Structors); |
3221 | if (Structors.empty()) |
3222 | return; |
3223 | |
3224 | unsigned Index = 0; |
3225 | for (Structor &S : Structors) { |
3226 | if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(Val: S.Func)) |
3227 | S.Func = CE->getOperand(i_nocapture: 0); |
3228 | |
3229 | llvm::GlobalAlias::create( |
3230 | Linkage: GlobalValue::ExternalLinkage, |
3231 | Name: (IsCtor ? llvm::Twine("__sinit" ) : llvm::Twine("__sterm" )) + |
3232 | llvm::Twine(convertToSinitPriority(Priority: S.Priority)) + |
3233 | llvm::Twine("_" , FormatIndicatorAndUniqueModId) + |
3234 | llvm::Twine("_" , llvm::utostr(X: Index++)), |
3235 | Aliasee: cast<Function>(Val: S.Func)); |
3236 | } |
3237 | } |
3238 | |
3239 | void PPCAIXAsmPrinter::emitTTypeReference(const GlobalValue *GV, |
3240 | unsigned Encoding) { |
3241 | if (GV) { |
3242 | TOCEntryType GlobalType = TOCType_GlobalInternal; |
3243 | GlobalValue::LinkageTypes Linkage = GV->getLinkage(); |
3244 | if (Linkage == GlobalValue::ExternalLinkage || |
3245 | Linkage == GlobalValue::AvailableExternallyLinkage || |
3246 | Linkage == GlobalValue::ExternalWeakLinkage) |
3247 | GlobalType = TOCType_GlobalExternal; |
3248 | MCSymbol *TypeInfoSym = TM.getSymbol(GV); |
3249 | MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(Sym: TypeInfoSym, Type: GlobalType); |
3250 | const MCSymbol *TOCBaseSym = |
3251 | cast<MCSectionXCOFF>(Val: getObjFileLowering().getTOCBaseSection()) |
3252 | ->getQualNameSymbol(); |
3253 | auto &Ctx = OutStreamer->getContext(); |
3254 | const MCExpr *Exp = |
3255 | MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: TOCEntry, Ctx), |
3256 | RHS: MCSymbolRefExpr::create(Symbol: TOCBaseSym, Ctx), Ctx); |
3257 | OutStreamer->emitValue(Value: Exp, Size: GetSizeOfEncodedValue(Encoding)); |
3258 | } else |
3259 | OutStreamer->emitIntValue(Value: 0, Size: GetSizeOfEncodedValue(Encoding)); |
3260 | } |
3261 | |
3262 | // Return a pass that prints the PPC assembly code for a MachineFunction to the |
3263 | // given output stream. |
3264 | static AsmPrinter * |
3265 | createPPCAsmPrinterPass(TargetMachine &tm, |
3266 | std::unique_ptr<MCStreamer> &&Streamer) { |
3267 | if (tm.getTargetTriple().isOSAIX()) |
3268 | return new PPCAIXAsmPrinter(tm, std::move(Streamer)); |
3269 | |
3270 | return new PPCLinuxAsmPrinter(tm, std::move(Streamer)); |
3271 | } |
3272 | |
3273 | void PPCAIXAsmPrinter::emitModuleCommandLines(Module &M) { |
3274 | const NamedMDNode *NMD = M.getNamedMetadata(Name: "llvm.commandline" ); |
3275 | if (!NMD || !NMD->getNumOperands()) |
3276 | return; |
3277 | |
3278 | std::string S; |
3279 | raw_string_ostream RSOS(S); |
3280 | for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { |
3281 | const MDNode *N = NMD->getOperand(i); |
3282 | assert(N->getNumOperands() == 1 && |
3283 | "llvm.commandline metadata entry can have only one operand" ); |
3284 | const MDString *MDS = cast<MDString>(Val: N->getOperand(I: 0)); |
3285 | // Add "@(#)" to support retrieving the command line information with the |
3286 | // AIX "what" command |
3287 | RSOS << "@(#)opt " << MDS->getString() << "\n" ; |
3288 | RSOS.write(C: '\0'); |
3289 | } |
3290 | OutStreamer->emitXCOFFCInfoSym(Name: ".GCC.command.line" , Metadata: RSOS.str()); |
3291 | } |
3292 | |
3293 | // Force static initialization. |
3294 | extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializePowerPCAsmPrinter() { |
3295 | TargetRegistry::RegisterAsmPrinter(T&: getThePPC32Target(), |
3296 | Fn: createPPCAsmPrinterPass); |
3297 | TargetRegistry::RegisterAsmPrinter(T&: getThePPC32LETarget(), |
3298 | Fn: createPPCAsmPrinterPass); |
3299 | TargetRegistry::RegisterAsmPrinter(T&: getThePPC64Target(), |
3300 | Fn: createPPCAsmPrinterPass); |
3301 | TargetRegistry::RegisterAsmPrinter(T&: getThePPC64LETarget(), |
3302 | Fn: createPPCAsmPrinterPass); |
3303 | } |
3304 | |