1//=====- NVPTXTargetStreamer.cpp - NVPTXTargetStreamer class ------------=====//
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 implements the NVPTXTargetStreamer class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "NVPTXTargetStreamer.h"
14#include "NVPTXUtilities.h"
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/MC/MCAsmInfo.h"
17#include "llvm/MC/MCContext.h"
18#include "llvm/MC/MCExpr.h"
19#include "llvm/MC/MCObjectFileInfo.h"
20#include "llvm/MC/MCSymbol.h"
21#include "llvm/Support/Casting.h"
22#include "llvm/Support/FormattedStream.h"
23
24using namespace llvm;
25
26//
27// NVPTXTargetStreamer Implemenation
28//
29NVPTXTargetStreamer::NVPTXTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}
30NVPTXTargetStreamer::~NVPTXTargetStreamer() = default;
31
32void NVPTXTargetStreamer::outputDwarfFileDirectives() {
33 for (const std::string &S : DwarfFiles)
34 getStreamer().emitRawText(String: S);
35 DwarfFiles.clear();
36}
37
38void NVPTXTargetStreamer::closeLastSection() {
39 if (HasSections)
40 getStreamer().emitRawText(String: "\t}");
41}
42
43void NVPTXTargetStreamer::emitDwarfFileDirective(StringRef Directive) {
44 DwarfFiles.emplace_back(Args&: Directive);
45}
46
47static bool isDwarfSection(const MCObjectFileInfo *FI,
48 const MCSection *Section) {
49 // FIXME: the checks for the DWARF sections are very fragile and should be
50 // fixed up in a followup patch.
51 if (!Section || Section->isText())
52 return false;
53 return Section == FI->getDwarfAbbrevSection() ||
54 Section == FI->getDwarfInfoSection() ||
55 Section == FI->getDwarfMacinfoSection() ||
56 Section == FI->getDwarfFrameSection() ||
57 Section == FI->getDwarfAddrSection() ||
58 Section == FI->getDwarfRangesSection() ||
59 Section == FI->getDwarfARangesSection() ||
60 Section == FI->getDwarfLocSection() ||
61 Section == FI->getDwarfStrSection() ||
62 Section == FI->getDwarfLineSection() ||
63 Section == FI->getDwarfStrOffSection() ||
64 Section == FI->getDwarfLineStrSection() ||
65 Section == FI->getDwarfPubNamesSection() ||
66 Section == FI->getDwarfPubTypesSection() ||
67 Section == FI->getDwarfSwiftASTSection() ||
68 Section == FI->getDwarfTypesDWOSection() ||
69 Section == FI->getDwarfAbbrevDWOSection() ||
70 Section == FI->getDwarfAccelObjCSection() ||
71 Section == FI->getDwarfAccelNamesSection() ||
72 Section == FI->getDwarfAccelTypesSection() ||
73 Section == FI->getDwarfAccelNamespaceSection() ||
74 Section == FI->getDwarfLocDWOSection() ||
75 Section == FI->getDwarfStrDWOSection() ||
76 Section == FI->getDwarfCUIndexSection() ||
77 Section == FI->getDwarfInfoDWOSection() ||
78 Section == FI->getDwarfLineDWOSection() ||
79 Section == FI->getDwarfTUIndexSection() ||
80 Section == FI->getDwarfStrOffDWOSection() ||
81 Section == FI->getDwarfDebugNamesSection() ||
82 Section == FI->getDwarfDebugInlineSection() ||
83 Section == FI->getDwarfGnuPubNamesSection() ||
84 Section == FI->getDwarfGnuPubTypesSection();
85}
86
87void NVPTXTargetStreamer::changeSection(const MCSection *CurSection,
88 MCSection *Section, uint32_t SubSection,
89 raw_ostream &OS) {
90 assert(!SubSection && "SubSection is not null!");
91 const MCObjectFileInfo *FI = getStreamer().getContext().getObjectFileInfo();
92 // Emit closing brace for DWARF sections only.
93 if (isDwarfSection(FI, Section: CurSection))
94 OS << "\t}\n";
95 if (isDwarfSection(FI, Section)) {
96 // Emit DWARF .file directives in the outermost scope.
97 outputDwarfFileDirectives();
98 OS << "\t.section\t" << Section->getName() << '\n';
99 // DWARF sections are enclosed into braces - emit the open one.
100 OS << "\t{\n";
101 HasSections = true;
102 }
103}
104
105void NVPTXTargetStreamer::emitRawBytes(StringRef Data) {
106 MCTargetStreamer::emitRawBytes(Data);
107 // TODO: enable this once the bug in the ptxas with the packed bytes is
108 // resolved. Currently, (it is confirmed by NVidia) it causes a crash in
109 // ptxas.
110#if 0
111 const MCAsmInfo &MAI = Streamer.getContext().getAsmInfo();
112 const char *Directive = MAI.getData8bitsDirective();
113 unsigned NumElements = Data.size();
114 const unsigned MaxLen = 40;
115 unsigned NumChunks = 1 + ((NumElements - 1) / MaxLen);
116 // Split the very long directives into several parts if the limit is
117 // specified.
118 for (unsigned I = 0; I < NumChunks; ++I) {
119 SmallString<128> Str;
120 raw_svector_ostream OS(Str);
121
122 const char *Label = Directive;
123 for (auto It = std::next(Data.bytes_begin(), I * MaxLen),
124 End = (I == NumChunks - 1)
125 ? Data.bytes_end()
126 : std::next(Data.bytes_begin(), (I + 1) * MaxLen);
127 It != End; ++It) {
128 OS << Label << (unsigned)*It;
129 if (Label == Directive)
130 Label = ",";
131 }
132 Streamer.emitRawText(OS.str());
133 }
134#endif
135}
136
137void NVPTXTargetStreamer::emitValue(const MCExpr *Value) {
138 if (Value->getKind() == MCExpr::SymbolRef) {
139 const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(Val: *Value);
140 StringRef SymName = SRE.getSymbol().getName();
141 if (!SymName.starts_with(Prefix: ".debug")) {
142 Streamer.emitRawText(String: NVPTX::getValidPTXIdentifier(Name: SymName));
143 return;
144 }
145 // Fall through to the normal printing.
146 }
147 // Otherwise, print the Value normally.
148 MCTargetStreamer::emitValue(Value);
149}
150
151//
152// NVPTXAsmTargetStreamer Implementation
153//
154
155NVPTXAsmTargetStreamer::NVPTXAsmTargetStreamer(MCStreamer &S,
156 formatted_raw_ostream &OS)
157 : NVPTXTargetStreamer(S), OS(OS) {}
158NVPTXAsmTargetStreamer::~NVPTXAsmTargetStreamer() = default;
159
160void NVPTXAsmTargetStreamer::emitBanner() {
161 OS << "//\n"
162 "// Generated by LLVM NVPTX Back-End\n"
163 "//\n"
164 "\n";
165}
166
167void NVPTXAsmTargetStreamer::emitVersionDirective(unsigned PTXVersion) {
168 OS << ".version " << (PTXVersion / 10) << "." << (PTXVersion % 10) << "\n";
169}
170
171void NVPTXAsmTargetStreamer::emitTargetDirective(StringRef Target,
172 bool TexModeIndependent,
173 bool HasDebug) {
174 OS << ".target " << Target;
175 if (TexModeIndependent)
176 OS << ", texmode_independent";
177 if (HasDebug)
178 OS << ", debug";
179 OS << "\n";
180}
181
182void NVPTXAsmTargetStreamer::emitAddressSizeDirective(unsigned AddrSize) {
183 OS << ".address_size " << AddrSize << "\n"
184 << "\n";
185}
186
187void NVPTXAsmTargetStreamer::emitBranchTargetsDirective(
188 ArrayRef<const MCSymbol *> Targets) {
189 const MCAsmInfo &MAI = getStreamer().getContext().getAsmInfo();
190 OS << "\t.branchtargets\n\t\t";
191 interleave(
192 c: Targets, os&: OS, each_fn: [&](const MCSymbol *Target) { Target->print(OS, MAI: &MAI); },
193 separator: ",\n\t\t");
194 OS << ";\n";
195}
196
197void NVPTXAsmTargetStreamer::emitRegDirective(unsigned SizeInBits,
198 StringRef Name,
199 std::optional<unsigned> Count) {
200 OS << "\t.reg ";
201 if (SizeInBits == 1)
202 OS << ".pred";
203 else
204 OS << ".b" << SizeInBits;
205
206 OS << " \t" << Name;
207 if (Count)
208 OS << "<" << *Count << ">";
209 OS << ";\n";
210}
211
212void NVPTXAsmTargetStreamer::emitLocalDirective(Align Alignment,
213 const MCSymbol *Name,
214 uint64_t Size) {
215 const MCAsmInfo &MAI = getStreamer().getContext().getAsmInfo();
216 OS << "\t.local .align " << Alignment.value() << " .b8 \t";
217 Name->print(OS, MAI: &MAI);
218 OS << "[" << Size << "];\n";
219}
220
221void NVPTXAsmTargetStreamer::emitAliasDirective(const MCSymbol *Name,
222 const MCSymbol *Aliasee) {
223 const MCAsmInfo &MAI = getStreamer().getContext().getAsmInfo();
224 OS << ".alias ";
225 Name->print(OS, MAI: &MAI);
226 OS << ", ";
227 Aliasee->print(OS, MAI: &MAI);
228 OS << ";\n";
229}
230
231void NVPTXAsmTargetStreamer::emitPragmaDirective(StringRef Pragma) {
232 OS << "\t.pragma \"" << Pragma << "\";\n";
233}
234
235void NVPTXAsmTargetStreamer::emitEmptySectionDirective(StringRef Name) {
236 OS << "\t.section\t" << Name << "\t{\t}\n";
237}
238