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