Line data Source code
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 "AMDGPUSubtarget.h"
19 : #include "SIMachineFunctionInfo.h"
20 : #include "SIProgramInfo.h"
21 : #include "Utils/AMDGPUBaseInfo.h"
22 : #include "llvm/ADT/StringSwitch.h"
23 : #include "llvm/IR/Constants.h"
24 : #include "llvm/IR/Module.h"
25 : #include "llvm/Support/raw_ostream.h"
26 :
27 : namespace llvm {
28 :
29 : static cl::opt<bool> DumpHSAMetadata(
30 : "amdgpu-dump-hsa-metadata",
31 : cl::desc("Dump AMDGPU HSA Metadata"));
32 : static cl::opt<bool> VerifyHSAMetadata(
33 : "amdgpu-verify-hsa-metadata",
34 : cl::desc("Verify AMDGPU HSA Metadata"));
35 :
36 : namespace AMDGPU {
37 : namespace HSAMD {
38 :
39 4 : void MetadataStreamer::dump(StringRef HSAMetadataString) const {
40 4 : errs() << "AMDGPU HSA Metadata:\n" << HSAMetadataString << '\n';
41 4 : }
42 :
43 4 : void MetadataStreamer::verify(StringRef HSAMetadataString) const {
44 4 : errs() << "AMDGPU HSA Metadata Parser Test: ";
45 :
46 4 : HSAMD::Metadata FromHSAMetadataString;
47 8 : if (fromString(HSAMetadataString, FromHSAMetadataString)) {
48 0 : errs() << "FAIL\n";
49 0 : return;
50 : }
51 :
52 : std::string ToHSAMetadataString;
53 4 : if (toString(FromHSAMetadataString, ToHSAMetadataString)) {
54 0 : errs() << "FAIL\n";
55 : return;
56 : }
57 :
58 8 : errs() << (HSAMetadataString == ToHSAMetadataString ? "PASS" : "FAIL")
59 : << '\n';
60 : if (HSAMetadataString != ToHSAMetadataString) {
61 0 : errs() << "Original input: " << HSAMetadataString << '\n'
62 0 : << "Produced output: " << ToHSAMetadataString << '\n';
63 : }
64 : }
65 :
66 6022 : AccessQualifier MetadataStreamer::getAccessQualifier(StringRef AccQual) const {
67 6022 : if (AccQual.empty())
68 : return AccessQualifier::Unknown;
69 :
70 337 : return StringSwitch<AccessQualifier>(AccQual)
71 674 : .Case("read_only", AccessQualifier::ReadOnly)
72 337 : .Case("write_only", AccessQualifier::WriteOnly)
73 337 : .Case("read_write", AccessQualifier::ReadWrite)
74 : .Default(AccessQualifier::Default);
75 : }
76 :
77 3629 : AddressSpaceQualifier MetadataStreamer::getAddressSpaceQualifer(
78 : unsigned AddressSpace) const {
79 : switch (AddressSpace) {
80 : case AMDGPUAS::PRIVATE_ADDRESS:
81 : return AddressSpaceQualifier::Private;
82 : case AMDGPUAS::GLOBAL_ADDRESS:
83 : return AddressSpaceQualifier::Global;
84 : case AMDGPUAS::CONSTANT_ADDRESS:
85 : return AddressSpaceQualifier::Constant;
86 : case AMDGPUAS::LOCAL_ADDRESS:
87 : return AddressSpaceQualifier::Local;
88 : case AMDGPUAS::FLAT_ADDRESS:
89 : return AddressSpaceQualifier::Generic;
90 : case AMDGPUAS::REGION_ADDRESS:
91 : return AddressSpaceQualifier::Region;
92 : default:
93 : return AddressSpaceQualifier::Unknown;
94 : }
95 : }
96 :
97 4644 : ValueKind MetadataStreamer::getValueKind(Type *Ty, StringRef TypeQual,
98 : StringRef BaseTypeName) const {
99 4644 : if (TypeQual.find("pipe") != StringRef::npos)
100 : return ValueKind::Pipe;
101 :
102 4638 : return StringSwitch<ValueKind>(BaseTypeName)
103 : .Case("image1d_t", ValueKind::Image)
104 : .Case("image1d_array_t", ValueKind::Image)
105 : .Case("image1d_buffer_t", ValueKind::Image)
106 : .Case("image2d_t", ValueKind::Image)
107 : .Case("image2d_array_t", ValueKind::Image)
108 : .Case("image2d_array_depth_t", ValueKind::Image)
109 : .Case("image2d_array_msaa_t", ValueKind::Image)
110 : .Case("image2d_array_msaa_depth_t", ValueKind::Image)
111 : .Case("image2d_depth_t", ValueKind::Image)
112 : .Case("image2d_msaa_t", ValueKind::Image)
113 : .Case("image2d_msaa_depth_t", ValueKind::Image)
114 : .Case("image3d_t", ValueKind::Image)
115 : .Case("sampler_t", ValueKind::Sampler)
116 : .Case("queue_t", ValueKind::Queue)
117 4638 : .Default(isa<PointerType>(Ty) ?
118 : (Ty->getPointerAddressSpace() ==
119 2947 : AMDGPUAS::LOCAL_ADDRESS ?
120 : ValueKind::DynamicSharedPointer :
121 : ValueKind::GlobalBuffer) :
122 : ValueKind::ByValue);
123 : }
124 :
125 6022 : ValueType MetadataStreamer::getValueType(Type *Ty, StringRef TypeName) const {
126 11361 : switch (Ty->getTypeID()) {
127 : case Type::IntegerTyID: {
128 4684 : auto Signed = !TypeName.startswith("u");
129 4684 : switch (Ty->getIntegerBitWidth()) {
130 1077 : case 8:
131 1077 : return Signed ? ValueType::I8 : ValueType::U8;
132 428 : case 16:
133 428 : return Signed ? ValueType::I16 : ValueType::U16;
134 2151 : case 32:
135 2151 : return Signed ? ValueType::I32 : ValueType::U32;
136 956 : case 64:
137 956 : return Signed ? ValueType::I64 : ValueType::U64;
138 : default:
139 : return ValueType::Struct;
140 : }
141 : }
142 : case Type::HalfTyID:
143 : return ValueType::F16;
144 222 : case Type::FloatTyID:
145 222 : return ValueType::F32;
146 100 : case Type::DoubleTyID:
147 100 : return ValueType::F64;
148 3644 : case Type::PointerTyID:
149 7288 : return getValueType(Ty->getPointerElementType(), TypeName);
150 1695 : case Type::VectorTyID:
151 3390 : return getValueType(Ty->getVectorElementType(), TypeName);
152 297 : default:
153 297 : return ValueType::Struct;
154 : }
155 : }
156 :
157 66 : std::string MetadataStreamer::getTypeName(Type *Ty, bool Signed) const {
158 66 : switch (Ty->getTypeID()) {
159 36 : case Type::IntegerTyID: {
160 36 : if (!Signed)
161 12 : return (Twine('u') + getTypeName(Ty, true)).str();
162 :
163 : auto BitWidth = Ty->getIntegerBitWidth();
164 30 : switch (BitWidth) {
165 : case 8:
166 6 : return "char";
167 : case 16:
168 6 : return "short";
169 : case 32:
170 12 : return "int";
171 : case 64:
172 6 : return "long";
173 : default:
174 0 : return (Twine('i') + Twine(BitWidth)).str();
175 : }
176 : }
177 : case Type::HalfTyID:
178 6 : return "half";
179 : case Type::FloatTyID:
180 6 : return "float";
181 : case Type::DoubleTyID:
182 6 : return "double";
183 : case Type::VectorTyID: {
184 : auto VecTy = cast<VectorType>(Ty);
185 6 : auto ElTy = VecTy->getElementType();
186 : auto NumElements = VecTy->getVectorNumElements();
187 12 : return (Twine(getTypeName(ElTy, Signed)) + Twine(NumElements)).str();
188 : }
189 : default:
190 6 : return "unknown";
191 : }
192 : }
193 :
194 12 : std::vector<uint32_t> MetadataStreamer::getWorkGroupDimensions(
195 : MDNode *Node) const {
196 : std::vector<uint32_t> Dims;
197 12 : if (Node->getNumOperands() != 3)
198 : return Dims;
199 :
200 48 : for (auto &Op : Node->operands())
201 36 : Dims.push_back(mdconst::extract<ConstantInt>(Op)->getZExtValue());
202 : return Dims;
203 : }
204 :
205 2434 : Kernel::CodeProps::Metadata MetadataStreamer::getHSACodeProps(
206 : const MachineFunction &MF,
207 : const SIProgramInfo &ProgramInfo) const {
208 2434 : const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
209 : const SIMachineFunctionInfo &MFI = *MF.getInfo<SIMachineFunctionInfo>();
210 2434 : HSAMD::Kernel::CodeProps::Metadata HSACodeProps;
211 2434 : const Function &F = MF.getFunction();
212 :
213 : assert(F.getCallingConv() == CallingConv::AMDGPU_KERNEL ||
214 : F.getCallingConv() == CallingConv::SPIR_KERNEL);
215 :
216 : unsigned MaxKernArgAlign;
217 2434 : HSACodeProps.mKernargSegmentSize = STM.getKernArgSegmentSize(F,
218 : MaxKernArgAlign);
219 2434 : HSACodeProps.mGroupSegmentFixedSize = ProgramInfo.LDSSize;
220 2434 : HSACodeProps.mPrivateSegmentFixedSize = ProgramInfo.ScratchSize;
221 2434 : HSACodeProps.mKernargSegmentAlign = std::max(MaxKernArgAlign, 4u);
222 2434 : HSACodeProps.mWavefrontSize = STM.getWavefrontSize();
223 2434 : HSACodeProps.mNumSGPRs = ProgramInfo.NumSGPR;
224 2434 : HSACodeProps.mNumVGPRs = ProgramInfo.NumVGPR;
225 2434 : HSACodeProps.mMaxFlatWorkGroupSize = MFI.getMaxFlatWorkGroupSize();
226 2434 : HSACodeProps.mIsDynamicCallStack = ProgramInfo.DynamicCallStack;
227 2434 : HSACodeProps.mIsXNACKEnabled = STM.isXNACKEnabled();
228 2434 : HSACodeProps.mNumSpilledSGPRs = MFI.getNumSpilledSGPRs();
229 2434 : HSACodeProps.mNumSpilledVGPRs = MFI.getNumSpilledVGPRs();
230 :
231 2434 : return HSACodeProps;
232 : }
233 :
234 2434 : Kernel::DebugProps::Metadata MetadataStreamer::getHSADebugProps(
235 : const MachineFunction &MF,
236 : const SIProgramInfo &ProgramInfo) const {
237 2434 : const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
238 : HSAMD::Kernel::DebugProps::Metadata HSADebugProps;
239 :
240 : if (!STM.debuggerSupported())
241 : return HSADebugProps;
242 :
243 3 : HSADebugProps.mDebuggerABIVersion.push_back(1);
244 3 : HSADebugProps.mDebuggerABIVersion.push_back(0);
245 :
246 3 : if (STM.debuggerEmitPrologue()) {
247 3 : HSADebugProps.mPrivateSegmentBufferSGPR =
248 3 : ProgramInfo.DebuggerPrivateSegmentBufferSGPR;
249 3 : HSADebugProps.mWavefrontPrivateSegmentOffsetSGPR =
250 3 : ProgramInfo.DebuggerWavefrontPrivateSegmentOffsetSGPR;
251 : }
252 :
253 : return HSADebugProps;
254 : }
255 :
256 324 : void MetadataStreamer::emitVersion() {
257 324 : auto &Version = HSAMetadata.mVersion;
258 :
259 324 : Version.push_back(VersionMajor);
260 324 : Version.push_back(VersionMinor);
261 324 : }
262 :
263 324 : void MetadataStreamer::emitPrintf(const Module &Mod) {
264 324 : auto &Printf = HSAMetadata.mPrintf;
265 :
266 324 : auto Node = Mod.getNamedMetadata("llvm.printf.fmts");
267 324 : if (!Node)
268 : return;
269 :
270 18 : for (auto Op : Node->operands())
271 12 : if (Op->getNumOperands())
272 24 : Printf.push_back(cast<MDString>(Op->getOperand(0))->getString());
273 : }
274 :
275 2434 : void MetadataStreamer::emitKernelLanguage(const Function &Func) {
276 : auto &Kernel = HSAMetadata.mKernels.back();
277 :
278 : // TODO: What about other languages?
279 4868 : auto Node = Func.getParent()->getNamedMetadata("opencl.ocl.version");
280 2434 : if (!Node || !Node->getNumOperands())
281 2209 : return;
282 225 : auto Op0 = Node->getOperand(0);
283 225 : if (Op0->getNumOperands() <= 1)
284 : return;
285 :
286 225 : Kernel.mLanguage = "OpenCL C";
287 450 : Kernel.mLanguageVersion.push_back(
288 : mdconst::extract<ConstantInt>(Op0->getOperand(0))->getZExtValue());
289 225 : Kernel.mLanguageVersion.push_back(
290 : mdconst::extract<ConstantInt>(Op0->getOperand(1))->getZExtValue());
291 : }
292 :
293 2434 : void MetadataStreamer::emitKernelAttrs(const Function &Func) {
294 : auto &Attrs = HSAMetadata.mKernels.back().mAttrs;
295 :
296 4868 : if (auto Node = Func.getMetadata("reqd_work_group_size"))
297 12 : Attrs.mReqdWorkGroupSize = getWorkGroupDimensions(Node);
298 2434 : if (auto Node = Func.getMetadata("work_group_size_hint"))
299 12 : Attrs.mWorkGroupSizeHint = getWorkGroupDimensions(Node);
300 2434 : if (auto Node = Func.getMetadata("vec_type_hint")) {
301 216 : Attrs.mVecTypeHint = getTypeName(
302 : cast<ValueAsMetadata>(Node->getOperand(0))->getType(),
303 54 : mdconst::extract<ConstantInt>(Node->getOperand(1))->getZExtValue());
304 : }
305 2434 : if (Func.hasFnAttribute("runtime-handle")) {
306 : Attrs.mRuntimeHandle =
307 18 : Func.getFnAttribute("runtime-handle").getValueAsString().str();
308 : }
309 2434 : }
310 :
311 2434 : void MetadataStreamer::emitKernelArgs(const Function &Func) {
312 7078 : for (auto &Arg : Func.args())
313 4644 : emitKernelArg(Arg);
314 :
315 2434 : emitHiddenKernelArgs(Func);
316 2434 : }
317 :
318 4644 : void MetadataStreamer::emitKernelArg(const Argument &Arg) {
319 4644 : auto Func = Arg.getParent();
320 4644 : auto ArgNo = Arg.getArgNo();
321 : const MDNode *Node;
322 :
323 4644 : StringRef Name;
324 9288 : Node = Func->getMetadata("kernel_arg_name");
325 4644 : if (Node && ArgNo < Node->getNumOperands())
326 0 : Name = cast<MDString>(Node->getOperand(ArgNo))->getString();
327 4644 : else if (Arg.hasName())
328 4447 : Name = Arg.getName();
329 :
330 4644 : StringRef TypeName;
331 4644 : Node = Func->getMetadata("kernel_arg_type");
332 4644 : if (Node && ArgNo < Node->getNumOperands())
333 370 : TypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
334 :
335 4644 : StringRef BaseTypeName;
336 4644 : Node = Func->getMetadata("kernel_arg_base_type");
337 4644 : if (Node && ArgNo < Node->getNumOperands())
338 370 : BaseTypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
339 :
340 4644 : StringRef AccQual;
341 9332 : if (Arg.getType()->isPointerTy() && Arg.onlyReadsMemory() &&
342 44 : Arg.hasNoAliasAttr()) {
343 4 : AccQual = "read_only";
344 : } else {
345 4640 : Node = Func->getMetadata("kernel_arg_access_qual");
346 4640 : if (Node && ArgNo < Node->getNumOperands())
347 333 : AccQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
348 : }
349 :
350 4644 : StringRef TypeQual;
351 4644 : Node = Func->getMetadata("kernel_arg_type_qual");
352 4644 : if (Node && ArgNo < Node->getNumOperands())
353 334 : TypeQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
354 :
355 4644 : Type *Ty = Arg.getType();
356 4644 : const DataLayout &DL = Func->getParent()->getDataLayout();
357 :
358 : unsigned PointeeAlign = 0;
359 : if (auto PtrTy = dyn_cast<PointerType>(Ty)) {
360 2953 : if (PtrTy->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS) {
361 175 : PointeeAlign = Arg.getParamAlignment();
362 175 : if (PointeeAlign == 0)
363 132 : PointeeAlign = DL.getABITypeAlignment(PtrTy->getElementType());
364 : }
365 : }
366 :
367 4644 : emitKernelArg(DL, Ty, getValueKind(Arg.getType(), TypeQual, BaseTypeName),
368 : PointeeAlign, Name, TypeName, BaseTypeName, AccQual, TypeQual);
369 4644 : }
370 :
371 6022 : void MetadataStreamer::emitKernelArg(const DataLayout &DL, Type *Ty,
372 : ValueKind ValueKind,
373 : unsigned PointeeAlign,
374 : StringRef Name,
375 : StringRef TypeName, StringRef BaseTypeName,
376 : StringRef AccQual, StringRef TypeQual) {
377 6022 : HSAMetadata.mKernels.back().mArgs.push_back(Kernel::Arg::Metadata());
378 : auto &Arg = HSAMetadata.mKernels.back().mArgs.back();
379 :
380 12044 : Arg.mName = Name;
381 6022 : Arg.mTypeName = TypeName;
382 6022 : Arg.mSize = DL.getTypeAllocSize(Ty);
383 6022 : Arg.mAlign = DL.getABITypeAlignment(Ty);
384 6022 : Arg.mValueKind = ValueKind;
385 6022 : Arg.mValueType = getValueType(Ty, BaseTypeName);
386 6022 : Arg.mPointeeAlign = PointeeAlign;
387 :
388 : if (auto PtrTy = dyn_cast<PointerType>(Ty))
389 3629 : Arg.mAddrSpaceQual = getAddressSpaceQualifer(PtrTy->getAddressSpace());
390 :
391 6022 : Arg.mAccQual = getAccessQualifier(AccQual);
392 :
393 : // TODO: Emit Arg.mActualAccQual.
394 :
395 : SmallVector<StringRef, 1> SplitTypeQuals;
396 6022 : TypeQual.split(SplitTypeQuals, " ", -1, false);
397 6048 : for (StringRef Key : SplitTypeQuals) {
398 0 : auto P = StringSwitch<bool*>(Key)
399 26 : .Case("const", &Arg.mIsConst)
400 26 : .Case("restrict", &Arg.mIsRestrict)
401 26 : .Case("volatile", &Arg.mIsVolatile)
402 26 : .Case("pipe", &Arg.mIsPipe)
403 : .Default(nullptr);
404 26 : if (P)
405 26 : *P = true;
406 : }
407 6022 : }
408 :
409 2434 : void MetadataStreamer::emitHiddenKernelArgs(const Function &Func) {
410 : int HiddenArgNumBytes =
411 2434 : getIntegerAttribute(Func, "amdgpu-implicitarg-num-bytes", 0);
412 :
413 2434 : if (!HiddenArgNumBytes)
414 : return;
415 :
416 237 : auto &DL = Func.getParent()->getDataLayout();
417 237 : auto Int64Ty = Type::getInt64Ty(Func.getContext());
418 :
419 237 : if (HiddenArgNumBytes >= 8)
420 237 : emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetX);
421 237 : if (HiddenArgNumBytes >= 16)
422 234 : emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetY);
423 237 : if (HiddenArgNumBytes >= 24)
424 231 : emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetZ);
425 :
426 237 : auto Int8PtrTy = Type::getInt8PtrTy(Func.getContext(),
427 : AMDGPUAS::GLOBAL_ADDRESS);
428 :
429 : // Emit "printf buffer" argument if printf is used, otherwise emit dummy
430 : // "none" argument.
431 237 : if (HiddenArgNumBytes >= 32) {
432 456 : if (Func.getParent()->getNamedMetadata("llvm.printf.fmts"))
433 210 : emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenPrintfBuffer);
434 : else
435 18 : emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone);
436 : }
437 :
438 : // Emit "default queue" and "completion action" arguments if enqueue kernel is
439 : // used, otherwise emit dummy "none" arguments.
440 237 : if (HiddenArgNumBytes >= 48) {
441 224 : if (Func.hasFnAttribute("calls-enqueue-kernel")) {
442 8 : emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenDefaultQueue);
443 8 : emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenCompletionAction);
444 : } else {
445 216 : emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone);
446 216 : emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone);
447 : }
448 : }
449 : }
450 :
451 324 : void MetadataStreamer::begin(const Module &Mod) {
452 324 : emitVersion();
453 324 : emitPrintf(Mod);
454 324 : }
455 :
456 323 : void MetadataStreamer::end() {
457 : std::string HSAMetadataString;
458 323 : if (toString(HSAMetadata, HSAMetadataString))
459 : return;
460 :
461 323 : if (DumpHSAMetadata)
462 4 : dump(HSAMetadataString);
463 323 : if (VerifyHSAMetadata)
464 4 : verify(HSAMetadataString);
465 : }
466 :
467 2437 : void MetadataStreamer::emitKernel(const MachineFunction &MF, const SIProgramInfo &ProgramInfo) {
468 2437 : auto &Func = MF.getFunction();
469 2437 : if (Func.getCallingConv() != CallingConv::AMDGPU_KERNEL)
470 3 : return;
471 :
472 2434 : auto CodeProps = getHSACodeProps(MF, ProgramInfo);
473 2434 : auto DebugProps = getHSADebugProps(MF, ProgramInfo);
474 :
475 4868 : HSAMetadata.mKernels.push_back(Kernel::Metadata());
476 : auto &Kernel = HSAMetadata.mKernels.back();
477 :
478 7302 : Kernel.mName = Func.getName();
479 4868 : Kernel.mSymbolName = (Twine(Func.getName()) + Twine("@kd")).str();
480 2434 : emitKernelLanguage(Func);
481 2434 : emitKernelAttrs(Func);
482 2434 : emitKernelArgs(Func);
483 2434 : HSAMetadata.mKernels.back().mCodeProps = CodeProps;
484 : HSAMetadata.mKernels.back().mDebugProps = DebugProps;
485 : }
486 :
487 : } // end namespace HSAMD
488 : } // end namespace AMDGPU
489 : } // end namespace llvm
|