1 | //===- lib/MC/MCStreamer.cpp - Streaming Machine Code Output --------------===// |
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 | #include "llvm/MC/MCStreamer.h" |
10 | #include "llvm/ADT/SmallString.h" |
11 | #include "llvm/ADT/StringRef.h" |
12 | #include "llvm/ADT/Twine.h" |
13 | #include "llvm/BinaryFormat/COFF.h" |
14 | #include "llvm/BinaryFormat/MachO.h" |
15 | #include "llvm/DebugInfo/CodeView/SymbolRecord.h" |
16 | #include "llvm/MC/MCAsmBackend.h" |
17 | #include "llvm/MC/MCAsmInfo.h" |
18 | #include "llvm/MC/MCCodeView.h" |
19 | #include "llvm/MC/MCContext.h" |
20 | #include "llvm/MC/MCDwarf.h" |
21 | #include "llvm/MC/MCExpr.h" |
22 | #include "llvm/MC/MCInst.h" |
23 | #include "llvm/MC/MCInstPrinter.h" |
24 | #include "llvm/MC/MCObjectFileInfo.h" |
25 | #include "llvm/MC/MCPseudoProbe.h" |
26 | #include "llvm/MC/MCRegister.h" |
27 | #include "llvm/MC/MCRegisterInfo.h" |
28 | #include "llvm/MC/MCSection.h" |
29 | #include "llvm/MC/MCSectionCOFF.h" |
30 | #include "llvm/MC/MCSymbol.h" |
31 | #include "llvm/MC/MCWin64EH.h" |
32 | #include "llvm/MC/MCWinEH.h" |
33 | #include "llvm/Support/Casting.h" |
34 | #include "llvm/Support/ErrorHandling.h" |
35 | #include "llvm/Support/LEB128.h" |
36 | #include "llvm/Support/MathExtras.h" |
37 | #include "llvm/Support/raw_ostream.h" |
38 | #include <cassert> |
39 | #include <cstdint> |
40 | #include <cstdlib> |
41 | #include <optional> |
42 | #include <utility> |
43 | |
44 | using namespace llvm; |
45 | |
46 | MCTargetStreamer::MCTargetStreamer(MCStreamer &S) : Streamer(S) { |
47 | S.setTargetStreamer(this); |
48 | } |
49 | |
50 | // Pin the vtables to this file. |
51 | MCTargetStreamer::~MCTargetStreamer() = default; |
52 | |
53 | void MCTargetStreamer::emitLabel(MCSymbol *Symbol) {} |
54 | |
55 | void MCTargetStreamer::finish() {} |
56 | |
57 | void MCTargetStreamer::emitConstantPools() {} |
58 | |
59 | void MCTargetStreamer::changeSection(const MCSection *CurSection, |
60 | MCSection *Section, |
61 | const MCExpr *Subsection, |
62 | raw_ostream &OS) { |
63 | Section->printSwitchToSection(MAI: *Streamer.getContext().getAsmInfo(), |
64 | T: Streamer.getContext().getTargetTriple(), OS, |
65 | Subsection); |
66 | } |
67 | |
68 | void MCTargetStreamer::emitDwarfFileDirective(StringRef Directive) { |
69 | Streamer.emitRawText(String: Directive); |
70 | } |
71 | |
72 | void MCTargetStreamer::emitValue(const MCExpr *Value) { |
73 | SmallString<128> Str; |
74 | raw_svector_ostream OS(Str); |
75 | |
76 | Value->print(OS, MAI: Streamer.getContext().getAsmInfo()); |
77 | Streamer.emitRawText(String: OS.str()); |
78 | } |
79 | |
80 | void MCTargetStreamer::emitRawBytes(StringRef Data) { |
81 | const MCAsmInfo *MAI = Streamer.getContext().getAsmInfo(); |
82 | const char *Directive = MAI->getData8bitsDirective(); |
83 | for (const unsigned char C : Data.bytes()) { |
84 | SmallString<128> Str; |
85 | raw_svector_ostream OS(Str); |
86 | |
87 | OS << Directive << (unsigned)C; |
88 | Streamer.emitRawText(String: OS.str()); |
89 | } |
90 | } |
91 | |
92 | void MCTargetStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {} |
93 | |
94 | MCStreamer::MCStreamer(MCContext &Ctx) |
95 | : Context(Ctx), CurrentWinFrameInfo(nullptr), |
96 | CurrentProcWinFrameInfoStartIndex(0), UseAssemblerInfoForParsing(false) { |
97 | SectionStack.push_back(Elt: std::pair<MCSectionSubPair, MCSectionSubPair>()); |
98 | } |
99 | |
100 | MCStreamer::~MCStreamer() = default; |
101 | |
102 | void MCStreamer::reset() { |
103 | DwarfFrameInfos.clear(); |
104 | CurrentWinFrameInfo = nullptr; |
105 | WinFrameInfos.clear(); |
106 | SymbolOrdering.clear(); |
107 | SectionStack.clear(); |
108 | SectionStack.push_back(Elt: std::pair<MCSectionSubPair, MCSectionSubPair>()); |
109 | } |
110 | |
111 | raw_ostream &MCStreamer::() { |
112 | // By default, discard comments. |
113 | return nulls(); |
114 | } |
115 | |
116 | unsigned MCStreamer::getNumFrameInfos() { return DwarfFrameInfos.size(); } |
117 | ArrayRef<MCDwarfFrameInfo> MCStreamer::getDwarfFrameInfos() const { |
118 | return DwarfFrameInfos; |
119 | } |
120 | |
121 | void MCStreamer::(const Twine &T, bool TabPrefix) {} |
122 | |
123 | void MCStreamer::(const Twine &T) {} |
124 | void MCStreamer::() {} |
125 | |
126 | void MCStreamer::generateCompactUnwindEncodings(MCAsmBackend *MAB) { |
127 | for (auto &FI : DwarfFrameInfos) |
128 | FI.CompactUnwindEncoding = |
129 | (MAB ? MAB->generateCompactUnwindEncoding(FI: &FI, Ctxt: &Context) : 0); |
130 | } |
131 | |
132 | /// EmitIntValue - Special case of EmitValue that avoids the client having to |
133 | /// pass in a MCExpr for constant integers. |
134 | void MCStreamer::emitIntValue(uint64_t Value, unsigned Size) { |
135 | assert(1 <= Size && Size <= 8 && "Invalid size" ); |
136 | assert((isUIntN(8 * Size, Value) || isIntN(8 * Size, Value)) && |
137 | "Invalid size" ); |
138 | const bool IsLittleEndian = Context.getAsmInfo()->isLittleEndian(); |
139 | uint64_t Swapped = support::endian::byte_swap( |
140 | value: Value, endian: IsLittleEndian ? llvm::endianness::little : llvm::endianness::big); |
141 | unsigned Index = IsLittleEndian ? 0 : 8 - Size; |
142 | emitBytes(Data: StringRef(reinterpret_cast<char *>(&Swapped) + Index, Size)); |
143 | } |
144 | void MCStreamer::emitIntValue(APInt Value) { |
145 | if (Value.getNumWords() == 1) { |
146 | emitIntValue(Value: Value.getLimitedValue(), Size: Value.getBitWidth() / 8); |
147 | return; |
148 | } |
149 | |
150 | const bool IsLittleEndianTarget = Context.getAsmInfo()->isLittleEndian(); |
151 | const bool ShouldSwap = sys::IsLittleEndianHost != IsLittleEndianTarget; |
152 | const APInt Swapped = ShouldSwap ? Value.byteSwap() : Value; |
153 | const unsigned Size = Value.getBitWidth() / 8; |
154 | SmallString<10> Tmp; |
155 | Tmp.resize(N: Size); |
156 | StoreIntToMemory(IntVal: Swapped, Dst: reinterpret_cast<uint8_t *>(Tmp.data()), StoreBytes: Size); |
157 | emitBytes(Data: Tmp.str()); |
158 | } |
159 | |
160 | /// EmitULEB128IntValue - Special case of EmitULEB128Value that avoids the |
161 | /// client having to pass in a MCExpr for constant integers. |
162 | unsigned MCStreamer::emitULEB128IntValue(uint64_t Value, unsigned PadTo) { |
163 | SmallString<128> Tmp; |
164 | raw_svector_ostream OSE(Tmp); |
165 | encodeULEB128(Value, OS&: OSE, PadTo); |
166 | emitBytes(Data: OSE.str()); |
167 | return Tmp.size(); |
168 | } |
169 | |
170 | /// EmitSLEB128IntValue - Special case of EmitSLEB128Value that avoids the |
171 | /// client having to pass in a MCExpr for constant integers. |
172 | unsigned MCStreamer::emitSLEB128IntValue(int64_t Value) { |
173 | SmallString<128> Tmp; |
174 | raw_svector_ostream OSE(Tmp); |
175 | encodeSLEB128(Value, OS&: OSE); |
176 | emitBytes(Data: OSE.str()); |
177 | return Tmp.size(); |
178 | } |
179 | |
180 | void MCStreamer::emitValue(const MCExpr *Value, unsigned Size, SMLoc Loc) { |
181 | emitValueImpl(Value, Size, Loc); |
182 | } |
183 | |
184 | void MCStreamer::emitSymbolValue(const MCSymbol *Sym, unsigned Size, |
185 | bool IsSectionRelative) { |
186 | assert((!IsSectionRelative || Size == 4) && |
187 | "SectionRelative value requires 4-bytes" ); |
188 | |
189 | if (!IsSectionRelative) |
190 | emitValueImpl(Value: MCSymbolRefExpr::create(Symbol: Sym, Ctx&: getContext()), Size); |
191 | else |
192 | emitCOFFSecRel32(Symbol: Sym, /*Offset=*/0); |
193 | } |
194 | |
195 | void MCStreamer::emitDTPRel64Value(const MCExpr *Value) { |
196 | report_fatal_error(reason: "unsupported directive in streamer" ); |
197 | } |
198 | |
199 | void MCStreamer::emitDTPRel32Value(const MCExpr *Value) { |
200 | report_fatal_error(reason: "unsupported directive in streamer" ); |
201 | } |
202 | |
203 | void MCStreamer::emitTPRel64Value(const MCExpr *Value) { |
204 | report_fatal_error(reason: "unsupported directive in streamer" ); |
205 | } |
206 | |
207 | void MCStreamer::emitTPRel32Value(const MCExpr *Value) { |
208 | report_fatal_error(reason: "unsupported directive in streamer" ); |
209 | } |
210 | |
211 | void MCStreamer::emitGPRel64Value(const MCExpr *Value) { |
212 | report_fatal_error(reason: "unsupported directive in streamer" ); |
213 | } |
214 | |
215 | void MCStreamer::emitGPRel32Value(const MCExpr *Value) { |
216 | report_fatal_error(reason: "unsupported directive in streamer" ); |
217 | } |
218 | |
219 | /// Emit NumBytes bytes worth of the value specified by FillValue. |
220 | /// This implements directives such as '.space'. |
221 | void MCStreamer::emitFill(uint64_t NumBytes, uint8_t FillValue) { |
222 | if (NumBytes) |
223 | emitFill(NumBytes: *MCConstantExpr::create(Value: NumBytes, Ctx&: getContext()), FillValue); |
224 | } |
225 | |
226 | void llvm::MCStreamer::emitNops(int64_t NumBytes, int64_t ControlledNopLen, |
227 | llvm::SMLoc, const MCSubtargetInfo& STI) {} |
228 | |
229 | /// The implementation in this class just redirects to emitFill. |
230 | void MCStreamer::emitZeros(uint64_t NumBytes) { emitFill(NumBytes, FillValue: 0); } |
231 | |
232 | Expected<unsigned> MCStreamer::tryEmitDwarfFileDirective( |
233 | unsigned FileNo, StringRef Directory, StringRef Filename, |
234 | std::optional<MD5::MD5Result> Checksum, std::optional<StringRef> Source, |
235 | unsigned CUID) { |
236 | return getContext().getDwarfFile(Directory, FileName: Filename, FileNumber: FileNo, Checksum, |
237 | Source, CUID); |
238 | } |
239 | |
240 | void MCStreamer::emitDwarfFile0Directive(StringRef Directory, |
241 | StringRef Filename, |
242 | std::optional<MD5::MD5Result> Checksum, |
243 | std::optional<StringRef> Source, |
244 | unsigned CUID) { |
245 | getContext().setMCLineTableRootFile(CUID, CompilationDir: Directory, Filename, Checksum, |
246 | Source); |
247 | } |
248 | |
249 | void MCStreamer::emitCFIBKeyFrame() { |
250 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
251 | if (!CurFrame) |
252 | return; |
253 | CurFrame->IsBKeyFrame = true; |
254 | } |
255 | |
256 | void MCStreamer::emitCFIMTETaggedFrame() { |
257 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
258 | if (!CurFrame) |
259 | return; |
260 | CurFrame->IsMTETaggedFrame = true; |
261 | } |
262 | |
263 | void MCStreamer::emitDwarfLocDirective(unsigned FileNo, unsigned Line, |
264 | unsigned Column, unsigned Flags, |
265 | unsigned Isa, unsigned Discriminator, |
266 | StringRef FileName) { |
267 | getContext().setCurrentDwarfLoc(FileNum: FileNo, Line, Column, Flags, Isa, |
268 | Discriminator); |
269 | } |
270 | |
271 | MCSymbol *MCStreamer::getDwarfLineTableSymbol(unsigned CUID) { |
272 | MCDwarfLineTable &Table = getContext().getMCDwarfLineTable(CUID); |
273 | if (!Table.getLabel()) { |
274 | StringRef Prefix = Context.getAsmInfo()->getPrivateGlobalPrefix(); |
275 | Table.setLabel( |
276 | Context.getOrCreateSymbol(Name: Prefix + "line_table_start" + Twine(CUID))); |
277 | } |
278 | return Table.getLabel(); |
279 | } |
280 | |
281 | bool MCStreamer::hasUnfinishedDwarfFrameInfo() { |
282 | return !FrameInfoStack.empty(); |
283 | } |
284 | |
285 | MCDwarfFrameInfo *MCStreamer::getCurrentDwarfFrameInfo() { |
286 | if (!hasUnfinishedDwarfFrameInfo()) { |
287 | getContext().reportError(L: getStartTokLoc(), |
288 | Msg: "this directive must appear between " |
289 | ".cfi_startproc and .cfi_endproc directives" ); |
290 | return nullptr; |
291 | } |
292 | return &DwarfFrameInfos[FrameInfoStack.back().first]; |
293 | } |
294 | |
295 | bool MCStreamer::emitCVFileDirective(unsigned FileNo, StringRef Filename, |
296 | ArrayRef<uint8_t> Checksum, |
297 | unsigned ChecksumKind) { |
298 | return getContext().getCVContext().addFile(OS&: *this, FileNumber: FileNo, Filename, ChecksumBytes: Checksum, |
299 | ChecksumKind); |
300 | } |
301 | |
302 | bool MCStreamer::emitCVFuncIdDirective(unsigned FunctionId) { |
303 | return getContext().getCVContext().recordFunctionId(FuncId: FunctionId); |
304 | } |
305 | |
306 | bool MCStreamer::emitCVInlineSiteIdDirective(unsigned FunctionId, |
307 | unsigned IAFunc, unsigned IAFile, |
308 | unsigned IALine, unsigned IACol, |
309 | SMLoc Loc) { |
310 | if (getContext().getCVContext().getCVFunctionInfo(FuncId: IAFunc) == nullptr) { |
311 | getContext().reportError(L: Loc, Msg: "parent function id not introduced by " |
312 | ".cv_func_id or .cv_inline_site_id" ); |
313 | return true; |
314 | } |
315 | |
316 | return getContext().getCVContext().recordInlinedCallSiteId( |
317 | FuncId: FunctionId, IAFunc, IAFile, IALine, IACol); |
318 | } |
319 | |
320 | void MCStreamer::emitCVLocDirective(unsigned FunctionId, unsigned FileNo, |
321 | unsigned Line, unsigned Column, |
322 | bool PrologueEnd, bool IsStmt, |
323 | StringRef FileName, SMLoc Loc) {} |
324 | |
325 | bool MCStreamer::checkCVLocSection(unsigned FuncId, unsigned FileNo, |
326 | SMLoc Loc) { |
327 | CodeViewContext &CVC = getContext().getCVContext(); |
328 | MCCVFunctionInfo *FI = CVC.getCVFunctionInfo(FuncId); |
329 | if (!FI) { |
330 | getContext().reportError( |
331 | L: Loc, Msg: "function id not introduced by .cv_func_id or .cv_inline_site_id" ); |
332 | return false; |
333 | } |
334 | |
335 | // Track the section |
336 | if (FI->Section == nullptr) |
337 | FI->Section = getCurrentSectionOnly(); |
338 | else if (FI->Section != getCurrentSectionOnly()) { |
339 | getContext().reportError( |
340 | L: Loc, |
341 | Msg: "all .cv_loc directives for a function must be in the same section" ); |
342 | return false; |
343 | } |
344 | return true; |
345 | } |
346 | |
347 | void MCStreamer::emitCVLinetableDirective(unsigned FunctionId, |
348 | const MCSymbol *Begin, |
349 | const MCSymbol *End) {} |
350 | |
351 | void MCStreamer::emitCVInlineLinetableDirective(unsigned PrimaryFunctionId, |
352 | unsigned SourceFileId, |
353 | unsigned SourceLineNum, |
354 | const MCSymbol *FnStartSym, |
355 | const MCSymbol *FnEndSym) {} |
356 | |
357 | /// Only call this on endian-specific types like ulittle16_t and little32_t, or |
358 | /// structs composed of them. |
359 | template <typename T> |
360 | static void copyBytesForDefRange(SmallString<20> &BytePrefix, |
361 | codeview::SymbolKind SymKind, |
362 | const T &) { |
363 | BytePrefix.resize(N: 2 + sizeof(T)); |
364 | codeview::ulittle16_t SymKindLE = codeview::ulittle16_t(SymKind); |
365 | memcpy(dest: &BytePrefix[0], src: &SymKindLE, n: 2); |
366 | memcpy(&BytePrefix[2], &DefRangeHeader, sizeof(T)); |
367 | } |
368 | |
369 | void MCStreamer::emitCVDefRangeDirective( |
370 | ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, |
371 | StringRef FixedSizePortion) {} |
372 | |
373 | void MCStreamer::( |
374 | ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, |
375 | codeview::DefRangeRegisterRelHeader DRHdr) { |
376 | SmallString<20> BytePrefix; |
377 | copyBytesForDefRange(BytePrefix, SymKind: codeview::S_DEFRANGE_REGISTER_REL, DefRangeHeader: DRHdr); |
378 | emitCVDefRangeDirective(Ranges, FixedSizePortion: BytePrefix); |
379 | } |
380 | |
381 | void MCStreamer::( |
382 | ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, |
383 | codeview::DefRangeSubfieldRegisterHeader DRHdr) { |
384 | SmallString<20> BytePrefix; |
385 | copyBytesForDefRange(BytePrefix, SymKind: codeview::S_DEFRANGE_SUBFIELD_REGISTER, |
386 | DefRangeHeader: DRHdr); |
387 | emitCVDefRangeDirective(Ranges, FixedSizePortion: BytePrefix); |
388 | } |
389 | |
390 | void MCStreamer::( |
391 | ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, |
392 | codeview::DefRangeRegisterHeader DRHdr) { |
393 | SmallString<20> BytePrefix; |
394 | copyBytesForDefRange(BytePrefix, SymKind: codeview::S_DEFRANGE_REGISTER, DefRangeHeader: DRHdr); |
395 | emitCVDefRangeDirective(Ranges, FixedSizePortion: BytePrefix); |
396 | } |
397 | |
398 | void MCStreamer::( |
399 | ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, |
400 | codeview::DefRangeFramePointerRelHeader DRHdr) { |
401 | SmallString<20> BytePrefix; |
402 | copyBytesForDefRange(BytePrefix, SymKind: codeview::S_DEFRANGE_FRAMEPOINTER_REL, |
403 | DefRangeHeader: DRHdr); |
404 | emitCVDefRangeDirective(Ranges, FixedSizePortion: BytePrefix); |
405 | } |
406 | |
407 | void MCStreamer::emitEHSymAttributes(const MCSymbol *Symbol, |
408 | MCSymbol *EHSymbol) { |
409 | } |
410 | |
411 | void MCStreamer::initSections(bool NoExecStack, const MCSubtargetInfo &STI) { |
412 | switchSection(Section: getContext().getObjectFileInfo()->getTextSection()); |
413 | } |
414 | |
415 | void MCStreamer::assignFragment(MCSymbol *Symbol, MCFragment *Fragment) { |
416 | assert(Fragment); |
417 | Symbol->setFragment(Fragment); |
418 | |
419 | // As we emit symbols into a section, track the order so that they can |
420 | // be sorted upon later. Zero is reserved to mean 'unemitted'. |
421 | SymbolOrdering[Symbol] = 1 + SymbolOrdering.size(); |
422 | } |
423 | |
424 | void MCStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) { |
425 | Symbol->redefineIfPossible(); |
426 | |
427 | if (!Symbol->isUndefined() || Symbol->isVariable()) |
428 | return getContext().reportError(L: Loc, Msg: "symbol '" + Twine(Symbol->getName()) + |
429 | "' is already defined" ); |
430 | |
431 | assert(!Symbol->isVariable() && "Cannot emit a variable symbol!" ); |
432 | assert(getCurrentSectionOnly() && "Cannot emit before setting section!" ); |
433 | assert(!Symbol->getFragment() && "Unexpected fragment on symbol data!" ); |
434 | assert(Symbol->isUndefined() && "Cannot define a symbol twice!" ); |
435 | |
436 | Symbol->setFragment(&getCurrentSectionOnly()->getDummyFragment()); |
437 | |
438 | MCTargetStreamer *TS = getTargetStreamer(); |
439 | if (TS) |
440 | TS->emitLabel(Symbol); |
441 | } |
442 | |
443 | void MCStreamer::emitConditionalAssignment(MCSymbol *Symbol, |
444 | const MCExpr *Value) {} |
445 | |
446 | void MCStreamer::emitCFISections(bool EH, bool Debug) {} |
447 | |
448 | void MCStreamer::emitCFIStartProc(bool IsSimple, SMLoc Loc) { |
449 | if (!FrameInfoStack.empty() && |
450 | getCurrentSectionOnly() == FrameInfoStack.back().second) |
451 | return getContext().reportError( |
452 | L: Loc, Msg: "starting new .cfi frame before finishing the previous one" ); |
453 | |
454 | MCDwarfFrameInfo Frame; |
455 | Frame.IsSimple = IsSimple; |
456 | emitCFIStartProcImpl(Frame); |
457 | |
458 | const MCAsmInfo* MAI = Context.getAsmInfo(); |
459 | if (MAI) { |
460 | for (const MCCFIInstruction& Inst : MAI->getInitialFrameState()) { |
461 | if (Inst.getOperation() == MCCFIInstruction::OpDefCfa || |
462 | Inst.getOperation() == MCCFIInstruction::OpDefCfaRegister || |
463 | Inst.getOperation() == MCCFIInstruction::OpLLVMDefAspaceCfa) { |
464 | Frame.CurrentCfaRegister = Inst.getRegister(); |
465 | } |
466 | } |
467 | } |
468 | |
469 | FrameInfoStack.emplace_back(Args: DwarfFrameInfos.size(), Args: getCurrentSectionOnly()); |
470 | DwarfFrameInfos.push_back(x: Frame); |
471 | } |
472 | |
473 | void MCStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) { |
474 | } |
475 | |
476 | void MCStreamer::emitCFIEndProc() { |
477 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
478 | if (!CurFrame) |
479 | return; |
480 | emitCFIEndProcImpl(CurFrame&: *CurFrame); |
481 | FrameInfoStack.pop_back(); |
482 | } |
483 | |
484 | void MCStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &Frame) { |
485 | // Put a dummy non-null value in Frame.End to mark that this frame has been |
486 | // closed. |
487 | Frame.End = (MCSymbol *)1; |
488 | } |
489 | |
490 | MCSymbol *MCStreamer::emitCFILabel() { |
491 | // Return a dummy non-null value so that label fields appear filled in when |
492 | // generating textual assembly. |
493 | return (MCSymbol *)1; |
494 | } |
495 | |
496 | void MCStreamer::emitCFIDefCfa(int64_t Register, int64_t Offset, SMLoc Loc) { |
497 | MCSymbol *Label = emitCFILabel(); |
498 | MCCFIInstruction Instruction = |
499 | MCCFIInstruction::cfiDefCfa(L: Label, Register, Offset, Loc); |
500 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
501 | if (!CurFrame) |
502 | return; |
503 | CurFrame->Instructions.push_back(x: Instruction); |
504 | CurFrame->CurrentCfaRegister = static_cast<unsigned>(Register); |
505 | } |
506 | |
507 | void MCStreamer::emitCFIDefCfaOffset(int64_t Offset, SMLoc Loc) { |
508 | MCSymbol *Label = emitCFILabel(); |
509 | MCCFIInstruction Instruction = |
510 | MCCFIInstruction::cfiDefCfaOffset(L: Label, Offset); |
511 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
512 | if (!CurFrame) |
513 | return; |
514 | CurFrame->Instructions.push_back(x: Instruction); |
515 | } |
516 | |
517 | void MCStreamer::emitCFIAdjustCfaOffset(int64_t Adjustment, SMLoc Loc) { |
518 | MCSymbol *Label = emitCFILabel(); |
519 | MCCFIInstruction Instruction = |
520 | MCCFIInstruction::createAdjustCfaOffset(L: Label, Adjustment, Loc); |
521 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
522 | if (!CurFrame) |
523 | return; |
524 | CurFrame->Instructions.push_back(x: Instruction); |
525 | } |
526 | |
527 | void MCStreamer::emitCFIDefCfaRegister(int64_t Register, SMLoc Loc) { |
528 | MCSymbol *Label = emitCFILabel(); |
529 | MCCFIInstruction Instruction = |
530 | MCCFIInstruction::createDefCfaRegister(L: Label, Register, Loc); |
531 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
532 | if (!CurFrame) |
533 | return; |
534 | CurFrame->Instructions.push_back(x: Instruction); |
535 | CurFrame->CurrentCfaRegister = static_cast<unsigned>(Register); |
536 | } |
537 | |
538 | void MCStreamer::emitCFILLVMDefAspaceCfa(int64_t Register, int64_t Offset, |
539 | int64_t AddressSpace, SMLoc Loc) { |
540 | MCSymbol *Label = emitCFILabel(); |
541 | MCCFIInstruction Instruction = MCCFIInstruction::createLLVMDefAspaceCfa( |
542 | L: Label, Register, Offset, AddressSpace, Loc); |
543 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
544 | if (!CurFrame) |
545 | return; |
546 | CurFrame->Instructions.push_back(x: Instruction); |
547 | CurFrame->CurrentCfaRegister = static_cast<unsigned>(Register); |
548 | } |
549 | |
550 | void MCStreamer::emitCFIOffset(int64_t Register, int64_t Offset, SMLoc Loc) { |
551 | MCSymbol *Label = emitCFILabel(); |
552 | MCCFIInstruction Instruction = |
553 | MCCFIInstruction::createOffset(L: Label, Register, Offset, Loc); |
554 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
555 | if (!CurFrame) |
556 | return; |
557 | CurFrame->Instructions.push_back(x: Instruction); |
558 | } |
559 | |
560 | void MCStreamer::emitCFIRelOffset(int64_t Register, int64_t Offset, SMLoc Loc) { |
561 | MCSymbol *Label = emitCFILabel(); |
562 | MCCFIInstruction Instruction = |
563 | MCCFIInstruction::createRelOffset(L: Label, Register, Offset, Loc); |
564 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
565 | if (!CurFrame) |
566 | return; |
567 | CurFrame->Instructions.push_back(x: Instruction); |
568 | } |
569 | |
570 | void MCStreamer::emitCFIPersonality(const MCSymbol *Sym, |
571 | unsigned Encoding) { |
572 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
573 | if (!CurFrame) |
574 | return; |
575 | CurFrame->Personality = Sym; |
576 | CurFrame->PersonalityEncoding = Encoding; |
577 | } |
578 | |
579 | void MCStreamer::emitCFILsda(const MCSymbol *Sym, unsigned Encoding) { |
580 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
581 | if (!CurFrame) |
582 | return; |
583 | CurFrame->Lsda = Sym; |
584 | CurFrame->LsdaEncoding = Encoding; |
585 | } |
586 | |
587 | void MCStreamer::emitCFIRememberState(SMLoc Loc) { |
588 | MCSymbol *Label = emitCFILabel(); |
589 | MCCFIInstruction Instruction = |
590 | MCCFIInstruction::createRememberState(L: Label, Loc); |
591 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
592 | if (!CurFrame) |
593 | return; |
594 | CurFrame->Instructions.push_back(x: Instruction); |
595 | } |
596 | |
597 | void MCStreamer::emitCFIRestoreState(SMLoc Loc) { |
598 | // FIXME: Error if there is no matching cfi_remember_state. |
599 | MCSymbol *Label = emitCFILabel(); |
600 | MCCFIInstruction Instruction = |
601 | MCCFIInstruction::createRestoreState(L: Label, Loc); |
602 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
603 | if (!CurFrame) |
604 | return; |
605 | CurFrame->Instructions.push_back(x: Instruction); |
606 | } |
607 | |
608 | void MCStreamer::emitCFISameValue(int64_t Register, SMLoc Loc) { |
609 | MCSymbol *Label = emitCFILabel(); |
610 | MCCFIInstruction Instruction = |
611 | MCCFIInstruction::createSameValue(L: Label, Register, Loc); |
612 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
613 | if (!CurFrame) |
614 | return; |
615 | CurFrame->Instructions.push_back(x: Instruction); |
616 | } |
617 | |
618 | void MCStreamer::emitCFIRestore(int64_t Register, SMLoc Loc) { |
619 | MCSymbol *Label = emitCFILabel(); |
620 | MCCFIInstruction Instruction = |
621 | MCCFIInstruction::createRestore(L: Label, Register, Loc); |
622 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
623 | if (!CurFrame) |
624 | return; |
625 | CurFrame->Instructions.push_back(x: Instruction); |
626 | } |
627 | |
628 | void MCStreamer::emitCFIEscape(StringRef Values, SMLoc Loc) { |
629 | MCSymbol *Label = emitCFILabel(); |
630 | MCCFIInstruction Instruction = |
631 | MCCFIInstruction::createEscape(L: Label, Vals: Values, Loc, Comment: "" ); |
632 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
633 | if (!CurFrame) |
634 | return; |
635 | CurFrame->Instructions.push_back(x: Instruction); |
636 | } |
637 | |
638 | void MCStreamer::emitCFIGnuArgsSize(int64_t Size, SMLoc Loc) { |
639 | MCSymbol *Label = emitCFILabel(); |
640 | MCCFIInstruction Instruction = |
641 | MCCFIInstruction::createGnuArgsSize(L: Label, Size, Loc); |
642 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
643 | if (!CurFrame) |
644 | return; |
645 | CurFrame->Instructions.push_back(x: Instruction); |
646 | } |
647 | |
648 | void MCStreamer::emitCFISignalFrame() { |
649 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
650 | if (!CurFrame) |
651 | return; |
652 | CurFrame->IsSignalFrame = true; |
653 | } |
654 | |
655 | void MCStreamer::emitCFIUndefined(int64_t Register, SMLoc Loc) { |
656 | MCSymbol *Label = emitCFILabel(); |
657 | MCCFIInstruction Instruction = |
658 | MCCFIInstruction::createUndefined(L: Label, Register, Loc); |
659 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
660 | if (!CurFrame) |
661 | return; |
662 | CurFrame->Instructions.push_back(x: Instruction); |
663 | } |
664 | |
665 | void MCStreamer::emitCFIRegister(int64_t Register1, int64_t Register2, |
666 | SMLoc Loc) { |
667 | MCSymbol *Label = emitCFILabel(); |
668 | MCCFIInstruction Instruction = |
669 | MCCFIInstruction::createRegister(L: Label, Register1, Register2, Loc); |
670 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
671 | if (!CurFrame) |
672 | return; |
673 | CurFrame->Instructions.push_back(x: Instruction); |
674 | } |
675 | |
676 | void MCStreamer::emitCFIWindowSave(SMLoc Loc) { |
677 | MCSymbol *Label = emitCFILabel(); |
678 | MCCFIInstruction Instruction = MCCFIInstruction::createWindowSave(L: Label, Loc); |
679 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
680 | if (!CurFrame) |
681 | return; |
682 | CurFrame->Instructions.push_back(x: Instruction); |
683 | } |
684 | |
685 | void MCStreamer::emitCFINegateRAState(SMLoc Loc) { |
686 | MCSymbol *Label = emitCFILabel(); |
687 | MCCFIInstruction Instruction = |
688 | MCCFIInstruction::createNegateRAState(L: Label, Loc); |
689 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
690 | if (!CurFrame) |
691 | return; |
692 | CurFrame->Instructions.push_back(x: Instruction); |
693 | } |
694 | |
695 | void MCStreamer::emitCFIReturnColumn(int64_t Register) { |
696 | MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); |
697 | if (!CurFrame) |
698 | return; |
699 | CurFrame->RAReg = Register; |
700 | } |
701 | |
702 | WinEH::FrameInfo *MCStreamer::EnsureValidWinFrameInfo(SMLoc Loc) { |
703 | const MCAsmInfo *MAI = Context.getAsmInfo(); |
704 | if (!MAI->usesWindowsCFI()) { |
705 | getContext().reportError( |
706 | L: Loc, Msg: ".seh_* directives are not supported on this target" ); |
707 | return nullptr; |
708 | } |
709 | if (!CurrentWinFrameInfo || CurrentWinFrameInfo->End) { |
710 | getContext().reportError( |
711 | L: Loc, Msg: ".seh_ directive must appear within an active frame" ); |
712 | return nullptr; |
713 | } |
714 | return CurrentWinFrameInfo; |
715 | } |
716 | |
717 | void MCStreamer::emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) { |
718 | const MCAsmInfo *MAI = Context.getAsmInfo(); |
719 | if (!MAI->usesWindowsCFI()) |
720 | return getContext().reportError( |
721 | L: Loc, Msg: ".seh_* directives are not supported on this target" ); |
722 | if (CurrentWinFrameInfo && !CurrentWinFrameInfo->End) |
723 | getContext().reportError( |
724 | L: Loc, Msg: "Starting a function before ending the previous one!" ); |
725 | |
726 | MCSymbol *StartProc = emitCFILabel(); |
727 | |
728 | CurrentProcWinFrameInfoStartIndex = WinFrameInfos.size(); |
729 | WinFrameInfos.emplace_back( |
730 | args: std::make_unique<WinEH::FrameInfo>(args&: Symbol, args&: StartProc)); |
731 | CurrentWinFrameInfo = WinFrameInfos.back().get(); |
732 | CurrentWinFrameInfo->TextSection = getCurrentSectionOnly(); |
733 | } |
734 | |
735 | void MCStreamer::emitWinCFIEndProc(SMLoc Loc) { |
736 | WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); |
737 | if (!CurFrame) |
738 | return; |
739 | if (CurFrame->ChainedParent) |
740 | getContext().reportError(L: Loc, Msg: "Not all chained regions terminated!" ); |
741 | |
742 | MCSymbol *Label = emitCFILabel(); |
743 | CurFrame->End = Label; |
744 | if (!CurFrame->FuncletOrFuncEnd) |
745 | CurFrame->FuncletOrFuncEnd = CurFrame->End; |
746 | |
747 | for (size_t I = CurrentProcWinFrameInfoStartIndex, E = WinFrameInfos.size(); |
748 | I != E; ++I) |
749 | emitWindowsUnwindTables(Frame: WinFrameInfos[I].get()); |
750 | switchSection(Section: CurFrame->TextSection); |
751 | } |
752 | |
753 | void MCStreamer::emitWinCFIFuncletOrFuncEnd(SMLoc Loc) { |
754 | WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); |
755 | if (!CurFrame) |
756 | return; |
757 | if (CurFrame->ChainedParent) |
758 | getContext().reportError(L: Loc, Msg: "Not all chained regions terminated!" ); |
759 | |
760 | MCSymbol *Label = emitCFILabel(); |
761 | CurFrame->FuncletOrFuncEnd = Label; |
762 | } |
763 | |
764 | void MCStreamer::emitWinCFIStartChained(SMLoc Loc) { |
765 | WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); |
766 | if (!CurFrame) |
767 | return; |
768 | |
769 | MCSymbol *StartProc = emitCFILabel(); |
770 | |
771 | WinFrameInfos.emplace_back(args: std::make_unique<WinEH::FrameInfo>( |
772 | args&: CurFrame->Function, args&: StartProc, args&: CurFrame)); |
773 | CurrentWinFrameInfo = WinFrameInfos.back().get(); |
774 | CurrentWinFrameInfo->TextSection = getCurrentSectionOnly(); |
775 | } |
776 | |
777 | void MCStreamer::emitWinCFIEndChained(SMLoc Loc) { |
778 | WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); |
779 | if (!CurFrame) |
780 | return; |
781 | if (!CurFrame->ChainedParent) |
782 | return getContext().reportError( |
783 | L: Loc, Msg: "End of a chained region outside a chained region!" ); |
784 | |
785 | MCSymbol *Label = emitCFILabel(); |
786 | |
787 | CurFrame->End = Label; |
788 | CurrentWinFrameInfo = const_cast<WinEH::FrameInfo *>(CurFrame->ChainedParent); |
789 | } |
790 | |
791 | void MCStreamer::emitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except, |
792 | SMLoc Loc) { |
793 | WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); |
794 | if (!CurFrame) |
795 | return; |
796 | if (CurFrame->ChainedParent) |
797 | return getContext().reportError( |
798 | L: Loc, Msg: "Chained unwind areas can't have handlers!" ); |
799 | CurFrame->ExceptionHandler = Sym; |
800 | if (!Except && !Unwind) |
801 | getContext().reportError(L: Loc, Msg: "Don't know what kind of handler this is!" ); |
802 | if (Unwind) |
803 | CurFrame->HandlesUnwind = true; |
804 | if (Except) |
805 | CurFrame->HandlesExceptions = true; |
806 | } |
807 | |
808 | void MCStreamer::emitWinEHHandlerData(SMLoc Loc) { |
809 | WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); |
810 | if (!CurFrame) |
811 | return; |
812 | if (CurFrame->ChainedParent) |
813 | getContext().reportError(L: Loc, Msg: "Chained unwind areas can't have handlers!" ); |
814 | } |
815 | |
816 | void MCStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From, |
817 | const MCSymbolRefExpr *To, uint64_t Count) { |
818 | } |
819 | |
820 | static MCSection *getWinCFISection(MCContext &Context, unsigned *NextWinCFIID, |
821 | MCSection *MainCFISec, |
822 | const MCSection *TextSec) { |
823 | // If this is the main .text section, use the main unwind info section. |
824 | if (TextSec == Context.getObjectFileInfo()->getTextSection()) |
825 | return MainCFISec; |
826 | |
827 | const auto *TextSecCOFF = cast<MCSectionCOFF>(Val: TextSec); |
828 | auto *MainCFISecCOFF = cast<MCSectionCOFF>(Val: MainCFISec); |
829 | unsigned UniqueID = TextSecCOFF->getOrAssignWinCFISectionID(NextID: NextWinCFIID); |
830 | |
831 | // If this section is COMDAT, this unwind section should be COMDAT associative |
832 | // with its group. |
833 | const MCSymbol *KeySym = nullptr; |
834 | if (TextSecCOFF->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) { |
835 | KeySym = TextSecCOFF->getCOMDATSymbol(); |
836 | |
837 | // In a GNU environment, we can't use associative comdats. Instead, do what |
838 | // GCC does, which is to make plain comdat selectany section named like |
839 | // ".[px]data$_Z3foov". |
840 | if (!Context.getAsmInfo()->hasCOFFAssociativeComdats()) { |
841 | std::string SectionName = (MainCFISecCOFF->getName() + "$" + |
842 | TextSecCOFF->getName().split(Separator: '$').second) |
843 | .str(); |
844 | return Context.getCOFFSection( |
845 | Section: SectionName, |
846 | Characteristics: MainCFISecCOFF->getCharacteristics() | COFF::IMAGE_SCN_LNK_COMDAT, |
847 | Kind: MainCFISecCOFF->getKind(), COMDATSymName: "" , Selection: COFF::IMAGE_COMDAT_SELECT_ANY); |
848 | } |
849 | } |
850 | |
851 | return Context.getAssociativeCOFFSection(Sec: MainCFISecCOFF, KeySym, UniqueID); |
852 | } |
853 | |
854 | MCSection *MCStreamer::getAssociatedPDataSection(const MCSection *TextSec) { |
855 | return getWinCFISection(Context&: getContext(), NextWinCFIID: &NextWinCFIID, |
856 | MainCFISec: getContext().getObjectFileInfo()->getPDataSection(), |
857 | TextSec); |
858 | } |
859 | |
860 | MCSection *MCStreamer::getAssociatedXDataSection(const MCSection *TextSec) { |
861 | return getWinCFISection(Context&: getContext(), NextWinCFIID: &NextWinCFIID, |
862 | MainCFISec: getContext().getObjectFileInfo()->getXDataSection(), |
863 | TextSec); |
864 | } |
865 | |
866 | void MCStreamer::emitSyntaxDirective() {} |
867 | |
868 | static unsigned encodeSEHRegNum(MCContext &Ctx, MCRegister Reg) { |
869 | return Ctx.getRegisterInfo()->getSEHRegNum(RegNum: Reg); |
870 | } |
871 | |
872 | void MCStreamer::emitWinCFIPushReg(MCRegister Register, SMLoc Loc) { |
873 | WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); |
874 | if (!CurFrame) |
875 | return; |
876 | |
877 | MCSymbol *Label = emitCFILabel(); |
878 | |
879 | WinEH::Instruction Inst = Win64EH::Instruction::PushNonVol( |
880 | L: Label, Reg: encodeSEHRegNum(Ctx&: Context, Reg: Register)); |
881 | CurFrame->Instructions.push_back(x: Inst); |
882 | } |
883 | |
884 | void MCStreamer::emitWinCFISetFrame(MCRegister Register, unsigned Offset, |
885 | SMLoc Loc) { |
886 | WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); |
887 | if (!CurFrame) |
888 | return; |
889 | if (CurFrame->LastFrameInst >= 0) |
890 | return getContext().reportError( |
891 | L: Loc, Msg: "frame register and offset can be set at most once" ); |
892 | if (Offset & 0x0F) |
893 | return getContext().reportError(L: Loc, Msg: "offset is not a multiple of 16" ); |
894 | if (Offset > 240) |
895 | return getContext().reportError( |
896 | L: Loc, Msg: "frame offset must be less than or equal to 240" ); |
897 | |
898 | MCSymbol *Label = emitCFILabel(); |
899 | |
900 | WinEH::Instruction Inst = Win64EH::Instruction::SetFPReg( |
901 | L: Label, Reg: encodeSEHRegNum(Ctx&: getContext(), Reg: Register), Off: Offset); |
902 | CurFrame->LastFrameInst = CurFrame->Instructions.size(); |
903 | CurFrame->Instructions.push_back(x: Inst); |
904 | } |
905 | |
906 | void MCStreamer::emitWinCFIAllocStack(unsigned Size, SMLoc Loc) { |
907 | WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); |
908 | if (!CurFrame) |
909 | return; |
910 | if (Size == 0) |
911 | return getContext().reportError(L: Loc, |
912 | Msg: "stack allocation size must be non-zero" ); |
913 | if (Size & 7) |
914 | return getContext().reportError( |
915 | L: Loc, Msg: "stack allocation size is not a multiple of 8" ); |
916 | |
917 | MCSymbol *Label = emitCFILabel(); |
918 | |
919 | WinEH::Instruction Inst = Win64EH::Instruction::Alloc(L: Label, Size); |
920 | CurFrame->Instructions.push_back(x: Inst); |
921 | } |
922 | |
923 | void MCStreamer::emitWinCFISaveReg(MCRegister Register, unsigned Offset, |
924 | SMLoc Loc) { |
925 | WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); |
926 | if (!CurFrame) |
927 | return; |
928 | |
929 | if (Offset & 7) |
930 | return getContext().reportError( |
931 | L: Loc, Msg: "register save offset is not 8 byte aligned" ); |
932 | |
933 | MCSymbol *Label = emitCFILabel(); |
934 | |
935 | WinEH::Instruction Inst = Win64EH::Instruction::SaveNonVol( |
936 | L: Label, Reg: encodeSEHRegNum(Ctx&: Context, Reg: Register), Offset); |
937 | CurFrame->Instructions.push_back(x: Inst); |
938 | } |
939 | |
940 | void MCStreamer::emitWinCFISaveXMM(MCRegister Register, unsigned Offset, |
941 | SMLoc Loc) { |
942 | WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); |
943 | if (!CurFrame) |
944 | return; |
945 | if (Offset & 0x0F) |
946 | return getContext().reportError(L: Loc, Msg: "offset is not a multiple of 16" ); |
947 | |
948 | MCSymbol *Label = emitCFILabel(); |
949 | |
950 | WinEH::Instruction Inst = Win64EH::Instruction::SaveXMM( |
951 | L: Label, Reg: encodeSEHRegNum(Ctx&: Context, Reg: Register), Offset); |
952 | CurFrame->Instructions.push_back(x: Inst); |
953 | } |
954 | |
955 | void MCStreamer::emitWinCFIPushFrame(bool Code, SMLoc Loc) { |
956 | WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); |
957 | if (!CurFrame) |
958 | return; |
959 | if (!CurFrame->Instructions.empty()) |
960 | return getContext().reportError( |
961 | L: Loc, Msg: "If present, PushMachFrame must be the first UOP" ); |
962 | |
963 | MCSymbol *Label = emitCFILabel(); |
964 | |
965 | WinEH::Instruction Inst = Win64EH::Instruction::PushMachFrame(L: Label, Code); |
966 | CurFrame->Instructions.push_back(x: Inst); |
967 | } |
968 | |
969 | void MCStreamer::emitWinCFIEndProlog(SMLoc Loc) { |
970 | WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); |
971 | if (!CurFrame) |
972 | return; |
973 | |
974 | MCSymbol *Label = emitCFILabel(); |
975 | |
976 | CurFrame->PrologEnd = Label; |
977 | } |
978 | |
979 | void MCStreamer::emitCOFFSafeSEH(MCSymbol const *Symbol) {} |
980 | |
981 | void MCStreamer::emitCOFFSymbolIndex(MCSymbol const *Symbol) {} |
982 | |
983 | void MCStreamer::emitCOFFSectionIndex(MCSymbol const *Symbol) {} |
984 | |
985 | void MCStreamer::emitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) {} |
986 | |
987 | void MCStreamer::emitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) {} |
988 | |
989 | /// EmitRawText - If this file is backed by an assembly streamer, this dumps |
990 | /// the specified string in the output .s file. This capability is |
991 | /// indicated by the hasRawTextSupport() predicate. |
992 | void MCStreamer::emitRawTextImpl(StringRef String) { |
993 | // This is not llvm_unreachable for the sake of out of tree backend |
994 | // developers who may not have assembly streamers and should serve as a |
995 | // reminder to not accidentally call EmitRawText in the absence of such. |
996 | report_fatal_error(reason: "EmitRawText called on an MCStreamer that doesn't support " |
997 | "it (target backend is likely missing an AsmStreamer " |
998 | "implementation)" ); |
999 | } |
1000 | |
1001 | void MCStreamer::emitRawText(const Twine &T) { |
1002 | SmallString<128> Str; |
1003 | emitRawTextImpl(String: T.toStringRef(Out&: Str)); |
1004 | } |
1005 | |
1006 | void MCStreamer::emitWindowsUnwindTables() {} |
1007 | |
1008 | void MCStreamer::emitWindowsUnwindTables(WinEH::FrameInfo *Frame) {} |
1009 | |
1010 | void MCStreamer::finish(SMLoc EndLoc) { |
1011 | if ((!DwarfFrameInfos.empty() && !DwarfFrameInfos.back().End) || |
1012 | (!WinFrameInfos.empty() && !WinFrameInfos.back()->End)) { |
1013 | getContext().reportError(L: EndLoc, Msg: "Unfinished frame!" ); |
1014 | return; |
1015 | } |
1016 | |
1017 | MCTargetStreamer *TS = getTargetStreamer(); |
1018 | if (TS) |
1019 | TS->finish(); |
1020 | |
1021 | finishImpl(); |
1022 | } |
1023 | |
1024 | void MCStreamer::maybeEmitDwarf64Mark() { |
1025 | if (Context.getDwarfFormat() != dwarf::DWARF64) |
1026 | return; |
1027 | AddComment(T: "DWARF64 Mark" ); |
1028 | emitInt32(Value: dwarf::DW_LENGTH_DWARF64); |
1029 | } |
1030 | |
1031 | void MCStreamer::emitDwarfUnitLength(uint64_t Length, const Twine &) { |
1032 | assert(Context.getDwarfFormat() == dwarf::DWARF64 || |
1033 | Length <= dwarf::DW_LENGTH_lo_reserved); |
1034 | maybeEmitDwarf64Mark(); |
1035 | AddComment(T: Comment); |
1036 | emitIntValue(Value: Length, Size: dwarf::getDwarfOffsetByteSize(Format: Context.getDwarfFormat())); |
1037 | } |
1038 | |
1039 | MCSymbol *MCStreamer::emitDwarfUnitLength(const Twine &Prefix, |
1040 | const Twine &) { |
1041 | maybeEmitDwarf64Mark(); |
1042 | AddComment(T: Comment); |
1043 | MCSymbol *Lo = Context.createTempSymbol(Name: Prefix + "_start" ); |
1044 | MCSymbol *Hi = Context.createTempSymbol(Name: Prefix + "_end" ); |
1045 | |
1046 | emitAbsoluteSymbolDiff( |
1047 | Hi, Lo, Size: dwarf::getDwarfOffsetByteSize(Format: Context.getDwarfFormat())); |
1048 | // emit the begin symbol after we generate the length field. |
1049 | emitLabel(Symbol: Lo); |
1050 | // Return the Hi symbol to the caller. |
1051 | return Hi; |
1052 | } |
1053 | |
1054 | void MCStreamer::emitDwarfLineStartLabel(MCSymbol *StartSym) { |
1055 | // Set the value of the symbol, as we are at the start of the line table. |
1056 | emitLabel(Symbol: StartSym); |
1057 | } |
1058 | |
1059 | void MCStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) { |
1060 | visitUsedExpr(Expr: *Value); |
1061 | Symbol->setVariableValue(Value); |
1062 | |
1063 | MCTargetStreamer *TS = getTargetStreamer(); |
1064 | if (TS) |
1065 | TS->emitAssignment(Symbol, Value); |
1066 | } |
1067 | |
1068 | void MCTargetStreamer::prettyPrintAsm(MCInstPrinter &InstPrinter, |
1069 | uint64_t Address, const MCInst &Inst, |
1070 | const MCSubtargetInfo &STI, |
1071 | raw_ostream &OS) { |
1072 | InstPrinter.printInst(MI: &Inst, Address, Annot: "" , STI, OS); |
1073 | } |
1074 | |
1075 | void MCStreamer::visitUsedSymbol(const MCSymbol &Sym) { |
1076 | } |
1077 | |
1078 | void MCStreamer::visitUsedExpr(const MCExpr &Expr) { |
1079 | switch (Expr.getKind()) { |
1080 | case MCExpr::Target: |
1081 | cast<MCTargetExpr>(Val: Expr).visitUsedExpr(Streamer&: *this); |
1082 | break; |
1083 | |
1084 | case MCExpr::Constant: |
1085 | break; |
1086 | |
1087 | case MCExpr::Binary: { |
1088 | const MCBinaryExpr &BE = cast<MCBinaryExpr>(Val: Expr); |
1089 | visitUsedExpr(Expr: *BE.getLHS()); |
1090 | visitUsedExpr(Expr: *BE.getRHS()); |
1091 | break; |
1092 | } |
1093 | |
1094 | case MCExpr::SymbolRef: |
1095 | visitUsedSymbol(Sym: cast<MCSymbolRefExpr>(Val: Expr).getSymbol()); |
1096 | break; |
1097 | |
1098 | case MCExpr::Unary: |
1099 | visitUsedExpr(Expr: *cast<MCUnaryExpr>(Val: Expr).getSubExpr()); |
1100 | break; |
1101 | } |
1102 | } |
1103 | |
1104 | void MCStreamer::emitInstruction(const MCInst &Inst, const MCSubtargetInfo &) { |
1105 | // Scan for values. |
1106 | for (unsigned i = Inst.getNumOperands(); i--;) |
1107 | if (Inst.getOperand(i).isExpr()) |
1108 | visitUsedExpr(Expr: *Inst.getOperand(i).getExpr()); |
1109 | } |
1110 | |
1111 | void MCStreamer::emitPseudoProbe(uint64_t Guid, uint64_t Index, uint64_t Type, |
1112 | uint64_t Attr, uint64_t Discriminator, |
1113 | const MCPseudoProbeInlineStack &InlineStack, |
1114 | MCSymbol *FnSym) { |
1115 | auto &Context = getContext(); |
1116 | |
1117 | // Create a symbol at in the current section for use in the probe. |
1118 | MCSymbol *ProbeSym = Context.createTempSymbol(); |
1119 | |
1120 | // Set the value of the symbol to use for the MCPseudoProbe. |
1121 | emitLabel(Symbol: ProbeSym); |
1122 | |
1123 | // Create a (local) probe entry with the symbol. |
1124 | MCPseudoProbe Probe(ProbeSym, Guid, Index, Type, Attr, Discriminator); |
1125 | |
1126 | // Add the probe entry to this section's entries. |
1127 | Context.getMCPseudoProbeTable().getProbeSections().addPseudoProbe( |
1128 | FuncSym: FnSym, Probe, InlineStack); |
1129 | } |
1130 | |
1131 | void MCStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, |
1132 | unsigned Size) { |
1133 | // Get the Hi-Lo expression. |
1134 | const MCExpr *Diff = |
1135 | MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: Hi, Ctx&: Context), |
1136 | RHS: MCSymbolRefExpr::create(Symbol: Lo, Ctx&: Context), Ctx&: Context); |
1137 | |
1138 | const MCAsmInfo *MAI = Context.getAsmInfo(); |
1139 | if (!MAI->doesSetDirectiveSuppressReloc()) { |
1140 | emitValue(Value: Diff, Size); |
1141 | return; |
1142 | } |
1143 | |
1144 | // Otherwise, emit with .set (aka assignment). |
1145 | MCSymbol *SetLabel = Context.createTempSymbol(Name: "set" ); |
1146 | emitAssignment(Symbol: SetLabel, Value: Diff); |
1147 | emitSymbolValue(Sym: SetLabel, Size); |
1148 | } |
1149 | |
1150 | void MCStreamer::emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi, |
1151 | const MCSymbol *Lo) { |
1152 | // Get the Hi-Lo expression. |
1153 | const MCExpr *Diff = |
1154 | MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: Hi, Ctx&: Context), |
1155 | RHS: MCSymbolRefExpr::create(Symbol: Lo, Ctx&: Context), Ctx&: Context); |
1156 | |
1157 | emitULEB128Value(Value: Diff); |
1158 | } |
1159 | |
1160 | void MCStreamer::emitAssemblerFlag(MCAssemblerFlag Flag) {} |
1161 | void MCStreamer::emitThumbFunc(MCSymbol *Func) {} |
1162 | void MCStreamer::emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {} |
1163 | void MCStreamer::beginCOFFSymbolDef(const MCSymbol *Symbol) { |
1164 | llvm_unreachable("this directive only supported on COFF targets" ); |
1165 | } |
1166 | void MCStreamer::endCOFFSymbolDef() { |
1167 | llvm_unreachable("this directive only supported on COFF targets" ); |
1168 | } |
1169 | void MCStreamer::emitFileDirective(StringRef Filename) {} |
1170 | void MCStreamer::emitFileDirective(StringRef Filename, |
1171 | StringRef CompilerVersion, |
1172 | StringRef TimeStamp, StringRef Description) { |
1173 | } |
1174 | void MCStreamer::emitCOFFSymbolStorageClass(int StorageClass) { |
1175 | llvm_unreachable("this directive only supported on COFF targets" ); |
1176 | } |
1177 | void MCStreamer::emitCOFFSymbolType(int Type) { |
1178 | llvm_unreachable("this directive only supported on COFF targets" ); |
1179 | } |
1180 | void MCStreamer::emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size, |
1181 | MCSymbol *CsectSym, |
1182 | Align Alignment) { |
1183 | llvm_unreachable("this directive only supported on XCOFF targets" ); |
1184 | } |
1185 | |
1186 | void MCStreamer::emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol, |
1187 | MCSymbolAttr Linkage, |
1188 | MCSymbolAttr Visibility) { |
1189 | llvm_unreachable("emitXCOFFSymbolLinkageWithVisibility is only supported on " |
1190 | "XCOFF targets" ); |
1191 | } |
1192 | |
1193 | void MCStreamer::emitXCOFFRenameDirective(const MCSymbol *Name, |
1194 | StringRef Rename) {} |
1195 | |
1196 | void MCStreamer::emitXCOFFRefDirective(const MCSymbol *Symbol) { |
1197 | llvm_unreachable("emitXCOFFRefDirective is only supported on XCOFF targets" ); |
1198 | } |
1199 | |
1200 | void MCStreamer::emitXCOFFExceptDirective(const MCSymbol *Symbol, |
1201 | const MCSymbol *Trap, |
1202 | unsigned Lang, unsigned Reason, |
1203 | unsigned FunctionSize, |
1204 | bool hasDebug) { |
1205 | report_fatal_error(reason: "emitXCOFFExceptDirective is only supported on " |
1206 | "XCOFF targets" ); |
1207 | } |
1208 | |
1209 | void MCStreamer::emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) { |
1210 | llvm_unreachable("emitXCOFFCInfoSym is only supported on" |
1211 | "XCOFF targets" ); |
1212 | } |
1213 | |
1214 | void MCStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} |
1215 | void MCStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym, |
1216 | StringRef Name, bool KeepOriginalSym) {} |
1217 | void MCStreamer::emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, |
1218 | Align ByteAlignment) {} |
1219 | void MCStreamer::emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, |
1220 | uint64_t Size, Align ByteAlignment) {} |
1221 | void MCStreamer::changeSection(MCSection *, const MCExpr *) {} |
1222 | void MCStreamer::emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) {} |
1223 | void MCStreamer::emitBytes(StringRef Data) {} |
1224 | void MCStreamer::emitBinaryData(StringRef Data) { emitBytes(Data); } |
1225 | void MCStreamer::emitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) { |
1226 | visitUsedExpr(Expr: *Value); |
1227 | } |
1228 | void MCStreamer::emitULEB128Value(const MCExpr *Value) {} |
1229 | void MCStreamer::emitSLEB128Value(const MCExpr *Value) {} |
1230 | void MCStreamer::emitFill(const MCExpr &NumBytes, uint64_t Value, SMLoc Loc) {} |
1231 | void MCStreamer::emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr, |
1232 | SMLoc Loc) {} |
1233 | void MCStreamer::emitValueToAlignment(Align Alignment, int64_t Value, |
1234 | unsigned ValueSize, |
1235 | unsigned MaxBytesToEmit) {} |
1236 | void MCStreamer::emitCodeAlignment(Align Alignment, const MCSubtargetInfo *STI, |
1237 | unsigned MaxBytesToEmit) {} |
1238 | void MCStreamer::emitValueToOffset(const MCExpr *Offset, unsigned char Value, |
1239 | SMLoc Loc) {} |
1240 | void MCStreamer::emitBundleAlignMode(Align Alignment) {} |
1241 | void MCStreamer::emitBundleLock(bool AlignToEnd) {} |
1242 | void MCStreamer::finishImpl() {} |
1243 | void MCStreamer::emitBundleUnlock() {} |
1244 | |
1245 | void MCStreamer::switchSection(MCSection *Section, const MCExpr *Subsection) { |
1246 | assert(Section && "Cannot switch to a null section!" ); |
1247 | MCSectionSubPair curSection = SectionStack.back().first; |
1248 | SectionStack.back().second = curSection; |
1249 | if (MCSectionSubPair(Section, Subsection) != curSection) { |
1250 | changeSection(Section, Subsection); |
1251 | SectionStack.back().first = MCSectionSubPair(Section, Subsection); |
1252 | assert(!Section->hasEnded() && "Section already ended" ); |
1253 | MCSymbol *Sym = Section->getBeginSymbol(); |
1254 | if (Sym && !Sym->isInSection()) |
1255 | emitLabel(Symbol: Sym); |
1256 | } |
1257 | } |
1258 | |
1259 | MCSymbol *MCStreamer::endSection(MCSection *Section) { |
1260 | // TODO: keep track of the last subsection so that this symbol appears in the |
1261 | // correct place. |
1262 | MCSymbol *Sym = Section->getEndSymbol(Ctx&: Context); |
1263 | if (Sym->isInSection()) |
1264 | return Sym; |
1265 | |
1266 | switchSection(Section); |
1267 | emitLabel(Symbol: Sym); |
1268 | return Sym; |
1269 | } |
1270 | |
1271 | static VersionTuple |
1272 | targetVersionOrMinimumSupportedOSVersion(const Triple &Target, |
1273 | VersionTuple TargetVersion) { |
1274 | VersionTuple Min = Target.getMinimumSupportedOSVersion(); |
1275 | return !Min.empty() && Min > TargetVersion ? Min : TargetVersion; |
1276 | } |
1277 | |
1278 | static MCVersionMinType |
1279 | getMachoVersionMinLoadCommandType(const Triple &Target) { |
1280 | assert(Target.isOSDarwin() && "expected a darwin OS" ); |
1281 | switch (Target.getOS()) { |
1282 | case Triple::MacOSX: |
1283 | case Triple::Darwin: |
1284 | return MCVM_OSXVersionMin; |
1285 | case Triple::IOS: |
1286 | assert(!Target.isMacCatalystEnvironment() && |
1287 | "mac Catalyst should use LC_BUILD_VERSION" ); |
1288 | return MCVM_IOSVersionMin; |
1289 | case Triple::TvOS: |
1290 | return MCVM_TvOSVersionMin; |
1291 | case Triple::WatchOS: |
1292 | return MCVM_WatchOSVersionMin; |
1293 | default: |
1294 | break; |
1295 | } |
1296 | llvm_unreachable("unexpected OS type" ); |
1297 | } |
1298 | |
1299 | static VersionTuple getMachoBuildVersionSupportedOS(const Triple &Target) { |
1300 | assert(Target.isOSDarwin() && "expected a darwin OS" ); |
1301 | switch (Target.getOS()) { |
1302 | case Triple::MacOSX: |
1303 | case Triple::Darwin: |
1304 | return VersionTuple(10, 14); |
1305 | case Triple::IOS: |
1306 | // Mac Catalyst always uses the build version load command. |
1307 | if (Target.isMacCatalystEnvironment()) |
1308 | return VersionTuple(); |
1309 | [[fallthrough]]; |
1310 | case Triple::TvOS: |
1311 | return VersionTuple(12); |
1312 | case Triple::WatchOS: |
1313 | return VersionTuple(5); |
1314 | case Triple::DriverKit: |
1315 | // DriverKit always uses the build version load command. |
1316 | return VersionTuple(); |
1317 | case Triple::XROS: |
1318 | // XROS always uses the build version load command. |
1319 | return VersionTuple(); |
1320 | default: |
1321 | break; |
1322 | } |
1323 | llvm_unreachable("unexpected OS type" ); |
1324 | } |
1325 | |
1326 | static MachO::PlatformType |
1327 | getMachoBuildVersionPlatformType(const Triple &Target) { |
1328 | assert(Target.isOSDarwin() && "expected a darwin OS" ); |
1329 | switch (Target.getOS()) { |
1330 | case Triple::MacOSX: |
1331 | case Triple::Darwin: |
1332 | return MachO::PLATFORM_MACOS; |
1333 | case Triple::IOS: |
1334 | if (Target.isMacCatalystEnvironment()) |
1335 | return MachO::PLATFORM_MACCATALYST; |
1336 | return Target.isSimulatorEnvironment() ? MachO::PLATFORM_IOSSIMULATOR |
1337 | : MachO::PLATFORM_IOS; |
1338 | case Triple::TvOS: |
1339 | return Target.isSimulatorEnvironment() ? MachO::PLATFORM_TVOSSIMULATOR |
1340 | : MachO::PLATFORM_TVOS; |
1341 | case Triple::WatchOS: |
1342 | return Target.isSimulatorEnvironment() ? MachO::PLATFORM_WATCHOSSIMULATOR |
1343 | : MachO::PLATFORM_WATCHOS; |
1344 | case Triple::DriverKit: |
1345 | return MachO::PLATFORM_DRIVERKIT; |
1346 | case Triple::XROS: |
1347 | return Target.isSimulatorEnvironment() ? MachO::PLATFORM_XROS_SIMULATOR |
1348 | : MachO::PLATFORM_XROS; |
1349 | default: |
1350 | break; |
1351 | } |
1352 | llvm_unreachable("unexpected OS type" ); |
1353 | } |
1354 | |
1355 | void MCStreamer::emitVersionForTarget( |
1356 | const Triple &Target, const VersionTuple &SDKVersion, |
1357 | const Triple *DarwinTargetVariantTriple, |
1358 | const VersionTuple &DarwinTargetVariantSDKVersion) { |
1359 | if (!Target.isOSBinFormatMachO() || !Target.isOSDarwin()) |
1360 | return; |
1361 | // Do we even know the version? |
1362 | if (Target.getOSMajorVersion() == 0) |
1363 | return; |
1364 | |
1365 | VersionTuple Version; |
1366 | switch (Target.getOS()) { |
1367 | case Triple::MacOSX: |
1368 | case Triple::Darwin: |
1369 | Target.getMacOSXVersion(Version); |
1370 | break; |
1371 | case Triple::IOS: |
1372 | case Triple::TvOS: |
1373 | Version = Target.getiOSVersion(); |
1374 | break; |
1375 | case Triple::WatchOS: |
1376 | Version = Target.getWatchOSVersion(); |
1377 | break; |
1378 | case Triple::DriverKit: |
1379 | Version = Target.getDriverKitVersion(); |
1380 | break; |
1381 | case Triple::XROS: |
1382 | Version = Target.getOSVersion(); |
1383 | break; |
1384 | default: |
1385 | llvm_unreachable("unexpected OS type" ); |
1386 | } |
1387 | assert(Version.getMajor() != 0 && "A non-zero major version is expected" ); |
1388 | auto LinkedTargetVersion = |
1389 | targetVersionOrMinimumSupportedOSVersion(Target, TargetVersion: Version); |
1390 | auto BuildVersionOSVersion = getMachoBuildVersionSupportedOS(Target); |
1391 | bool ShouldEmitBuildVersion = false; |
1392 | if (BuildVersionOSVersion.empty() || |
1393 | LinkedTargetVersion >= BuildVersionOSVersion) { |
1394 | if (Target.isMacCatalystEnvironment() && DarwinTargetVariantTriple && |
1395 | DarwinTargetVariantTriple->isMacOSX()) { |
1396 | emitVersionForTarget(Target: *DarwinTargetVariantTriple, |
1397 | SDKVersion: DarwinTargetVariantSDKVersion, |
1398 | /*DarwinTargetVariantTriple=*/nullptr, |
1399 | /*DarwinTargetVariantSDKVersion=*/VersionTuple()); |
1400 | emitDarwinTargetVariantBuildVersion( |
1401 | Platform: getMachoBuildVersionPlatformType(Target), |
1402 | Major: LinkedTargetVersion.getMajor(), |
1403 | Minor: LinkedTargetVersion.getMinor().value_or(u: 0), |
1404 | Update: LinkedTargetVersion.getSubminor().value_or(u: 0), SDKVersion); |
1405 | return; |
1406 | } |
1407 | emitBuildVersion(Platform: getMachoBuildVersionPlatformType(Target), |
1408 | Major: LinkedTargetVersion.getMajor(), |
1409 | Minor: LinkedTargetVersion.getMinor().value_or(u: 0), |
1410 | Update: LinkedTargetVersion.getSubminor().value_or(u: 0), SDKVersion); |
1411 | ShouldEmitBuildVersion = true; |
1412 | } |
1413 | |
1414 | if (const Triple *TVT = DarwinTargetVariantTriple) { |
1415 | if (Target.isMacOSX() && TVT->isMacCatalystEnvironment()) { |
1416 | auto TVLinkedTargetVersion = |
1417 | targetVersionOrMinimumSupportedOSVersion(Target: *TVT, TargetVersion: TVT->getiOSVersion()); |
1418 | emitDarwinTargetVariantBuildVersion( |
1419 | Platform: getMachoBuildVersionPlatformType(Target: *TVT), |
1420 | Major: TVLinkedTargetVersion.getMajor(), |
1421 | Minor: TVLinkedTargetVersion.getMinor().value_or(u: 0), |
1422 | Update: TVLinkedTargetVersion.getSubminor().value_or(u: 0), |
1423 | SDKVersion: DarwinTargetVariantSDKVersion); |
1424 | } |
1425 | } |
1426 | |
1427 | if (ShouldEmitBuildVersion) |
1428 | return; |
1429 | |
1430 | emitVersionMin(Type: getMachoVersionMinLoadCommandType(Target), |
1431 | Major: LinkedTargetVersion.getMajor(), |
1432 | Minor: LinkedTargetVersion.getMinor().value_or(u: 0), |
1433 | Update: LinkedTargetVersion.getSubminor().value_or(u: 0), SDKVersion); |
1434 | } |
1435 | |