1 //===-- AMDGPUTargetStreamer.cpp - Mips Target Streamer Methods -----------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file provides AMDGPU specific target streamer methods.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "AMDGPUTargetStreamer.h"
15 #include "AMDGPU.h"
16 #include "SIDefines.h"
17 #include "Utils/AMDGPUBaseInfo.h"
18 #include "Utils/AMDKernelCodeTUtils.h"
19 #include "llvm/ADT/Twine.h"
20 #include "llvm/BinaryFormat/ELF.h"
21 #include "llvm/IR/Constants.h"
22 #include "llvm/IR/Function.h"
23 #include "llvm/IR/Metadata.h"
24 #include "llvm/IR/Module.h"
25 #include "llvm/MC/MCContext.h"
26 #include "llvm/MC/MCELFStreamer.h"
27 #include "llvm/MC/MCObjectFileInfo.h"
28 #include "llvm/MC/MCSectionELF.h"
29 #include "llvm/Support/FormattedStream.h"
30 
31 namespace llvm {
32 #include "AMDGPUPTNote.h"
33 }
34 
35 using namespace llvm;
36 using namespace llvm::AMDGPU;
37 
38 //===----------------------------------------------------------------------===//
39 // AMDGPUTargetStreamer
40 //===----------------------------------------------------------------------===//
41 
42 AMDGPUTargetStreamer::AMDGPUTargetStreamer(MCStreamer &S)
43     : MCTargetStreamer(S) {}
44 
45 bool AMDGPUTargetStreamer::EmitHSAMetadata(StringRef HSAMetadataString) {
46   HSAMD::Metadata HSAMetadata;
47   if (HSAMD::fromString(HSAMetadataString, HSAMetadata))
48     return false;
49 
50   return EmitHSAMetadata(HSAMetadata);
51 }
52 
53 //===----------------------------------------------------------------------===//
54 // AMDGPUTargetAsmStreamer
55 //===----------------------------------------------------------------------===//
56 
57 AMDGPUTargetAsmStreamer::AMDGPUTargetAsmStreamer(MCStreamer &S,
58                                                  formatted_raw_ostream &OS)
59     : AMDGPUTargetStreamer(S), OS(OS) { }
60 
61 void
62 AMDGPUTargetAsmStreamer::EmitDirectiveHSACodeObjectVersion(uint32_t Major,
63                                                            uint32_t Minor) {
64   OS << "\t.hsa_code_object_version " <<
65         Twine(Major) << "," << Twine(Minor) << '\n';
66 }
67 
68 void
69 AMDGPUTargetAsmStreamer::EmitDirectiveHSACodeObjectISA(uint32_t Major,
70                                                        uint32_t Minor,
71                                                        uint32_t Stepping,
72                                                        StringRef VendorName,
73                                                        StringRef ArchName) {
74   OS << "\t.hsa_code_object_isa " <<
75         Twine(Major) << "," << Twine(Minor) << "," << Twine(Stepping) <<
76         ",\"" << VendorName << "\",\"" << ArchName << "\"\n";
77 
78 }
79 
80 void
81 AMDGPUTargetAsmStreamer::EmitAMDKernelCodeT(const amd_kernel_code_t &Header) {
82   OS << "\t.amd_kernel_code_t\n";
83   dumpAmdKernelCode(&Header, OS, "\t\t");
84   OS << "\t.end_amd_kernel_code_t\n";
85 }
86 
87 void AMDGPUTargetAsmStreamer::EmitAMDGPUSymbolType(StringRef SymbolName,
88                                                    unsigned Type) {
89   switch (Type) {
90     default: llvm_unreachable("Invalid AMDGPU symbol type");
91     case ELF::STT_AMDGPU_HSA_KERNEL:
92       OS << "\t.amdgpu_hsa_kernel " << SymbolName << '\n' ;
93       break;
94   }
95 }
96 
97 bool AMDGPUTargetAsmStreamer::EmitHSAMetadata(
98     const AMDGPU::HSAMD::Metadata &HSAMetadata) {
99   std::string HSAMetadataString;
100   if (HSAMD::toString(HSAMetadata, HSAMetadataString))
101     return false;
102 
103   OS << '\t' << HSAMD::AssemblerDirectiveBegin << '\n';
104   OS << HSAMetadataString << '\n';
105   OS << '\t' << HSAMD::AssemblerDirectiveEnd << '\n';
106   return true;
107 }
108 
109 bool AMDGPUTargetAsmStreamer::EmitPALMetadata(
110     const PALMD::Metadata &PALMetadata) {
111   std::string PALMetadataString;
112   if (PALMD::toString(PALMetadata, PALMetadataString))
113     return false;
114 
115   OS << '\t' << PALMD::AssemblerDirective << PALMetadataString << '\n';
116   return true;
117 }
118 
119 //===----------------------------------------------------------------------===//
120 // AMDGPUTargetELFStreamer
121 //===----------------------------------------------------------------------===//
122 
123 AMDGPUTargetELFStreamer::AMDGPUTargetELFStreamer(MCStreamer &S)
124     : AMDGPUTargetStreamer(S), Streamer(S) {}
125 
126 MCELFStreamer &AMDGPUTargetELFStreamer::getStreamer() {
127   return static_cast<MCELFStreamer &>(Streamer);
128 }
129 
130 void AMDGPUTargetELFStreamer::EmitAMDGPUNote(
131     const MCExpr *DescSZ, unsigned NoteType,
132     function_ref<void(MCELFStreamer &)> EmitDesc) {
133   auto &S = getStreamer();
134   auto &Context = S.getContext();
135 
136   auto NameSZ = sizeof(ElfNote::NoteName);
137 
138   S.PushSection();
139   S.SwitchSection(Context.getELFSection(
140     ElfNote::SectionName, ELF::SHT_NOTE, ELF::SHF_ALLOC));
141   S.EmitIntValue(NameSZ, 4);                                  // namesz
142   S.EmitValue(DescSZ, 4);                                     // descz
143   S.EmitIntValue(NoteType, 4);                                // type
144   S.EmitBytes(StringRef(ElfNote::NoteName, NameSZ));          // name
145   S.EmitValueToAlignment(4, 0, 1, 0);                         // padding 0
146   EmitDesc(S);                                                // desc
147   S.EmitValueToAlignment(4, 0, 1, 0);                         // padding 0
148   S.PopSection();
149 }
150 
151 void
152 AMDGPUTargetELFStreamer::EmitDirectiveHSACodeObjectVersion(uint32_t Major,
153                                                            uint32_t Minor) {
154 
155   EmitAMDGPUNote(
156     MCConstantExpr::create(8, getContext()),
157     ElfNote::NT_AMDGPU_HSA_CODE_OBJECT_VERSION,
158     [&](MCELFStreamer &OS){
159       OS.EmitIntValue(Major, 4);
160       OS.EmitIntValue(Minor, 4);
161     }
162   );
163 }
164 
165 void
166 AMDGPUTargetELFStreamer::EmitDirectiveHSACodeObjectISA(uint32_t Major,
167                                                        uint32_t Minor,
168                                                        uint32_t Stepping,
169                                                        StringRef VendorName,
170                                                        StringRef ArchName) {
171   uint16_t VendorNameSize = VendorName.size() + 1;
172   uint16_t ArchNameSize = ArchName.size() + 1;
173 
174   unsigned DescSZ = sizeof(VendorNameSize) + sizeof(ArchNameSize) +
175     sizeof(Major) + sizeof(Minor) + sizeof(Stepping) +
176     VendorNameSize + ArchNameSize;
177 
178   EmitAMDGPUNote(
179     MCConstantExpr::create(DescSZ, getContext()),
180     ElfNote::NT_AMDGPU_HSA_ISA,
181     [&](MCELFStreamer &OS) {
182       OS.EmitIntValue(VendorNameSize, 2);
183       OS.EmitIntValue(ArchNameSize, 2);
184       OS.EmitIntValue(Major, 4);
185       OS.EmitIntValue(Minor, 4);
186       OS.EmitIntValue(Stepping, 4);
187       OS.EmitBytes(VendorName);
188       OS.EmitIntValue(0, 1); // NULL terminate VendorName
189       OS.EmitBytes(ArchName);
190       OS.EmitIntValue(0, 1); // NULL terminte ArchName
191     }
192   );
193 }
194 
195 void
196 AMDGPUTargetELFStreamer::EmitAMDKernelCodeT(const amd_kernel_code_t &Header) {
197 
198   MCStreamer &OS = getStreamer();
199   OS.PushSection();
200   OS.EmitBytes(StringRef((const char*)&Header, sizeof(Header)));
201   OS.PopSection();
202 }
203 
204 void AMDGPUTargetELFStreamer::EmitAMDGPUSymbolType(StringRef SymbolName,
205                                                    unsigned Type) {
206   MCSymbolELF *Symbol = cast<MCSymbolELF>(
207       getStreamer().getContext().getOrCreateSymbol(SymbolName));
208   Symbol->setType(ELF::STT_AMDGPU_HSA_KERNEL);
209 }
210 
211 bool AMDGPUTargetELFStreamer::EmitHSAMetadata(
212     const AMDGPU::HSAMD::Metadata &HSAMetadata) {
213   std::string HSAMetadataString;
214   if (HSAMD::toString(HSAMetadata, HSAMetadataString))
215     return false;
216 
217   // Create two labels to mark the beginning and end of the desc field
218   // and a MCExpr to calculate the size of the desc field.
219   auto &Context = getContext();
220   auto *DescBegin = Context.createTempSymbol();
221   auto *DescEnd = Context.createTempSymbol();
222   auto *DescSZ = MCBinaryExpr::createSub(
223     MCSymbolRefExpr::create(DescEnd, Context),
224     MCSymbolRefExpr::create(DescBegin, Context), Context);
225 
226   EmitAMDGPUNote(
227     DescSZ,
228     ELF::NT_AMD_AMDGPU_HSA_METADATA,
229     [&](MCELFStreamer &OS) {
230       OS.EmitLabel(DescBegin);
231       OS.EmitBytes(HSAMetadataString);
232       OS.EmitLabel(DescEnd);
233     }
234   );
235   return true;
236 }
237 
238 bool AMDGPUTargetELFStreamer::EmitPALMetadata(
239     const PALMD::Metadata &PALMetadata) {
240   EmitAMDGPUNote(
241     MCConstantExpr::create(PALMetadata.size() * sizeof(uint32_t), getContext()),
242     ELF::NT_AMD_AMDGPU_PAL_METADATA,
243     [&](MCELFStreamer &OS){
244       for (auto I : PALMetadata)
245         OS.EmitIntValue(I, sizeof(uint32_t));
246     }
247   );
248   return true;
249 }
250