blob: 862b90949fcdda8c869a8e48da3d0b7c8c377ad5 [file] [log] [blame]
alan-bakera1be3322020-04-20 12:48:18 -04001// Copyright 2020 The Clspv Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "llvm/IR/Constants.h"
16
17#include "Constants.h"
18#include "SpecConstant.h"
19
20using namespace llvm;
21
22namespace {
23
24void InitSpecConstantMetadata(Module *module) {
25 auto next_spec_id_md =
26 module->getOrInsertNamedMetadata(clspv::NextSpecConstantMetadataName());
27 next_spec_id_md->clearOperands();
28
29 // Start at 3 to accommodate workgroup size ids.
30 const uint32_t first_spec_id = 3;
31 auto id_const = ValueAsMetadata::getConstant(ConstantInt::get(
32 IntegerType::get(module->getContext(), 32), first_spec_id));
33 auto id_md = MDTuple::get(module->getContext(), {id_const});
34 next_spec_id_md->addOperand(id_md);
35
36 auto spec_constant_list_md =
37 module->getOrInsertNamedMetadata(clspv::SpecConstantMetadataName());
38 spec_constant_list_md->clearOperands();
39}
40
41} // namespace
42
43namespace clspv {
44
45const char *GetSpecConstantName(SpecConstant kind) {
46 switch (kind) {
47 case SpecConstant::kWorkgroupSizeX:
48 return "workgroup_size_x";
49 case SpecConstant::kWorkgroupSizeY:
50 return "workgroup_size_y";
51 case SpecConstant::kWorkgroupSizeZ:
52 return "workgroup_size_z";
53 case SpecConstant::kLocalMemorySize:
54 return "local_memory_size";
alan-bakerbed3a882020-04-21 14:42:41 -040055 case SpecConstant::kWorkDim:
56 return "work_dim";
alan-bakera1be3322020-04-20 12:48:18 -040057 }
58 llvm::errs() << "Unhandled case in clspv::GetSpecConstantName: " << int(kind)
59 << "\n";
60 return "";
61}
62
63SpecConstant GetSpecConstantFromName(const std::string &name) {
64 if (name == "workgroup_size_x")
65 return SpecConstant::kWorkgroupSizeX;
66 else if (name == "workgroup_size_y")
67 return SpecConstant::kWorkgroupSizeY;
68 else if (name == "workgroup_size_z")
69 return SpecConstant::kWorkgroupSizeZ;
70 else if (name == "local_memory_size")
71 return SpecConstant::kLocalMemorySize;
alan-bakerbed3a882020-04-21 14:42:41 -040072 else if (name == "work_dim")
73 return SpecConstant::kWorkDim;
alan-bakera1be3322020-04-20 12:48:18 -040074
75 llvm::errs() << "Unhandled csae in clspv::GetSpecConstantFromName: " << name
76 << "\n";
77 return SpecConstant::kWorkgroupSizeX;
78}
79
80void AddWorkgroupSpecConstants(Module *module) {
81 auto spec_constant_list_md =
82 module->getNamedMetadata(SpecConstantMetadataName());
83 if (!spec_constant_list_md) {
84 InitSpecConstantMetadata(module);
85 spec_constant_list_md =
86 module->getNamedMetadata(SpecConstantMetadataName());
87 }
88
89 // Workgroup size spec constants always occupy ids 0, 1 and 2.
90 auto enum_const = ValueAsMetadata::getConstant(
91 ConstantInt::get(IntegerType::get(module->getContext(), 32),
92 static_cast<uint64_t>(SpecConstant::kWorkgroupSizeX)));
93 auto id_const = ValueAsMetadata::getConstant(
94 ConstantInt::get(IntegerType::get(module->getContext(), 32), 0));
95 auto wg_md = MDTuple::get(module->getContext(), {enum_const, id_const});
96 spec_constant_list_md->addOperand(wg_md);
97
98 enum_const = ValueAsMetadata::getConstant(
99 ConstantInt::get(IntegerType::get(module->getContext(), 32),
100 static_cast<uint64_t>(SpecConstant::kWorkgroupSizeY)));
101 id_const = ValueAsMetadata::getConstant(
102 ConstantInt::get(IntegerType::get(module->getContext(), 32), 1));
103 wg_md = MDTuple::get(module->getContext(), {enum_const, id_const});
104 spec_constant_list_md->addOperand(wg_md);
105
106 enum_const = ValueAsMetadata::getConstant(
107 ConstantInt::get(IntegerType::get(module->getContext(), 32),
108 static_cast<uint64_t>(SpecConstant::kWorkgroupSizeZ)));
109 id_const = ValueAsMetadata::getConstant(
110 ConstantInt::get(IntegerType::get(module->getContext(), 32), 2));
111 wg_md = MDTuple::get(module->getContext(), {enum_const, id_const});
112 spec_constant_list_md->addOperand(wg_md);
113}
114
115uint32_t AllocateSpecConstant(Module *module, SpecConstant kind) {
116 auto spec_constant_id_md =
117 module->getNamedMetadata(NextSpecConstantMetadataName());
118 if (!spec_constant_id_md) {
119 InitSpecConstantMetadata(module);
120 spec_constant_id_md =
121 module->getNamedMetadata(NextSpecConstantMetadataName());
122 }
123
124 auto value_md = spec_constant_id_md->getOperand(0);
125 auto value = cast<ConstantInt>(
126 dyn_cast<ValueAsMetadata>(value_md->getOperand(0))->getValue());
127 uint32_t next_id = static_cast<uint32_t>(value->getZExtValue());
128 // Update the next available id.
129 value_md->replaceOperandWith(
130 0, ValueAsMetadata::getConstant(ConstantInt::get(
131 IntegerType::get(module->getContext(), 32), next_id + 1)));
132
133 // Add the allocation to the metadata list.
134 auto spec_constant_list_md =
135 module->getNamedMetadata(SpecConstantMetadataName());
136 auto enum_const = ValueAsMetadata::getConstant(ConstantInt::get(
137 IntegerType::get(module->getContext(), 32), static_cast<uint64_t>(kind)));
138 auto id_const = ValueAsMetadata::getConstant(
139 ConstantInt::get(IntegerType::get(module->getContext(), 32), next_id));
140 auto wg_md = MDTuple::get(module->getContext(), {enum_const, id_const});
141 spec_constant_list_md->addOperand(wg_md);
142
143 return next_id;
144}
145
146std::vector<std::pair<SpecConstant, uint32_t>>
147GetSpecConstants(Module *module) {
148 std::vector<std::pair<SpecConstant, uint32_t>> spec_constants;
149 auto spec_constant_md =
150 module->getNamedMetadata(clspv::SpecConstantMetadataName());
151 if (!spec_constant_md)
152 return spec_constants;
153
154 for (auto pair : spec_constant_md->operands()) {
155 // Metadata is formatted as pairs of <SpecConstant, id>.
156 auto kind = static_cast<SpecConstant>(
157 cast<ConstantInt>(
158 cast<ValueAsMetadata>(pair->getOperand(0))->getValue())
159 ->getZExtValue());
160
161 uint32_t spec_id = static_cast<uint32_t>(
162 cast<ConstantInt>(
163 cast<ValueAsMetadata>(pair->getOperand(1))->getValue())
164 ->getZExtValue());
165 spec_constants.emplace_back(kind, spec_id);
166 }
167
168 return spec_constants;
169}
170
171} // namespace clspv