blob: 4a576ca5c0b83737e071dcbd41e9034e19be4f82 [file] [log] [blame]
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +00001//===--- 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
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +000016#include "AMDGPUCodeObjectMetadataStreamer.h"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000017#include "AMDGPU.h"
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +000018#include "llvm/ADT/StringSwitch.h"
19#include "llvm/IR/Constants.h"
20#include "llvm/IR/Module.h"
Konstantin Zhuravlyov1e2b8782017-06-06 18:35:50 +000021#include "llvm/Support/raw_ostream.h"
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +000022
23namespace llvm {
24
25static cl::opt<bool> DumpCodeObjectMetadata(
26 "amdgpu-dump-comd",
27 cl::desc("Dump AMDGPU Code Object Metadata"));
28static cl::opt<bool> VerifyCodeObjectMetadata(
29 "amdgpu-verify-comd",
30 cl::desc("Verify AMDGPU Code Object Metadata"));
31
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +000032namespace AMDGPU {
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +000033namespace CodeObject {
34
35void MetadataStreamer::dump(StringRef YamlString) const {
36 errs() << "AMDGPU Code Object Metadata:\n" << YamlString << '\n';
37}
38
39void MetadataStreamer::verify(StringRef YamlString) const {
40 errs() << "AMDGPU Code Object Metadata Parser Test: ";
41
42 CodeObject::Metadata FromYamlString;
43 if (Metadata::fromYamlString(YamlString, FromYamlString)) {
44 errs() << "FAIL\n";
45 return;
46 }
47
48 std::string ToYamlString;
49 if (Metadata::toYamlString(FromYamlString, ToYamlString)) {
50 errs() << "FAIL\n";
51 return;
52 }
53
54 errs() << (YamlString == ToYamlString ? "PASS" : "FAIL") << '\n';
55 if (YamlString != ToYamlString) {
56 errs() << "Original input: " << YamlString << '\n'
57 << "Produced output: " << ToYamlString << '\n';
58 }
59}
60
61AccessQualifier MetadataStreamer::getAccessQualifier(StringRef AccQual) const {
62 if (AccQual.empty())
63 return AccessQualifier::Unknown;
64
65 return StringSwitch<AccessQualifier>(AccQual)
66 .Case("read_only", AccessQualifier::ReadOnly)
67 .Case("write_only", AccessQualifier::WriteOnly)
68 .Case("read_write", AccessQualifier::ReadWrite)
69 .Default(AccessQualifier::Default);
70}
71
72AddressSpaceQualifier MetadataStreamer::getAddressSpaceQualifer(
73 unsigned AddressSpace) const {
Yaxun Liu1a14bfa2017-03-27 14:04:01 +000074 if (AddressSpace == AMDGPUASI.PRIVATE_ADDRESS)
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +000075 return AddressSpaceQualifier::Private;
Yaxun Liu1a14bfa2017-03-27 14:04:01 +000076 if (AddressSpace == AMDGPUASI.GLOBAL_ADDRESS)
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +000077 return AddressSpaceQualifier::Global;
Yaxun Liu1a14bfa2017-03-27 14:04:01 +000078 if (AddressSpace == AMDGPUASI.CONSTANT_ADDRESS)
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +000079 return AddressSpaceQualifier::Constant;
Yaxun Liu1a14bfa2017-03-27 14:04:01 +000080 if (AddressSpace == AMDGPUASI.LOCAL_ADDRESS)
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +000081 return AddressSpaceQualifier::Local;
Yaxun Liu1a14bfa2017-03-27 14:04:01 +000082 if (AddressSpace == AMDGPUASI.FLAT_ADDRESS)
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +000083 return AddressSpaceQualifier::Generic;
Yaxun Liu1a14bfa2017-03-27 14:04:01 +000084 if (AddressSpace == AMDGPUASI.REGION_ADDRESS)
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +000085 return AddressSpaceQualifier::Region;
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +000086
87 llvm_unreachable("Unknown address space qualifier");
88}
89
90ValueKind MetadataStreamer::getValueKind(Type *Ty, StringRef TypeQual,
91 StringRef BaseTypeName) const {
92 if (TypeQual.find("pipe") != StringRef::npos)
93 return ValueKind::Pipe;
94
95 return StringSwitch<ValueKind>(BaseTypeName)
Konstantin Zhuravlyov54ba4312017-04-25 20:38:26 +000096 .Case("image1d_t", ValueKind::Image)
97 .Case("image1d_array_t", ValueKind::Image)
98 .Case("image1d_buffer_t", ValueKind::Image)
99 .Case("image2d_t", ValueKind::Image)
100 .Case("image2d_array_t", ValueKind::Image)
101 .Case("image2d_array_depth_t", ValueKind::Image)
102 .Case("image2d_array_msaa_t", ValueKind::Image)
103 .Case("image2d_array_msaa_depth_t", ValueKind::Image)
104 .Case("image2d_depth_t", ValueKind::Image)
105 .Case("image2d_msaa_t", ValueKind::Image)
106 .Case("image2d_msaa_depth_t", ValueKind::Image)
107 .Case("image3d_t", ValueKind::Image)
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +0000108 .Case("sampler_t", ValueKind::Sampler)
109 .Case("queue_t", ValueKind::Queue)
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +0000110 .Default(isa<PointerType>(Ty) ?
111 (Ty->getPointerAddressSpace() ==
Yaxun Liu1a14bfa2017-03-27 14:04:01 +0000112 AMDGPUASI.LOCAL_ADDRESS ?
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +0000113 ValueKind::DynamicSharedPointer :
114 ValueKind::GlobalBuffer) :
115 ValueKind::ByValue);
116}
117
118ValueType MetadataStreamer::getValueType(Type *Ty, StringRef TypeName) const {
119 switch (Ty->getTypeID()) {
120 case Type::IntegerTyID: {
121 auto Signed = !TypeName.startswith("u");
122 switch (Ty->getIntegerBitWidth()) {
123 case 8:
124 return Signed ? ValueType::I8 : ValueType::U8;
125 case 16:
126 return Signed ? ValueType::I16 : ValueType::U16;
127 case 32:
128 return Signed ? ValueType::I32 : ValueType::U32;
129 case 64:
130 return Signed ? ValueType::I64 : ValueType::U64;
131 default:
132 return ValueType::Struct;
133 }
134 }
135 case Type::HalfTyID:
136 return ValueType::F16;
137 case Type::FloatTyID:
138 return ValueType::F32;
139 case Type::DoubleTyID:
140 return ValueType::F64;
141 case Type::PointerTyID:
142 return getValueType(Ty->getPointerElementType(), TypeName);
143 case Type::VectorTyID:
144 return getValueType(Ty->getVectorElementType(), TypeName);
145 default:
146 return ValueType::Struct;
147 }
148}
149
150std::string MetadataStreamer::getTypeName(Type *Ty, bool Signed) const {
151 switch (Ty->getTypeID()) {
152 case Type::IntegerTyID: {
153 if (!Signed)
154 return (Twine('u') + getTypeName(Ty, true)).str();
155
156 auto BitWidth = Ty->getIntegerBitWidth();
157 switch (BitWidth) {
158 case 8:
159 return "char";
160 case 16:
161 return "short";
162 case 32:
163 return "int";
164 case 64:
165 return "long";
166 default:
167 return (Twine('i') + Twine(BitWidth)).str();
168 }
169 }
170 case Type::HalfTyID:
171 return "half";
172 case Type::FloatTyID:
173 return "float";
174 case Type::DoubleTyID:
175 return "double";
176 case Type::VectorTyID: {
177 auto VecTy = cast<VectorType>(Ty);
178 auto ElTy = VecTy->getElementType();
179 auto NumElements = VecTy->getVectorNumElements();
180 return (Twine(getTypeName(ElTy, Signed)) + Twine(NumElements)).str();
181 }
182 default:
183 return "unknown";
184 }
185}
186
187std::vector<uint32_t> MetadataStreamer::getWorkGroupDimensions(
188 MDNode *Node) const {
189 std::vector<uint32_t> Dims;
190 if (Node->getNumOperands() != 3)
191 return Dims;
192
193 for (auto &Op : Node->operands())
194 Dims.push_back(mdconst::extract<ConstantInt>(Op)->getZExtValue());
195 return Dims;
196}
197
198void MetadataStreamer::emitVersion() {
199 auto &Version = CodeObjectMetadata.mVersion;
200
201 Version.push_back(MetadataVersionMajor);
202 Version.push_back(MetadataVersionMinor);
203}
204
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +0000205void MetadataStreamer::emitPrintf(const Module &Mod) {
206 auto &Printf = CodeObjectMetadata.mPrintf;
207
208 auto Node = Mod.getNamedMetadata("llvm.printf.fmts");
209 if (!Node)
210 return;
211
212 for (auto Op : Node->operands())
213 if (Op->getNumOperands())
214 Printf.push_back(cast<MDString>(Op->getOperand(0))->getString());
215}
216
217void MetadataStreamer::emitKernelLanguage(const Function &Func) {
218 auto &Kernel = CodeObjectMetadata.mKernels.back();
219
220 // TODO: What about other languages?
221 auto Node = Func.getParent()->getNamedMetadata("opencl.ocl.version");
222 if (!Node || !Node->getNumOperands())
223 return;
224 auto Op0 = Node->getOperand(0);
225 if (Op0->getNumOperands() <= 1)
226 return;
227
228 Kernel.mLanguage = "OpenCL C";
229 Kernel.mLanguageVersion.push_back(
230 mdconst::extract<ConstantInt>(Op0->getOperand(0))->getZExtValue());
231 Kernel.mLanguageVersion.push_back(
232 mdconst::extract<ConstantInt>(Op0->getOperand(1))->getZExtValue());
233}
234
235void MetadataStreamer::emitKernelAttrs(const Function &Func) {
236 auto &Attrs = CodeObjectMetadata.mKernels.back().mAttrs;
237
238 if (auto Node = Func.getMetadata("reqd_work_group_size"))
239 Attrs.mReqdWorkGroupSize = getWorkGroupDimensions(Node);
240 if (auto Node = Func.getMetadata("work_group_size_hint"))
241 Attrs.mWorkGroupSizeHint = getWorkGroupDimensions(Node);
242 if (auto Node = Func.getMetadata("vec_type_hint")) {
243 Attrs.mVecTypeHint = getTypeName(
244 cast<ValueAsMetadata>(Node->getOperand(0))->getType(),
245 mdconst::extract<ConstantInt>(Node->getOperand(1))->getZExtValue());
246 }
Yaxun Liude4b88d2017-10-10 19:39:48 +0000247 if (Func.hasFnAttribute("runtime-handle")) {
248 Attrs.mRuntimeHandle =
249 Func.getFnAttribute("runtime-handle").getValueAsString().str();
250 }
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +0000251}
252
253void MetadataStreamer::emitKernelArgs(const Function &Func) {
254 for (auto &Arg : Func.args())
255 emitKernelArg(Arg);
256
257 // TODO: What about other languages?
258 if (!Func.getParent()->getNamedMetadata("opencl.ocl.version"))
259 return;
260
261 auto &DL = Func.getParent()->getDataLayout();
262 auto Int64Ty = Type::getInt64Ty(Func.getContext());
263
264 emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetX);
265 emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetY);
266 emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetZ);
267
268 if (!Func.getParent()->getNamedMetadata("llvm.printf.fmts"))
269 return;
270
271 auto Int8PtrTy = Type::getInt8PtrTy(Func.getContext(),
Yaxun Liu1a14bfa2017-03-27 14:04:01 +0000272 AMDGPUASI.GLOBAL_ADDRESS);
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +0000273 emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenPrintfBuffer);
274}
275
276void MetadataStreamer::emitKernelArg(const Argument &Arg) {
277 auto Func = Arg.getParent();
278 auto ArgNo = Arg.getArgNo();
279 const MDNode *Node;
280
281 StringRef TypeQual;
282 Node = Func->getMetadata("kernel_arg_type_qual");
283 if (Node && ArgNo < Node->getNumOperands())
284 TypeQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
285
286 StringRef BaseTypeName;
287 Node = Func->getMetadata("kernel_arg_base_type");
288 if (Node && ArgNo < Node->getNumOperands())
289 BaseTypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
290
291 StringRef AccQual;
Stanislav Mekhanoshineff0bc72017-04-14 19:11:40 +0000292 if (Arg.getType()->isPointerTy() && Arg.onlyReadsMemory() &&
293 Arg.hasNoAliasAttr()) {
294 AccQual = "read_only";
295 } else {
296 Node = Func->getMetadata("kernel_arg_access_qual");
297 if (Node && ArgNo < Node->getNumOperands())
298 AccQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
299 }
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +0000300
301 StringRef Name;
302 Node = Func->getMetadata("kernel_arg_name");
303 if (Node && ArgNo < Node->getNumOperands())
304 Name = cast<MDString>(Node->getOperand(ArgNo))->getString();
305
306 StringRef TypeName;
307 Node = Func->getMetadata("kernel_arg_type");
308 if (Node && ArgNo < Node->getNumOperands())
309 TypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
310
311 emitKernelArg(Func->getParent()->getDataLayout(), Arg.getType(),
312 getValueKind(Arg.getType(), TypeQual, BaseTypeName), TypeQual,
313 BaseTypeName, AccQual, Name, TypeName);
314}
315
316void MetadataStreamer::emitKernelArg(const DataLayout &DL, Type *Ty,
317 ValueKind ValueKind, StringRef TypeQual,
318 StringRef BaseTypeName, StringRef AccQual,
319 StringRef Name, StringRef TypeName) {
320 CodeObjectMetadata.mKernels.back().mArgs.push_back(Kernel::Arg::Metadata());
321 auto &Arg = CodeObjectMetadata.mKernels.back().mArgs.back();
322
323 Arg.mSize = DL.getTypeAllocSize(Ty);
324 Arg.mAlign = DL.getABITypeAlignment(Ty);
325 Arg.mValueKind = ValueKind;
326 Arg.mValueType = getValueType(Ty, BaseTypeName);
327
328 if (auto PtrTy = dyn_cast<PointerType>(Ty)) {
329 auto ElTy = PtrTy->getElementType();
Yaxun Liu1a14bfa2017-03-27 14:04:01 +0000330 if (PtrTy->getAddressSpace() == AMDGPUASI.LOCAL_ADDRESS && ElTy->isSized())
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +0000331 Arg.mPointeeAlign = DL.getABITypeAlignment(ElTy);
332 }
333
334 Arg.mAccQual = getAccessQualifier(AccQual);
335
336 if (auto PtrTy = dyn_cast<PointerType>(Ty))
337 Arg.mAddrSpaceQual = getAddressSpaceQualifer(PtrTy->getAddressSpace());
338
339 SmallVector<StringRef, 1> SplitTypeQuals;
340 TypeQual.split(SplitTypeQuals, " ", -1, false);
341 for (StringRef Key : SplitTypeQuals) {
342 auto P = StringSwitch<bool*>(Key)
343 .Case("const", &Arg.mIsConst)
344 .Case("pipe", &Arg.mIsPipe)
345 .Case("restrict", &Arg.mIsRestrict)
346 .Case("volatile", &Arg.mIsVolatile)
347 .Default(nullptr);
348 if (P)
349 *P = true;
350 }
351
352 Arg.mName = Name;
353 Arg.mTypeName = TypeName;
354}
355
Konstantin Zhuravlyovca0e7f62017-03-22 22:54:39 +0000356void MetadataStreamer::emitKernelCodeProps(
357 const amd_kernel_code_t &KernelCode) {
358 auto &CodeProps = CodeObjectMetadata.mKernels.back().mCodeProps;
359
360 CodeProps.mKernargSegmentSize = KernelCode.kernarg_segment_byte_size;
361 CodeProps.mWorkgroupGroupSegmentSize =
362 KernelCode.workgroup_group_segment_byte_size;
363 CodeProps.mWorkitemPrivateSegmentSize =
364 KernelCode.workitem_private_segment_byte_size;
365 CodeProps.mWavefrontNumSGPRs = KernelCode.wavefront_sgpr_count;
366 CodeProps.mWorkitemNumVGPRs = KernelCode.workitem_vgpr_count;
367 CodeProps.mKernargSegmentAlign = KernelCode.kernarg_segment_alignment;
368 CodeProps.mGroupSegmentAlign = KernelCode.group_segment_alignment;
369 CodeProps.mPrivateSegmentAlign = KernelCode.private_segment_alignment;
370 CodeProps.mWavefrontSize = KernelCode.wavefront_size;
371}
372
Konstantin Zhuravlyova780ffa2017-03-22 23:10:46 +0000373void MetadataStreamer::emitKernelDebugProps(
374 const amd_kernel_code_t &KernelCode) {
375 if (!(KernelCode.code_properties & AMD_CODE_PROPERTY_IS_DEBUG_SUPPORTED))
376 return;
377
378 auto &DebugProps = CodeObjectMetadata.mKernels.back().mDebugProps;
379
380 // FIXME: Need to pass down debugger ABI version through features. This is ok
381 // for now because we only have one version.
382 DebugProps.mDebuggerABIVersion.push_back(1);
383 DebugProps.mDebuggerABIVersion.push_back(0);
384 DebugProps.mReservedNumVGPRs = KernelCode.reserved_vgpr_count;
385 DebugProps.mReservedFirstVGPR = KernelCode.reserved_vgpr_first;
386 DebugProps.mPrivateSegmentBufferSGPR =
387 KernelCode.debug_private_segment_buffer_sgpr;
388 DebugProps.mWavefrontPrivateSegmentOffsetSGPR =
389 KernelCode.debug_wavefront_private_segment_offset_sgpr;
390}
391
Konstantin Zhuravlyov4cbb6892017-03-22 23:27:09 +0000392void MetadataStreamer::begin(const Module &Mod) {
Yaxun Liu1a14bfa2017-03-27 14:04:01 +0000393 AMDGPUASI = getAMDGPUAS(Mod);
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +0000394 emitVersion();
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +0000395 emitPrintf(Mod);
396}
397
Konstantin Zhuravlyovca0e7f62017-03-22 22:54:39 +0000398void MetadataStreamer::emitKernel(const Function &Func,
399 const amd_kernel_code_t &KernelCode) {
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +0000400 if (Func.getCallingConv() != CallingConv::AMDGPU_KERNEL)
401 return;
402
403 CodeObjectMetadata.mKernels.push_back(Kernel::Metadata());
404 auto &Kernel = CodeObjectMetadata.mKernels.back();
405
406 Kernel.mName = Func.getName();
407 emitKernelLanguage(Func);
408 emitKernelAttrs(Func);
409 emitKernelArgs(Func);
Konstantin Zhuravlyovca0e7f62017-03-22 22:54:39 +0000410 emitKernelCodeProps(KernelCode);
Konstantin Zhuravlyova780ffa2017-03-22 23:10:46 +0000411 emitKernelDebugProps(KernelCode);
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +0000412}
413
414ErrorOr<std::string> MetadataStreamer::toYamlString() {
415 std::string YamlString;
416 if (auto Error = Metadata::toYamlString(CodeObjectMetadata, YamlString))
417 return Error;
418
419 if (DumpCodeObjectMetadata)
420 dump(YamlString);
421 if (VerifyCodeObjectMetadata)
422 verify(YamlString);
423
424 return YamlString;
425}
426
Konstantin Zhuravlyov4cbb6892017-03-22 23:27:09 +0000427ErrorOr<std::string> MetadataStreamer::toYamlString(StringRef YamlString) {
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +0000428 if (auto Error = Metadata::fromYamlString(YamlString, CodeObjectMetadata))
429 return Error;
430
Konstantin Zhuravlyov7498cd62017-03-22 22:32:22 +0000431 return toYamlString();
432}
433
434} // end namespace CodeObject
435} // end namespace AMDGPU
436} // end namespace llvm