blob: a5ccc894715ac98eb9c7382bf0df33a637a35ef3 [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));
James Price2cf925c2021-01-07 11:44:25 -050033 auto id_md = MDTuple::getDistinct(module->getContext(), {id_const});
alan-bakera1be3322020-04-20 12:48:18 -040034 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-bakere1996972020-05-04 08:38:12 -040057 case SpecConstant::kGlobalOffsetX:
58 return "global_offset_x";
59 case SpecConstant::kGlobalOffsetY:
60 return "global_offset_y";
61 case SpecConstant::kGlobalOffsetZ:
62 return "global_offset_z";
alan-bakera1be3322020-04-20 12:48:18 -040063 }
64 llvm::errs() << "Unhandled case in clspv::GetSpecConstantName: " << int(kind)
65 << "\n";
66 return "";
67}
68
69SpecConstant GetSpecConstantFromName(const std::string &name) {
70 if (name == "workgroup_size_x")
71 return SpecConstant::kWorkgroupSizeX;
72 else if (name == "workgroup_size_y")
73 return SpecConstant::kWorkgroupSizeY;
74 else if (name == "workgroup_size_z")
75 return SpecConstant::kWorkgroupSizeZ;
76 else if (name == "local_memory_size")
77 return SpecConstant::kLocalMemorySize;
alan-bakerbed3a882020-04-21 14:42:41 -040078 else if (name == "work_dim")
79 return SpecConstant::kWorkDim;
alan-bakere1996972020-05-04 08:38:12 -040080 else if (name == "global_offset_x")
81 return SpecConstant::kGlobalOffsetX;
82 else if (name == "global_offset_y")
83 return SpecConstant::kGlobalOffsetY;
84 else if (name == "global_offset_z")
85 return SpecConstant::kGlobalOffsetZ;
alan-bakera1be3322020-04-20 12:48:18 -040086
87 llvm::errs() << "Unhandled csae in clspv::GetSpecConstantFromName: " << name
88 << "\n";
89 return SpecConstant::kWorkgroupSizeX;
90}
91
92void AddWorkgroupSpecConstants(Module *module) {
93 auto spec_constant_list_md =
94 module->getNamedMetadata(SpecConstantMetadataName());
95 if (!spec_constant_list_md) {
96 InitSpecConstantMetadata(module);
97 spec_constant_list_md =
98 module->getNamedMetadata(SpecConstantMetadataName());
99 }
100
101 // Workgroup size spec constants always occupy ids 0, 1 and 2.
102 auto enum_const = ValueAsMetadata::getConstant(
103 ConstantInt::get(IntegerType::get(module->getContext(), 32),
104 static_cast<uint64_t>(SpecConstant::kWorkgroupSizeX)));
105 auto id_const = ValueAsMetadata::getConstant(
106 ConstantInt::get(IntegerType::get(module->getContext(), 32), 0));
107 auto wg_md = MDTuple::get(module->getContext(), {enum_const, id_const});
108 spec_constant_list_md->addOperand(wg_md);
109
110 enum_const = ValueAsMetadata::getConstant(
111 ConstantInt::get(IntegerType::get(module->getContext(), 32),
112 static_cast<uint64_t>(SpecConstant::kWorkgroupSizeY)));
113 id_const = ValueAsMetadata::getConstant(
114 ConstantInt::get(IntegerType::get(module->getContext(), 32), 1));
115 wg_md = MDTuple::get(module->getContext(), {enum_const, id_const});
116 spec_constant_list_md->addOperand(wg_md);
117
118 enum_const = ValueAsMetadata::getConstant(
119 ConstantInt::get(IntegerType::get(module->getContext(), 32),
120 static_cast<uint64_t>(SpecConstant::kWorkgroupSizeZ)));
121 id_const = ValueAsMetadata::getConstant(
122 ConstantInt::get(IntegerType::get(module->getContext(), 32), 2));
123 wg_md = MDTuple::get(module->getContext(), {enum_const, id_const});
124 spec_constant_list_md->addOperand(wg_md);
125}
126
127uint32_t AllocateSpecConstant(Module *module, SpecConstant kind) {
128 auto spec_constant_id_md =
129 module->getNamedMetadata(NextSpecConstantMetadataName());
130 if (!spec_constant_id_md) {
131 InitSpecConstantMetadata(module);
132 spec_constant_id_md =
133 module->getNamedMetadata(NextSpecConstantMetadataName());
134 }
135
136 auto value_md = spec_constant_id_md->getOperand(0);
137 auto value = cast<ConstantInt>(
138 dyn_cast<ValueAsMetadata>(value_md->getOperand(0))->getValue());
139 uint32_t next_id = static_cast<uint32_t>(value->getZExtValue());
140 // Update the next available id.
141 value_md->replaceOperandWith(
142 0, ValueAsMetadata::getConstant(ConstantInt::get(
143 IntegerType::get(module->getContext(), 32), next_id + 1)));
144
145 // Add the allocation to the metadata list.
146 auto spec_constant_list_md =
147 module->getNamedMetadata(SpecConstantMetadataName());
148 auto enum_const = ValueAsMetadata::getConstant(ConstantInt::get(
149 IntegerType::get(module->getContext(), 32), static_cast<uint64_t>(kind)));
150 auto id_const = ValueAsMetadata::getConstant(
151 ConstantInt::get(IntegerType::get(module->getContext(), 32), next_id));
152 auto wg_md = MDTuple::get(module->getContext(), {enum_const, id_const});
153 spec_constant_list_md->addOperand(wg_md);
154
155 return next_id;
156}
157
158std::vector<std::pair<SpecConstant, uint32_t>>
159GetSpecConstants(Module *module) {
160 std::vector<std::pair<SpecConstant, uint32_t>> spec_constants;
161 auto spec_constant_md =
162 module->getNamedMetadata(clspv::SpecConstantMetadataName());
163 if (!spec_constant_md)
164 return spec_constants;
165
166 for (auto pair : spec_constant_md->operands()) {
167 // Metadata is formatted as pairs of <SpecConstant, id>.
168 auto kind = static_cast<SpecConstant>(
169 cast<ConstantInt>(
170 cast<ValueAsMetadata>(pair->getOperand(0))->getValue())
171 ->getZExtValue());
172
173 uint32_t spec_id = static_cast<uint32_t>(
174 cast<ConstantInt>(
175 cast<ValueAsMetadata>(pair->getOperand(1))->getValue())
176 ->getZExtValue());
177 spec_constants.emplace_back(kind, spec_id);
178 }
179
180 return spec_constants;
181}
182
183} // namespace clspv