Line data Source code
1 : //===--- AMDGPUCodeObjectMetadataStreamer.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 : /// \brief AMDGPU Code Object Metadata Streamer.
12 : ///
13 : //
14 : //===----------------------------------------------------------------------===//
15 :
16 : #include "AMDGPUCodeObjectMetadataStreamer.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 72306 : static cl::opt<bool> DumpCodeObjectMetadata(
26 : "amdgpu-dump-comd",
27 144612 : cl::desc("Dump AMDGPU Code Object Metadata"));
28 72306 : static cl::opt<bool> VerifyCodeObjectMetadata(
29 : "amdgpu-verify-comd",
30 144612 : cl::desc("Verify AMDGPU Code Object Metadata"));
31 :
32 : namespace AMDGPU {
33 : namespace CodeObject {
34 :
35 6 : void MetadataStreamer::dump(StringRef YamlString) const {
36 12 : errs() << "AMDGPU Code Object Metadata:\n" << YamlString << '\n';
37 6 : }
38 :
39 6 : void MetadataStreamer::verify(StringRef YamlString) const {
40 6 : errs() << "AMDGPU Code Object Metadata Parser Test: ";
41 :
42 12 : CodeObject::Metadata FromYamlString;
43 12 : if (Metadata::fromYamlString(YamlString, FromYamlString)) {
44 0 : errs() << "FAIL\n";
45 0 : return;
46 : }
47 :
48 12 : std::string ToYamlString;
49 6 : if (Metadata::toYamlString(FromYamlString, ToYamlString)) {
50 0 : errs() << "FAIL\n";
51 : return;
52 : }
53 :
54 24 : errs() << (YamlString == ToYamlString ? "PASS" : "FAIL") << '\n';
55 6 : if (YamlString != ToYamlString) {
56 0 : errs() << "Original input: " << YamlString << '\n'
57 0 : << "Produced output: " << ToYamlString << '\n';
58 : }
59 : }
60 :
61 3257 : AccessQualifier MetadataStreamer::getAccessQualifier(StringRef AccQual) const {
62 3257 : if (AccQual.empty())
63 : return AccessQualifier::Unknown;
64 :
65 278 : return StringSwitch<AccessQualifier>(AccQual)
66 834 : .Case("read_only", AccessQualifier::ReadOnly)
67 834 : .Case("write_only", AccessQualifier::WriteOnly)
68 834 : .Case("read_write", AccessQualifier::ReadWrite)
69 556 : .Default(AccessQualifier::Default);
70 : }
71 :
72 2006 : AddressSpaceQualifier MetadataStreamer::getAddressSpaceQualifer(
73 : unsigned AddressSpace) const {
74 2006 : if (AddressSpace == AMDGPUASI.PRIVATE_ADDRESS)
75 : return AddressSpaceQualifier::Private;
76 1972 : if (AddressSpace == AMDGPUASI.GLOBAL_ADDRESS)
77 : return AddressSpaceQualifier::Global;
78 476 : if (AddressSpace == AMDGPUASI.CONSTANT_ADDRESS)
79 : return AddressSpaceQualifier::Constant;
80 313 : if (AddressSpace == AMDGPUASI.LOCAL_ADDRESS)
81 : return AddressSpaceQualifier::Local;
82 203 : if (AddressSpace == AMDGPUASI.FLAT_ADDRESS)
83 : return AddressSpaceQualifier::Generic;
84 0 : if (AddressSpace == AMDGPUASI.REGION_ADDRESS)
85 : return AddressSpaceQualifier::Region;
86 :
87 0 : llvm_unreachable("Unknown address space qualifier");
88 : }
89 :
90 2480 : ValueKind MetadataStreamer::getValueKind(Type *Ty, StringRef TypeQual,
91 : StringRef BaseTypeName) const {
92 2480 : if (TypeQual.find("pipe") != StringRef::npos)
93 : return ValueKind::Pipe;
94 :
95 2474 : return StringSwitch<ValueKind>(BaseTypeName)
96 7422 : .Case("image1d_t", ValueKind::Image)
97 7422 : .Case("image1d_array_t", ValueKind::Image)
98 7422 : .Case("image1d_buffer_t", ValueKind::Image)
99 7422 : .Case("image2d_t", ValueKind::Image)
100 7422 : .Case("image2d_array_t", ValueKind::Image)
101 7422 : .Case("image2d_array_depth_t", ValueKind::Image)
102 7422 : .Case("image2d_array_msaa_t", ValueKind::Image)
103 7422 : .Case("image2d_array_msaa_depth_t", ValueKind::Image)
104 7422 : .Case("image2d_depth_t", ValueKind::Image)
105 7422 : .Case("image2d_msaa_t", ValueKind::Image)
106 7422 : .Case("image2d_msaa_depth_t", ValueKind::Image)
107 7422 : .Case("image3d_t", ValueKind::Image)
108 7422 : .Case("sampler_t", ValueKind::Sampler)
109 7422 : .Case("queue_t", ValueKind::Queue)
110 7422 : .Default(isa<PointerType>(Ty) ?
111 3628 : (Ty->getPointerAddressSpace() ==
112 1814 : AMDGPUASI.LOCAL_ADDRESS ?
113 : ValueKind::DynamicSharedPointer :
114 : ValueKind::GlobalBuffer) :
115 2474 : ValueKind::ByValue);
116 : }
117 :
118 3257 : ValueType MetadataStreamer::getValueType(Type *Ty, StringRef TypeName) const {
119 6143 : switch (Ty->getTypeID()) {
120 2615 : case Type::IntegerTyID: {
121 5230 : auto Signed = !TypeName.startswith("u");
122 2615 : switch (Ty->getIntegerBitWidth()) {
123 430 : case 8:
124 430 : return Signed ? ValueType::I8 : ValueType::U8;
125 165 : case 16:
126 165 : return Signed ? ValueType::I16 : ValueType::U16;
127 1252 : case 32:
128 1252 : return Signed ? ValueType::I32 : ValueType::U32;
129 752 : case 64:
130 752 : return Signed ? ValueType::I64 : ValueType::U64;
131 : default:
132 : return ValueType::Struct;
133 : }
134 : }
135 : case Type::HalfTyID:
136 : return ValueType::F16;
137 94 : case Type::FloatTyID:
138 94 : return ValueType::F32;
139 59 : case Type::DoubleTyID:
140 59 : return ValueType::F64;
141 2021 : case Type::PointerTyID:
142 4042 : return getValueType(Ty->getPointerElementType(), TypeName);
143 865 : case Type::VectorTyID:
144 1730 : return getValueType(Ty->getVectorElementType(), TypeName);
145 108 : default:
146 108 : return ValueType::Struct;
147 : }
148 : }
149 :
150 66 : std::string MetadataStreamer::getTypeName(Type *Ty, bool Signed) const {
151 66 : switch (Ty->getTypeID()) {
152 36 : case Type::IntegerTyID: {
153 36 : if (!Signed)
154 30 : return (Twine('u') + getTypeName(Ty, true)).str();
155 :
156 30 : auto BitWidth = Ty->getIntegerBitWidth();
157 30 : switch (BitWidth) {
158 : case 8:
159 12 : return "char";
160 : case 16:
161 12 : return "short";
162 : case 32:
163 24 : return "int";
164 : case 64:
165 12 : return "long";
166 0 : default:
167 0 : return (Twine('i') + Twine(BitWidth)).str();
168 : }
169 : }
170 : case Type::HalfTyID:
171 12 : return "half";
172 : case Type::FloatTyID:
173 12 : return "float";
174 : case Type::DoubleTyID:
175 12 : return "double";
176 6 : case Type::VectorTyID: {
177 6 : auto VecTy = cast<VectorType>(Ty);
178 6 : auto ElTy = VecTy->getElementType();
179 12 : auto NumElements = VecTy->getVectorNumElements();
180 24 : return (Twine(getTypeName(ElTy, Signed)) + Twine(NumElements)).str();
181 : }
182 : default:
183 12 : return "unknown";
184 : }
185 : }
186 :
187 12 : std::vector<uint32_t> MetadataStreamer::getWorkGroupDimensions(
188 : MDNode *Node) const {
189 12 : std::vector<uint32_t> Dims;
190 12 : if (Node->getNumOperands() != 3)
191 : return Dims;
192 :
193 48 : for (auto &Op : Node->operands())
194 108 : Dims.push_back(mdconst::extract<ConstantInt>(Op)->getZExtValue());
195 : return Dims;
196 : }
197 :
198 240 : void MetadataStreamer::emitVersion() {
199 240 : auto &Version = CodeObjectMetadata.mVersion;
200 :
201 240 : Version.push_back(MetadataVersionMajor);
202 240 : Version.push_back(MetadataVersionMinor);
203 240 : }
204 :
205 240 : void MetadataStreamer::emitPrintf(const Module &Mod) {
206 240 : auto &Printf = CodeObjectMetadata.mPrintf;
207 :
208 240 : auto Node = Mod.getNamedMetadata("llvm.printf.fmts");
209 240 : if (!Node)
210 : return;
211 :
212 18 : for (auto Op : Node->operands())
213 12 : if (Op->getNumOperands())
214 60 : Printf.push_back(cast<MDString>(Op->getOperand(0))->getString());
215 : }
216 :
217 1661 : void MetadataStreamer::emitKernelLanguage(const Function &Func) {
218 3322 : auto &Kernel = CodeObjectMetadata.mKernels.back();
219 :
220 : // TODO: What about other languages?
221 3322 : auto Node = Func.getParent()->getNamedMetadata("opencl.ocl.version");
222 1661 : if (!Node || !Node->getNumOperands())
223 : return;
224 197 : auto Op0 = Node->getOperand(0);
225 197 : if (Op0->getNumOperands() <= 1)
226 : return;
227 :
228 394 : Kernel.mLanguage = "OpenCL C";
229 591 : Kernel.mLanguageVersion.push_back(
230 591 : mdconst::extract<ConstantInt>(Op0->getOperand(0))->getZExtValue());
231 591 : Kernel.mLanguageVersion.push_back(
232 591 : mdconst::extract<ConstantInt>(Op0->getOperand(1))->getZExtValue());
233 : }
234 :
235 1661 : void MetadataStreamer::emitKernelAttrs(const Function &Func) {
236 3322 : auto &Attrs = CodeObjectMetadata.mKernels.back().mAttrs;
237 :
238 3322 : if (auto Node = Func.getMetadata("reqd_work_group_size"))
239 18 : Attrs.mReqdWorkGroupSize = getWorkGroupDimensions(Node);
240 3322 : if (auto Node = Func.getMetadata("work_group_size_hint"))
241 18 : Attrs.mWorkGroupSizeHint = getWorkGroupDimensions(Node);
242 3322 : if (auto Node = Func.getMetadata("vec_type_hint")) {
243 270 : Attrs.mVecTypeHint = getTypeName(
244 : cast<ValueAsMetadata>(Node->getOperand(0))->getType(),
245 216 : mdconst::extract<ConstantInt>(Node->getOperand(1))->getZExtValue());
246 : }
247 1661 : }
248 :
249 1661 : void MetadataStreamer::emitKernelArgs(const Function &Func) {
250 4141 : for (auto &Arg : Func.args())
251 2480 : emitKernelArg(Arg);
252 :
253 : // TODO: What about other languages?
254 3322 : if (!Func.getParent()->getNamedMetadata("opencl.ocl.version"))
255 : return;
256 :
257 197 : auto &DL = Func.getParent()->getDataLayout();
258 197 : auto Int64Ty = Type::getInt64Ty(Func.getContext());
259 :
260 985 : emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetX);
261 985 : emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetY);
262 985 : emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetZ);
263 :
264 394 : if (!Func.getParent()->getNamedMetadata("llvm.printf.fmts"))
265 : return;
266 :
267 186 : auto Int8PtrTy = Type::getInt8PtrTy(Func.getContext(),
268 186 : AMDGPUASI.GLOBAL_ADDRESS);
269 930 : emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenPrintfBuffer);
270 : }
271 :
272 2480 : void MetadataStreamer::emitKernelArg(const Argument &Arg) {
273 2480 : auto Func = Arg.getParent();
274 2480 : auto ArgNo = Arg.getArgNo();
275 : const MDNode *Node;
276 :
277 2480 : StringRef TypeQual;
278 4960 : Node = Func->getMetadata("kernel_arg_type_qual");
279 2480 : if (Node && ArgNo < Node->getNumOperands())
280 552 : TypeQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
281 :
282 2480 : StringRef BaseTypeName;
283 4960 : Node = Func->getMetadata("kernel_arg_base_type");
284 2480 : if (Node && ArgNo < Node->getNumOperands())
285 624 : BaseTypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
286 :
287 2480 : StringRef AccQual;
288 4990 : if (Arg.getType()->isPointerTy() && Arg.onlyReadsMemory() &&
289 30 : Arg.hasNoAliasAttr()) {
290 3 : AccQual = "read_only";
291 : } else {
292 4954 : Node = Func->getMetadata("kernel_arg_access_qual");
293 2752 : if (Node && ArgNo < Node->getNumOperands())
294 550 : AccQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
295 : }
296 :
297 2480 : StringRef Name;
298 4960 : Node = Func->getMetadata("kernel_arg_name");
299 2480 : if (Node && ArgNo < Node->getNumOperands())
300 0 : Name = cast<MDString>(Node->getOperand(ArgNo))->getString();
301 :
302 2480 : StringRef TypeName;
303 4960 : Node = Func->getMetadata("kernel_arg_type");
304 2480 : if (Node && ArgNo < Node->getNumOperands())
305 624 : TypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
306 :
307 2480 : emitKernelArg(Func->getParent()->getDataLayout(), Arg.getType(),
308 : getValueKind(Arg.getType(), TypeQual, BaseTypeName), TypeQual,
309 : BaseTypeName, AccQual, Name, TypeName);
310 2480 : }
311 :
312 3257 : void MetadataStreamer::emitKernelArg(const DataLayout &DL, Type *Ty,
313 : ValueKind ValueKind, StringRef TypeQual,
314 : StringRef BaseTypeName, StringRef AccQual,
315 : StringRef Name, StringRef TypeName) {
316 13028 : CodeObjectMetadata.mKernels.back().mArgs.push_back(Kernel::Arg::Metadata());
317 9771 : auto &Arg = CodeObjectMetadata.mKernels.back().mArgs.back();
318 :
319 3257 : Arg.mSize = DL.getTypeAllocSize(Ty);
320 3257 : Arg.mAlign = DL.getABITypeAlignment(Ty);
321 3257 : Arg.mValueKind = ValueKind;
322 3257 : Arg.mValueType = getValueType(Ty, BaseTypeName);
323 :
324 2006 : if (auto PtrTy = dyn_cast<PointerType>(Ty)) {
325 2006 : auto ElTy = PtrTy->getElementType();
326 2006 : if (PtrTy->getAddressSpace() == AMDGPUASI.LOCAL_ADDRESS && ElTy->isSized())
327 110 : Arg.mPointeeAlign = DL.getABITypeAlignment(ElTy);
328 : }
329 :
330 3257 : Arg.mAccQual = getAccessQualifier(AccQual);
331 :
332 2006 : if (auto PtrTy = dyn_cast<PointerType>(Ty))
333 2006 : Arg.mAddrSpaceQual = getAddressSpaceQualifer(PtrTy->getAddressSpace());
334 :
335 6514 : SmallVector<StringRef, 1> SplitTypeQuals;
336 3257 : TypeQual.split(SplitTypeQuals, " ", -1, false);
337 9797 : for (StringRef Key : SplitTypeQuals) {
338 26 : auto P = StringSwitch<bool*>(Key)
339 78 : .Case("const", &Arg.mIsConst)
340 78 : .Case("pipe", &Arg.mIsPipe)
341 78 : .Case("restrict", &Arg.mIsRestrict)
342 78 : .Case("volatile", &Arg.mIsVolatile)
343 52 : .Default(nullptr);
344 26 : if (P)
345 26 : *P = true;
346 : }
347 :
348 6514 : Arg.mName = Name;
349 6514 : Arg.mTypeName = TypeName;
350 3257 : }
351 :
352 1661 : void MetadataStreamer::emitKernelCodeProps(
353 : const amd_kernel_code_t &KernelCode) {
354 3322 : auto &CodeProps = CodeObjectMetadata.mKernels.back().mCodeProps;
355 :
356 1661 : CodeProps.mKernargSegmentSize = KernelCode.kernarg_segment_byte_size;
357 1661 : CodeProps.mWorkgroupGroupSegmentSize =
358 1661 : KernelCode.workgroup_group_segment_byte_size;
359 1661 : CodeProps.mWorkitemPrivateSegmentSize =
360 1661 : KernelCode.workitem_private_segment_byte_size;
361 1661 : CodeProps.mWavefrontNumSGPRs = KernelCode.wavefront_sgpr_count;
362 1661 : CodeProps.mWorkitemNumVGPRs = KernelCode.workitem_vgpr_count;
363 1661 : CodeProps.mKernargSegmentAlign = KernelCode.kernarg_segment_alignment;
364 1661 : CodeProps.mGroupSegmentAlign = KernelCode.group_segment_alignment;
365 1661 : CodeProps.mPrivateSegmentAlign = KernelCode.private_segment_alignment;
366 1661 : CodeProps.mWavefrontSize = KernelCode.wavefront_size;
367 1661 : }
368 :
369 1661 : void MetadataStreamer::emitKernelDebugProps(
370 : const amd_kernel_code_t &KernelCode) {
371 1661 : if (!(KernelCode.code_properties & AMD_CODE_PROPERTY_IS_DEBUG_SUPPORTED))
372 : return;
373 :
374 6 : auto &DebugProps = CodeObjectMetadata.mKernels.back().mDebugProps;
375 :
376 : // FIXME: Need to pass down debugger ABI version through features. This is ok
377 : // for now because we only have one version.
378 6 : DebugProps.mDebuggerABIVersion.push_back(1);
379 6 : DebugProps.mDebuggerABIVersion.push_back(0);
380 3 : DebugProps.mReservedNumVGPRs = KernelCode.reserved_vgpr_count;
381 3 : DebugProps.mReservedFirstVGPR = KernelCode.reserved_vgpr_first;
382 3 : DebugProps.mPrivateSegmentBufferSGPR =
383 3 : KernelCode.debug_private_segment_buffer_sgpr;
384 3 : DebugProps.mWavefrontPrivateSegmentOffsetSGPR =
385 3 : KernelCode.debug_wavefront_private_segment_offset_sgpr;
386 : }
387 :
388 240 : void MetadataStreamer::begin(const Module &Mod) {
389 240 : AMDGPUASI = getAMDGPUAS(Mod);
390 240 : emitVersion();
391 240 : emitPrintf(Mod);
392 240 : }
393 :
394 1664 : void MetadataStreamer::emitKernel(const Function &Func,
395 : const amd_kernel_code_t &KernelCode) {
396 1664 : if (Func.getCallingConv() != CallingConv::AMDGPU_KERNEL)
397 : return;
398 :
399 3322 : CodeObjectMetadata.mKernels.push_back(Kernel::Metadata());
400 3322 : auto &Kernel = CodeObjectMetadata.mKernels.back();
401 :
402 4983 : Kernel.mName = Func.getName();
403 1661 : emitKernelLanguage(Func);
404 1661 : emitKernelAttrs(Func);
405 1661 : emitKernelArgs(Func);
406 1661 : emitKernelCodeProps(KernelCode);
407 1661 : emitKernelDebugProps(KernelCode);
408 : }
409 :
410 496 : ErrorOr<std::string> MetadataStreamer::toYamlString() {
411 992 : std::string YamlString;
412 496 : if (auto Error = Metadata::toYamlString(CodeObjectMetadata, YamlString))
413 0 : return Error;
414 :
415 496 : if (DumpCodeObjectMetadata)
416 6 : dump(YamlString);
417 496 : if (VerifyCodeObjectMetadata)
418 6 : verify(YamlString);
419 :
420 : return YamlString;
421 : }
422 :
423 262 : ErrorOr<std::string> MetadataStreamer::toYamlString(StringRef YamlString) {
424 786 : if (auto Error = Metadata::fromYamlString(YamlString, CodeObjectMetadata))
425 6 : return Error;
426 :
427 256 : return toYamlString();
428 : }
429 :
430 : } // end namespace CodeObject
431 : } // end namespace AMDGPU
432 216918 : } // end namespace llvm
|