blob: b4c56c471ba4b69775543eaaf2e24bd6f0ac1266 [file] [log] [blame]
Kévin Petitbbbda972020-03-03 19:16:31 +00001// 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 "PushConstant.h"
16
17#include "llvm/IR/Constants.h"
18#include "llvm/IR/Function.h"
19#include "llvm/IR/IRBuilder.h"
20#include "llvm/IR/Metadata.h"
21#include "llvm/IR/Module.h"
22#include "llvm/IR/Type.h"
23#include "llvm/Support/ErrorHandling.h"
24
alan-bakerc4579bb2020-04-29 14:15:50 -040025#include "clspv/Option.h"
26
Kévin Petitbbbda972020-03-03 19:16:31 +000027#include "Constants.h"
28
29using namespace llvm;
30
31namespace clspv {
32
33const char *GetPushConstantName(PushConstant pc) {
34 switch (pc) {
35 case PushConstant::Dimensions:
36 return "dimensions";
37 case PushConstant::GlobalOffset:
38 return "global_offset";
Kévin Petit1af73be2020-03-11 17:53:44 +000039 case PushConstant::EnqueuedLocalSize:
40 return "enqueued_local_size";
Kévin Petit21c23c62020-04-29 01:38:28 +010041 case PushConstant::GlobalSize:
42 return "global_size";
43 case PushConstant::RegionOffset:
44 return "region_offset";
45 case PushConstant::NumWorkgroups:
46 return "num_workgroups";
47 case PushConstant::RegionGroupOffset:
48 return "region_group_offset";
alan-baker6a3930b2020-05-21 10:09:11 -040049 case PushConstant::KernelArgument:
50 return "kernel_argument";
Kévin Petitbbbda972020-03-03 19:16:31 +000051 }
52 llvm_unreachable("Unknown PushConstant in GetPushConstantName");
53 return "";
54}
55
56Type *GetPushConstantType(Module &M, PushConstant pc) {
57 auto &C = M.getContext();
58 switch (pc) {
59 case PushConstant::Dimensions:
60 return IntegerType::get(C, 32);
61 case PushConstant::GlobalOffset:
62 return VectorType::get(IntegerType::get(C, 32), 3);
Kévin Petit1af73be2020-03-11 17:53:44 +000063 case PushConstant::EnqueuedLocalSize:
64 return VectorType::get(IntegerType::get(C, 32), 3);
Kévin Petit21c23c62020-04-29 01:38:28 +010065 case PushConstant::GlobalSize:
66 return VectorType::get(IntegerType::get(C, 32), 3);
67 case PushConstant::RegionOffset:
68 return VectorType::get(IntegerType::get(C, 32), 3);
69 case PushConstant::NumWorkgroups:
70 return VectorType::get(IntegerType::get(C, 32), 3);
71 case PushConstant::RegionGroupOffset:
72 return VectorType::get(IntegerType::get(C, 32), 3);
alan-baker6a3930b2020-05-21 10:09:11 -040073 default:
74 break;
Kévin Petitbbbda972020-03-03 19:16:31 +000075 }
76 llvm_unreachable("Unknown PushConstant in GetPushConstantType");
77 return nullptr;
78}
79
alan-baker6a3930b2020-05-21 10:09:11 -040080Value *GetPushConstantPointer(BasicBlock *BB, PushConstant pc,
81 const ArrayRef<Value *> &extra_indices) {
Kévin Petitbbbda972020-03-03 19:16:31 +000082 auto M = BB->getParent()->getParent();
83
84 // Get variable
85 auto GV = M->getGlobalVariable(clspv::PushConstantsVariableName());
86 assert(GV && "Push constants requested but none are declared.");
87
88 // Find requested pc in metadata
89 auto MD = GV->getMetadata(clspv::PushConstantsMetadataName());
90 bool found = false;
91 uint32_t idx = 0;
92 for (auto &PCMD : MD->operands()) {
93 auto mpc = static_cast<PushConstant>(
94 mdconst::extract<ConstantInt>(PCMD)->getZExtValue());
95 if (mpc == pc) {
96 found = true;
97 break;
98 }
99 idx++;
100 }
101
102 // Assert that it exists
103 assert(found && "Push constant wasn't declared.");
104
105 // Construct pointer
106 IRBuilder<> Builder(BB);
alan-baker6a3930b2020-05-21 10:09:11 -0400107 SmallVector<Value *, 4> Indices(2);
108 Indices[0] = Builder.getInt32(0);
109 Indices[1] = Builder.getInt32(idx);
110 for (auto idx : extra_indices)
111 Indices.push_back(idx);
Kévin Petitbbbda972020-03-03 19:16:31 +0000112 return Builder.CreateInBoundsGEP(GV, Indices);
113}
114
alan-bakerc4579bb2020-04-29 14:15:50 -0400115bool UsesGlobalPushConstants(Module &M) {
alan-baker6a3930b2020-05-21 10:09:11 -0400116 return ShouldDeclareGlobalOffsetPushConstant(M) ||
117 ShouldDeclareEnqueuedLocalSizePushConstant(M) ||
118 ShouldDeclareGlobalSizePushConstant(M) ||
119 ShouldDeclareRegionOffsetPushConstant(M) ||
120 ShouldDeclareNumWorkgroupsPushConstant(M) ||
121 ShouldDeclareRegionGroupOffsetPushConstant(M);
alan-bakerc4579bb2020-04-29 14:15:50 -0400122}
123
alan-bakere1996972020-05-04 08:38:12 -0400124bool ShouldDeclareGlobalOffsetPushConstant(Module &M) {
125 bool isEnabled = (clspv::Option::GlobalOffset() &&
126 clspv::Option::NonUniformNDRangeSupported()) ||
127 clspv::Option::GlobalOffsetPushConstant();
alan-bakerc4579bb2020-04-29 14:15:50 -0400128 bool isUsed = (M.getFunction("_Z17get_global_offsetj") != nullptr) ||
129 (M.getFunction("_Z13get_global_idj") != nullptr);
130 return isEnabled && isUsed;
131}
132
alan-baker6a3930b2020-05-21 10:09:11 -0400133bool ShouldDeclareEnqueuedLocalSizePushConstant(Module &M) {
134 bool isEnabled = clspv::Option::NonUniformNDRangeSupported();
135 bool isUsed = M.getFunction("_Z23get_enqueued_local_sizej") != nullptr;
136 return isEnabled && isUsed;
137}
138
139bool ShouldDeclareGlobalSizePushConstant(Module &M) {
140 bool isEnabled = clspv::Option::NonUniformNDRangeSupported();
141 bool isUsed = M.getFunction("_Z15get_global_sizej") != nullptr;
142 return isEnabled && isUsed;
143}
144
145bool ShouldDeclareRegionOffsetPushConstant(Module &M) {
146 bool isEnabled = clspv::Option::NonUniformNDRangeSupported();
147 bool isUsed = M.getFunction("_Z13get_global_idj") != nullptr;
148 return isEnabled && isUsed;
149}
150
151bool ShouldDeclareNumWorkgroupsPushConstant(Module &M) {
152 bool isEnabled = clspv::Option::NonUniformNDRangeSupported();
153 bool isUsed = M.getFunction("_Z14get_num_groupsj") != nullptr;
154 return isEnabled && isUsed;
155}
156
157bool ShouldDeclareRegionGroupOffsetPushConstant(Module &M) {
158 bool isEnabled = clspv::Option::NonUniformNDRangeSupported();
159 bool isUsed = M.getFunction("_Z12get_group_idj") != nullptr;
160 return isEnabled && isUsed;
161}
162
163uint64_t GlobalPushConstantsSize(Module &M) {
164 const auto &DL = M.getDataLayout();
165 if (auto GV = M.getGlobalVariable(clspv::PushConstantsVariableName())) {
166 auto ptr_ty = GV->getType();
167 auto block_ty = ptr_ty->getPointerElementType();
168 return DL.getTypeStoreSize(block_ty).getKnownMinSize();
169 } else {
170 SmallVector<Type *, 8> types;
171 if (ShouldDeclareGlobalOffsetPushConstant(M)) {
172 auto type = GetPushConstantType(M, PushConstant::GlobalOffset);
173 types.push_back(type);
174 }
175 if (ShouldDeclareEnqueuedLocalSizePushConstant(M)) {
176 auto type = GetPushConstantType(M, PushConstant::EnqueuedLocalSize);
177 types.push_back(type);
178 }
179 if (ShouldDeclareGlobalSizePushConstant(M)) {
180 auto type = GetPushConstantType(M, PushConstant::GlobalSize);
181 types.push_back(type);
182 }
183 if (ShouldDeclareRegionOffsetPushConstant(M)) {
184 auto type = GetPushConstantType(M, PushConstant::RegionOffset);
185 types.push_back(type);
186 }
187 if (ShouldDeclareNumWorkgroupsPushConstant(M)) {
188 auto type = GetPushConstantType(M, PushConstant::NumWorkgroups);
189 types.push_back(type);
190 }
191 if (ShouldDeclareRegionGroupOffsetPushConstant(M)) {
192 auto type = GetPushConstantType(M, PushConstant::RegionGroupOffset);
193 types.push_back(type);
194 }
195
196 auto block_ty = StructType::get(M.getContext(), types, false);
197 return DL.getTypeStoreSize(block_ty).getKnownMinSize();
198 }
199}
200
Kévin Petitbbbda972020-03-03 19:16:31 +0000201} // namespace clspv