/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUHSAMetadataStreamer.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- AMDGPUHSAMetadataStreamer.cpp --------------------------*- C++ -*-===// |
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 | | /// \file |
11 | | /// AMDGPU HSA Metadata Streamer. |
12 | | /// |
13 | | // |
14 | | //===----------------------------------------------------------------------===// |
15 | | |
16 | | #include "AMDGPUHSAMetadataStreamer.h" |
17 | | #include "AMDGPU.h" |
18 | | #include "llvm/ADT/StringSwitch.h" |
19 | | #include "llvm/IR/Constants.h" |
20 | | #include "llvm/IR/Module.h" |
21 | | #include "llvm/Support/raw_ostream.h" |
22 | | |
23 | | namespace llvm { |
24 | | |
25 | | static cl::opt<bool> DumpHSAMetadata( |
26 | | "amdgpu-dump-hsa-metadata", |
27 | | cl::desc("Dump AMDGPU HSA Metadata")); |
28 | | static cl::opt<bool> VerifyHSAMetadata( |
29 | | "amdgpu-verify-hsa-metadata", |
30 | | cl::desc("Verify AMDGPU HSA Metadata")); |
31 | | |
32 | | namespace AMDGPU { |
33 | | namespace HSAMD { |
34 | | |
35 | 4 | void MetadataStreamer::dump(StringRef HSAMetadataString) const { |
36 | 4 | errs() << "AMDGPU HSA Metadata:\n" << HSAMetadataString << '\n'; |
37 | 4 | } |
38 | | |
39 | 4 | void MetadataStreamer::verify(StringRef HSAMetadataString) const { |
40 | 4 | errs() << "AMDGPU HSA Metadata Parser Test: "; |
41 | 4 | |
42 | 4 | HSAMD::Metadata FromHSAMetadataString; |
43 | 4 | if (fromString(HSAMetadataString, FromHSAMetadataString)) { |
44 | 0 | errs() << "FAIL\n"; |
45 | 0 | return; |
46 | 0 | } |
47 | 4 | |
48 | 4 | std::string ToHSAMetadataString; |
49 | 4 | if (toString(FromHSAMetadataString, ToHSAMetadataString)) { |
50 | 0 | errs() << "FAIL\n"; |
51 | 0 | return; |
52 | 0 | } |
53 | 4 | |
54 | 4 | errs() << (HSAMetadataString == ToHSAMetadataString ? "PASS" : "FAIL"0 ) |
55 | 4 | << '\n'; |
56 | 4 | if (HSAMetadataString != ToHSAMetadataString) { |
57 | 0 | errs() << "Original input: " << HSAMetadataString << '\n' |
58 | 0 | << "Produced output: " << ToHSAMetadataString << '\n'; |
59 | 0 | } |
60 | 4 | } |
61 | | |
62 | 5.67k | AccessQualifier MetadataStreamer::getAccessQualifier(StringRef AccQual) const { |
63 | 5.67k | if (AccQual.empty()) |
64 | 5.33k | return AccessQualifier::Unknown; |
65 | 337 | |
66 | 337 | return StringSwitch<AccessQualifier>(AccQual) |
67 | 337 | .Case("read_only", AccessQualifier::ReadOnly) |
68 | 337 | .Case("write_only", AccessQualifier::WriteOnly) |
69 | 337 | .Case("read_write", AccessQualifier::ReadWrite) |
70 | 337 | .Default(AccessQualifier::Default); |
71 | 337 | } |
72 | | |
73 | | AddressSpaceQualifier MetadataStreamer::getAddressSpaceQualifer( |
74 | 3.46k | unsigned AddressSpace) const { |
75 | 3.46k | if (AddressSpace == AMDGPUASI.PRIVATE_ADDRESS) |
76 | 22 | return AddressSpaceQualifier::Private; |
77 | 3.44k | if (AddressSpace == AMDGPUASI.GLOBAL_ADDRESS) |
78 | 2.78k | return AddressSpaceQualifier::Global; |
79 | 660 | if (AddressSpace == AMDGPUASI.CONSTANT_ADDRESS) |
80 | 206 | return AddressSpaceQualifier::Constant; |
81 | 454 | if (AddressSpace == AMDGPUASI.LOCAL_ADDRESS) |
82 | 175 | return AddressSpaceQualifier::Local; |
83 | 279 | if (AddressSpace == AMDGPUASI.FLAT_ADDRESS) |
84 | 278 | return AddressSpaceQualifier::Generic; |
85 | 1 | if (AddressSpace == AMDGPUASI.REGION_ADDRESS) |
86 | 1 | return AddressSpaceQualifier::Region; |
87 | 0 | |
88 | 0 | llvm_unreachable("Unknown address space qualifier"); |
89 | 0 | } |
90 | | |
91 | | ValueKind MetadataStreamer::getValueKind(Type *Ty, StringRef TypeQual, |
92 | 4.34k | StringRef BaseTypeName) const { |
93 | 4.34k | if (TypeQual.find("pipe") != StringRef::npos) |
94 | 6 | return ValueKind::Pipe; |
95 | 4.33k | |
96 | 4.33k | return StringSwitch<ValueKind>(BaseTypeName) |
97 | 4.33k | .Case("image1d_t", ValueKind::Image) |
98 | 4.33k | .Case("image1d_array_t", ValueKind::Image) |
99 | 4.33k | .Case("image1d_buffer_t", ValueKind::Image) |
100 | 4.33k | .Case("image2d_t", ValueKind::Image) |
101 | 4.33k | .Case("image2d_array_t", ValueKind::Image) |
102 | 4.33k | .Case("image2d_array_depth_t", ValueKind::Image) |
103 | 4.33k | .Case("image2d_array_msaa_t", ValueKind::Image) |
104 | 4.33k | .Case("image2d_array_msaa_depth_t", ValueKind::Image) |
105 | 4.33k | .Case("image2d_depth_t", ValueKind::Image) |
106 | 4.33k | .Case("image2d_msaa_t", ValueKind::Image) |
107 | 4.33k | .Case("image2d_msaa_depth_t", ValueKind::Image) |
108 | 4.33k | .Case("image3d_t", ValueKind::Image) |
109 | 4.33k | .Case("sampler_t", ValueKind::Sampler) |
110 | 4.33k | .Case("queue_t", ValueKind::Queue) |
111 | 4.33k | .Default(isa<PointerType>(Ty) ? |
112 | 2.79k | (Ty->getPointerAddressSpace() == |
113 | 2.79k | AMDGPUASI.LOCAL_ADDRESS ? |
114 | 175 | ValueKind::DynamicSharedPointer : |
115 | 2.79k | ValueKind::GlobalBuffer2.62k ) : |
116 | 4.33k | ValueKind::ByValue1.53k ); |
117 | 4.33k | } |
118 | | |
119 | 10.7k | ValueType MetadataStreamer::getValueType(Type *Ty, StringRef TypeName) const { |
120 | 10.7k | switch (Ty->getTypeID()) { |
121 | 10.7k | case Type::IntegerTyID: { |
122 | 4.44k | auto Signed = !TypeName.startswith("u"); |
123 | 4.44k | switch (Ty->getIntegerBitWidth()) { |
124 | 4.44k | case 8: |
125 | 1.05k | return Signed ? ValueType::I8 : ValueType::U80 ; |
126 | 4.44k | case 16: |
127 | 426 | return Signed ? ValueType::I16420 : ValueType::U166 ; |
128 | 4.44k | case 32: |
129 | 2.01k | return Signed ? ValueType::I32 : ValueType::U320 ; |
130 | 4.44k | case 64: |
131 | 892 | return Signed ? ValueType::I64886 : ValueType::U646 ; |
132 | 4.44k | default: |
133 | 54 | return ValueType::Struct; |
134 | 0 | } |
135 | 0 | } |
136 | 638 | case Type::HalfTyID: |
137 | 638 | return ValueType::F16; |
138 | 221 | case Type::FloatTyID: |
139 | 221 | return ValueType::F32; |
140 | 100 | case Type::DoubleTyID: |
141 | 100 | return ValueType::F64; |
142 | 3.48k | case Type::PointerTyID: |
143 | 3.48k | return getValueType(Ty->getPointerElementType(), TypeName); |
144 | 1.55k | case Type::VectorTyID: |
145 | 1.55k | return getValueType(Ty->getVectorElementType(), TypeName); |
146 | 272 | default: |
147 | 272 | return ValueType::Struct; |
148 | 10.7k | } |
149 | 10.7k | } |
150 | | |
151 | 66 | std::string MetadataStreamer::getTypeName(Type *Ty, bool Signed) const { |
152 | 66 | switch (Ty->getTypeID()) { |
153 | 66 | case Type::IntegerTyID: { |
154 | 36 | if (!Signed) |
155 | 6 | return (Twine('u') + getTypeName(Ty, true)).str(); |
156 | 30 | |
157 | 30 | auto BitWidth = Ty->getIntegerBitWidth(); |
158 | 30 | switch (BitWidth) { |
159 | 30 | case 8: |
160 | 6 | return "char"; |
161 | 30 | case 16: |
162 | 6 | return "short"; |
163 | 30 | case 32: |
164 | 12 | return "int"; |
165 | 30 | case 64: |
166 | 6 | return "long"; |
167 | 30 | default: |
168 | 0 | return (Twine('i') + Twine(BitWidth)).str(); |
169 | 0 | } |
170 | 0 | } |
171 | 6 | case Type::HalfTyID: |
172 | 6 | return "half"; |
173 | 6 | case Type::FloatTyID: |
174 | 6 | return "float"; |
175 | 6 | case Type::DoubleTyID: |
176 | 6 | return "double"; |
177 | 6 | case Type::VectorTyID: { |
178 | 6 | auto VecTy = cast<VectorType>(Ty); |
179 | 6 | auto ElTy = VecTy->getElementType(); |
180 | 6 | auto NumElements = VecTy->getVectorNumElements(); |
181 | 6 | return (Twine(getTypeName(ElTy, Signed)) + Twine(NumElements)).str(); |
182 | 0 | } |
183 | 6 | default: |
184 | 6 | return "unknown"; |
185 | 66 | } |
186 | 66 | } |
187 | | |
188 | | std::vector<uint32_t> MetadataStreamer::getWorkGroupDimensions( |
189 | 12 | MDNode *Node) const { |
190 | 12 | std::vector<uint32_t> Dims; |
191 | 12 | if (Node->getNumOperands() != 3) |
192 | 0 | return Dims; |
193 | 12 | |
194 | 12 | for (auto &Op : Node->operands()) |
195 | 36 | Dims.push_back(mdconst::extract<ConstantInt>(Op)->getZExtValue()); |
196 | 12 | return Dims; |
197 | 12 | } |
198 | | |
199 | 298 | void MetadataStreamer::emitVersion() { |
200 | 298 | auto &Version = HSAMetadata.mVersion; |
201 | 298 | |
202 | 298 | Version.push_back(VersionMajor); |
203 | 298 | Version.push_back(VersionMinor); |
204 | 298 | } |
205 | | |
206 | 298 | void MetadataStreamer::emitPrintf(const Module &Mod) { |
207 | 298 | auto &Printf = HSAMetadata.mPrintf; |
208 | 298 | |
209 | 298 | auto Node = Mod.getNamedMetadata("llvm.printf.fmts"); |
210 | 298 | if (!Node) |
211 | 292 | return; |
212 | 6 | |
213 | 6 | for (auto Op : Node->operands()) |
214 | 12 | if (Op->getNumOperands()) |
215 | 12 | Printf.push_back(cast<MDString>(Op->getOperand(0))->getString()); |
216 | 6 | } |
217 | | |
218 | 2.28k | void MetadataStreamer::emitKernelLanguage(const Function &Func) { |
219 | 2.28k | auto &Kernel = HSAMetadata.mKernels.back(); |
220 | 2.28k | |
221 | 2.28k | // TODO: What about other languages? |
222 | 2.28k | auto Node = Func.getParent()->getNamedMetadata("opencl.ocl.version"); |
223 | 2.28k | if (!Node || !Node->getNumOperands()222 ) |
224 | 2.06k | return; |
225 | 222 | auto Op0 = Node->getOperand(0); |
226 | 222 | if (Op0->getNumOperands() <= 1) |
227 | 0 | return; |
228 | 222 | |
229 | 222 | Kernel.mLanguage = "OpenCL C"; |
230 | 222 | Kernel.mLanguageVersion.push_back( |
231 | 222 | mdconst::extract<ConstantInt>(Op0->getOperand(0))->getZExtValue()); |
232 | 222 | Kernel.mLanguageVersion.push_back( |
233 | 222 | mdconst::extract<ConstantInt>(Op0->getOperand(1))->getZExtValue()); |
234 | 222 | } |
235 | | |
236 | 2.28k | void MetadataStreamer::emitKernelAttrs(const Function &Func) { |
237 | 2.28k | auto &Attrs = HSAMetadata.mKernels.back().mAttrs; |
238 | 2.28k | |
239 | 2.28k | if (auto Node = Func.getMetadata("reqd_work_group_size")) |
240 | 6 | Attrs.mReqdWorkGroupSize = getWorkGroupDimensions(Node); |
241 | 2.28k | if (auto Node = Func.getMetadata("work_group_size_hint")) |
242 | 6 | Attrs.mWorkGroupSizeHint = getWorkGroupDimensions(Node); |
243 | 2.28k | if (auto Node = Func.getMetadata("vec_type_hint")) { |
244 | 54 | Attrs.mVecTypeHint = getTypeName( |
245 | 54 | cast<ValueAsMetadata>(Node->getOperand(0))->getType(), |
246 | 54 | mdconst::extract<ConstantInt>(Node->getOperand(1))->getZExtValue()); |
247 | 54 | } |
248 | 2.28k | if (Func.hasFnAttribute("runtime-handle")) { |
249 | 6 | Attrs.mRuntimeHandle = |
250 | 6 | Func.getFnAttribute("runtime-handle").getValueAsString().str(); |
251 | 6 | } |
252 | 2.28k | } |
253 | | |
254 | 2.28k | void MetadataStreamer::emitKernelArgs(const Function &Func) { |
255 | 2.28k | for (auto &Arg : Func.args()) |
256 | 4.34k | emitKernelArg(Arg); |
257 | 2.28k | |
258 | 2.28k | // TODO: What about other languages? |
259 | 2.28k | if (!Func.getParent()->getNamedMetadata("opencl.ocl.version")) |
260 | 2.06k | return; |
261 | 222 | |
262 | 222 | auto &DL = Func.getParent()->getDataLayout(); |
263 | 222 | auto Int64Ty = Type::getInt64Ty(Func.getContext()); |
264 | 222 | |
265 | 222 | emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetX); |
266 | 222 | emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetY); |
267 | 222 | emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetZ); |
268 | 222 | |
269 | 222 | auto Int8PtrTy = Type::getInt8PtrTy(Func.getContext(), |
270 | 222 | AMDGPUASI.GLOBAL_ADDRESS); |
271 | 222 | |
272 | 222 | // Emit "printf buffer" argument if printf is used, otherwise emit dummy |
273 | 222 | // "none" argument. |
274 | 222 | if (Func.getParent()->getNamedMetadata("llvm.printf.fmts")) |
275 | 204 | emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenPrintfBuffer); |
276 | 18 | else |
277 | 18 | emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone); |
278 | 222 | |
279 | 222 | // Emit "default queue" and "completion action" arguments if enqueue kernel is |
280 | 222 | // used, otherwise emit dummy "none" arguments. |
281 | 222 | if (Func.hasFnAttribute("calls-enqueue-kernel")) { |
282 | 8 | emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenDefaultQueue); |
283 | 8 | emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenCompletionAction); |
284 | 214 | } else { |
285 | 214 | emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone); |
286 | 214 | emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone); |
287 | 214 | } |
288 | 222 | } |
289 | | |
290 | 4.34k | void MetadataStreamer::emitKernelArg(const Argument &Arg) { |
291 | 4.34k | auto Func = Arg.getParent(); |
292 | 4.34k | auto ArgNo = Arg.getArgNo(); |
293 | 4.34k | const MDNode *Node; |
294 | 4.34k | |
295 | 4.34k | StringRef Name; |
296 | 4.34k | Node = Func->getMetadata("kernel_arg_name"); |
297 | 4.34k | if (Node && ArgNo < Node->getNumOperands()0 ) |
298 | 0 | Name = cast<MDString>(Node->getOperand(ArgNo))->getString(); |
299 | 4.34k | else if (Arg.hasName()) |
300 | 4.16k | Name = Arg.getName(); |
301 | 4.34k | |
302 | 4.34k | StringRef TypeName; |
303 | 4.34k | Node = Func->getMetadata("kernel_arg_type"); |
304 | 4.34k | if (Node && ArgNo < Node->getNumOperands()382 ) |
305 | 370 | TypeName = cast<MDString>(Node->getOperand(ArgNo))->getString(); |
306 | 4.34k | |
307 | 4.34k | StringRef BaseTypeName; |
308 | 4.34k | Node = Func->getMetadata("kernel_arg_base_type"); |
309 | 4.34k | if (Node && ArgNo < Node->getNumOperands()382 ) |
310 | 370 | BaseTypeName = cast<MDString>(Node->getOperand(ArgNo))->getString(); |
311 | 4.34k | |
312 | 4.34k | StringRef AccQual; |
313 | 4.34k | if (Arg.getType()->isPointerTy() && Arg.onlyReadsMemory()2.80k && |
314 | 4.34k | Arg.hasNoAliasAttr()44 ) { |
315 | 4 | AccQual = "read_only"; |
316 | 4.33k | } else { |
317 | 4.33k | Node = Func->getMetadata("kernel_arg_access_qual"); |
318 | 4.33k | if (Node && ArgNo < Node->getNumOperands()345 ) |
319 | 333 | AccQual = cast<MDString>(Node->getOperand(ArgNo))->getString(); |
320 | 4.33k | } |
321 | 4.34k | |
322 | 4.34k | StringRef TypeQual; |
323 | 4.34k | Node = Func->getMetadata("kernel_arg_type_qual"); |
324 | 4.34k | if (Node && ArgNo < Node->getNumOperands()346 ) |
325 | 334 | TypeQual = cast<MDString>(Node->getOperand(ArgNo))->getString(); |
326 | 4.34k | |
327 | 4.34k | Type *Ty = Arg.getType(); |
328 | 4.34k | const DataLayout &DL = Func->getParent()->getDataLayout(); |
329 | 4.34k | |
330 | 4.34k | unsigned PointeeAlign = 0; |
331 | 4.34k | if (auto PtrTy = dyn_cast<PointerType>(Ty)) { |
332 | 2.80k | if (PtrTy->getAddressSpace() == AMDGPUASI.LOCAL_ADDRESS) { |
333 | 175 | PointeeAlign = Arg.getParamAlignment(); |
334 | 175 | if (PointeeAlign == 0) |
335 | 132 | PointeeAlign = DL.getABITypeAlignment(PtrTy->getElementType()); |
336 | 175 | } |
337 | 2.80k | } |
338 | 4.34k | |
339 | 4.34k | emitKernelArg(DL, Ty, getValueKind(Arg.getType(), TypeQual, BaseTypeName), |
340 | 4.34k | PointeeAlign, Name, TypeName, BaseTypeName, AccQual, TypeQual); |
341 | 4.34k | } |
342 | | |
343 | | void MetadataStreamer::emitKernelArg(const DataLayout &DL, Type *Ty, |
344 | | ValueKind ValueKind, |
345 | | unsigned PointeeAlign, |
346 | | StringRef Name, |
347 | | StringRef TypeName, StringRef BaseTypeName, |
348 | 5.67k | StringRef AccQual, StringRef TypeQual) { |
349 | 5.67k | HSAMetadata.mKernels.back().mArgs.push_back(Kernel::Arg::Metadata()); |
350 | 5.67k | auto &Arg = HSAMetadata.mKernels.back().mArgs.back(); |
351 | 5.67k | |
352 | 5.67k | Arg.mName = Name; |
353 | 5.67k | Arg.mTypeName = TypeName; |
354 | 5.67k | Arg.mSize = DL.getTypeAllocSize(Ty); |
355 | 5.67k | Arg.mAlign = DL.getABITypeAlignment(Ty); |
356 | 5.67k | Arg.mValueKind = ValueKind; |
357 | 5.67k | Arg.mValueType = getValueType(Ty, BaseTypeName); |
358 | 5.67k | Arg.mPointeeAlign = PointeeAlign; |
359 | 5.67k | |
360 | 5.67k | if (auto PtrTy = dyn_cast<PointerType>(Ty)) |
361 | 3.46k | Arg.mAddrSpaceQual = getAddressSpaceQualifer(PtrTy->getAddressSpace()); |
362 | 5.67k | |
363 | 5.67k | Arg.mAccQual = getAccessQualifier(AccQual); |
364 | 5.67k | |
365 | 5.67k | // TODO: Emit Arg.mActualAccQual. |
366 | 5.67k | |
367 | 5.67k | SmallVector<StringRef, 1> SplitTypeQuals; |
368 | 5.67k | TypeQual.split(SplitTypeQuals, " ", -1, false); |
369 | 5.67k | for (StringRef Key : SplitTypeQuals) { |
370 | 26 | auto P = StringSwitch<bool*>(Key) |
371 | 26 | .Case("const", &Arg.mIsConst) |
372 | 26 | .Case("restrict", &Arg.mIsRestrict) |
373 | 26 | .Case("volatile", &Arg.mIsVolatile) |
374 | 26 | .Case("pipe", &Arg.mIsPipe) |
375 | 26 | .Default(nullptr); |
376 | 26 | if (P) |
377 | 26 | *P = true; |
378 | 26 | } |
379 | 5.67k | } |
380 | | |
381 | 298 | void MetadataStreamer::begin(const Module &Mod) { |
382 | 298 | AMDGPUASI = getAMDGPUAS(Mod); |
383 | 298 | emitVersion(); |
384 | 298 | emitPrintf(Mod); |
385 | 298 | } |
386 | | |
387 | 298 | void MetadataStreamer::end() { |
388 | 298 | std::string HSAMetadataString; |
389 | 298 | if (toString(HSAMetadata, HSAMetadataString)) |
390 | 0 | return; |
391 | 298 | |
392 | 298 | if (DumpHSAMetadata) |
393 | 4 | dump(HSAMetadataString); |
394 | 298 | if (VerifyHSAMetadata) |
395 | 4 | verify(HSAMetadataString); |
396 | 298 | } |
397 | | |
398 | | void MetadataStreamer::emitKernel( |
399 | | const Function &Func, |
400 | | const Kernel::CodeProps::Metadata &CodeProps, |
401 | 2.29k | const Kernel::DebugProps::Metadata &DebugProps) { |
402 | 2.29k | if (Func.getCallingConv() != CallingConv::AMDGPU_KERNEL) |
403 | 3 | return; |
404 | 2.28k | |
405 | 2.28k | HSAMetadata.mKernels.push_back(Kernel::Metadata()); |
406 | 2.28k | auto &Kernel = HSAMetadata.mKernels.back(); |
407 | 2.28k | |
408 | 2.28k | Kernel.mName = Func.getName(); |
409 | 2.28k | Kernel.mSymbolName = (Twine(Func.getName()) + Twine("@kd")).str(); |
410 | 2.28k | emitKernelLanguage(Func); |
411 | 2.28k | emitKernelAttrs(Func); |
412 | 2.28k | emitKernelArgs(Func); |
413 | 2.28k | HSAMetadata.mKernels.back().mCodeProps = CodeProps; |
414 | 2.28k | HSAMetadata.mKernels.back().mDebugProps = DebugProps; |
415 | 2.28k | } |
416 | | |
417 | | } // end namespace HSAMD |
418 | | } // end namespace AMDGPU |
419 | | } // end namespace llvm |