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