/src/glslang/glslang/MachineIndependent/SpirvIntrinsics.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // Copyright(C) 2021 Advanced Micro Devices, Inc. |
3 | | // |
4 | | // All rights reserved. |
5 | | // |
6 | | // Redistribution and use in source and binary forms, with or without |
7 | | // modification, are permitted provided that the following conditions |
8 | | // are met: |
9 | | // |
10 | | // Redistributions of source code must retain the above copyright |
11 | | // notice, this list of conditions and the following disclaimer. |
12 | | // |
13 | | // Redistributions in binary form must reproduce the above |
14 | | // copyright notice, this list of conditions and the following |
15 | | // disclaimer in the documentation and/or other materials provided |
16 | | // with the distribution. |
17 | | // |
18 | | // Neither the name of 3Dlabs Inc. Ltd. nor the names of its |
19 | | // contributors may be used to endorse or promote products derived |
20 | | // from this software without specific prior written permission. |
21 | | // |
22 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
23 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
24 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
25 | | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
26 | | // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
27 | | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
28 | | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
29 | | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
30 | | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
31 | | // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
32 | | // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
33 | | // POSSIBILITY OF SUCH DAMAGE. |
34 | | // |
35 | | |
36 | | // |
37 | | // GL_EXT_spirv_intrinsics |
38 | | // |
39 | | #include "../Include/intermediate.h" |
40 | | #include "../Include/SpirvIntrinsics.h" |
41 | | #include "../Include/Types.h" |
42 | | #include "ParseHelper.h" |
43 | | |
44 | | namespace glslang { |
45 | | |
46 | | bool TSpirvTypeParameter::operator==(const TSpirvTypeParameter& rhs) const |
47 | 0 | { |
48 | 0 | if (getAsConstant() != nullptr) |
49 | 0 | return getAsConstant()->getConstArray() == rhs.getAsConstant()->getConstArray(); |
50 | | |
51 | 0 | assert(getAsType() != nullptr); |
52 | 0 | return *getAsType() == *rhs.getAsType(); |
53 | 0 | } |
54 | | |
55 | | // |
56 | | // Handle SPIR-V requirements |
57 | | // |
58 | | TSpirvRequirement* TParseContext::makeSpirvRequirement(const TSourceLoc& loc, const TString& name, |
59 | | const TIntermAggregate* extensions, |
60 | | const TIntermAggregate* capabilities) |
61 | 0 | { |
62 | 0 | TSpirvRequirement* spirvReq = new TSpirvRequirement; |
63 | |
|
64 | 0 | if (name == "extensions") { |
65 | 0 | assert(extensions); |
66 | 0 | for (auto extension : extensions->getSequence()) { |
67 | 0 | assert(extension->getAsConstantUnion()); |
68 | 0 | spirvReq->extensions.insert(*extension->getAsConstantUnion()->getConstArray()[0].getSConst()); |
69 | 0 | } |
70 | 0 | } else if (name == "capabilities") { |
71 | 0 | assert(capabilities); |
72 | 0 | for (auto capability : capabilities->getSequence()) { |
73 | 0 | assert(capability->getAsConstantUnion()); |
74 | 0 | spirvReq->capabilities.insert(capability->getAsConstantUnion()->getConstArray()[0].getIConst()); |
75 | 0 | } |
76 | 0 | } else |
77 | 0 | error(loc, "unknown SPIR-V requirement", name.c_str(), ""); |
78 | |
|
79 | 0 | return spirvReq; |
80 | 0 | } |
81 | | |
82 | | TSpirvRequirement* TParseContext::mergeSpirvRequirements(const TSourceLoc& loc, TSpirvRequirement* spirvReq1, |
83 | | TSpirvRequirement* spirvReq2) |
84 | 0 | { |
85 | | // Merge the second SPIR-V requirement to the first one |
86 | 0 | if (!spirvReq2->extensions.empty()) { |
87 | 0 | if (spirvReq1->extensions.empty()) |
88 | 0 | spirvReq1->extensions = spirvReq2->extensions; |
89 | 0 | else |
90 | 0 | error(loc, "too many SPIR-V requirements", "extensions", ""); |
91 | 0 | } |
92 | |
|
93 | 0 | if (!spirvReq2->capabilities.empty()) { |
94 | 0 | if (spirvReq1->capabilities.empty()) |
95 | 0 | spirvReq1->capabilities = spirvReq2->capabilities; |
96 | 0 | else |
97 | 0 | error(loc, "too many SPIR-V requirements", "capabilities", ""); |
98 | 0 | } |
99 | |
|
100 | 0 | return spirvReq1; |
101 | 0 | } |
102 | | |
103 | | void TIntermediate::insertSpirvRequirement(const TSpirvRequirement* spirvReq) |
104 | 0 | { |
105 | 0 | if (!spirvRequirement) |
106 | 0 | spirvRequirement = new TSpirvRequirement; |
107 | |
|
108 | 0 | for (auto extension : spirvReq->extensions) |
109 | 0 | spirvRequirement->extensions.insert(extension); |
110 | |
|
111 | 0 | for (auto capability : spirvReq->capabilities) |
112 | 0 | spirvRequirement->capabilities.insert(capability); |
113 | 0 | } |
114 | | |
115 | | // |
116 | | // Handle SPIR-V execution modes |
117 | | // |
118 | | void TIntermediate::insertSpirvExecutionMode(int executionMode, const TIntermAggregate* args) |
119 | 0 | { |
120 | 0 | if (!spirvExecutionMode) |
121 | 0 | spirvExecutionMode = new TSpirvExecutionMode; |
122 | |
|
123 | 0 | TVector<const TIntermConstantUnion*> extraOperands; |
124 | 0 | if (args) { |
125 | 0 | for (auto arg : args->getSequence()) { |
126 | 0 | auto extraOperand = arg->getAsConstantUnion(); |
127 | 0 | assert(extraOperand != nullptr); |
128 | 0 | extraOperands.push_back(extraOperand); |
129 | 0 | } |
130 | 0 | } |
131 | 0 | spirvExecutionMode->modes[executionMode] = extraOperands; |
132 | 0 | } |
133 | | |
134 | | void TIntermediate::insertSpirvExecutionModeId(int executionMode, const TIntermAggregate* args) |
135 | 0 | { |
136 | 0 | if (!spirvExecutionMode) |
137 | 0 | spirvExecutionMode = new TSpirvExecutionMode; |
138 | |
|
139 | 0 | assert(args); |
140 | 0 | TVector<const TIntermTyped*> extraOperands; |
141 | |
|
142 | 0 | for (auto arg : args->getSequence()) { |
143 | 0 | auto extraOperand = arg->getAsTyped(); |
144 | 0 | assert(extraOperand != nullptr && extraOperand->getQualifier().isConstant()); |
145 | 0 | extraOperands.push_back(extraOperand); |
146 | 0 | } |
147 | 0 | spirvExecutionMode->modeIds[executionMode] = extraOperands; |
148 | 0 | } |
149 | | |
150 | | // |
151 | | // Handle SPIR-V decorate qualifiers |
152 | | // |
153 | | void TQualifier::setSpirvDecorate(int decoration, const TIntermAggregate* args) |
154 | 0 | { |
155 | 0 | if (!spirvDecorate) |
156 | 0 | spirvDecorate = new TSpirvDecorate; |
157 | |
|
158 | 0 | TVector<const TIntermConstantUnion*> extraOperands; |
159 | 0 | if (args) { |
160 | 0 | for (auto arg : args->getSequence()) { |
161 | 0 | auto extraOperand = arg->getAsConstantUnion(); |
162 | 0 | assert(extraOperand != nullptr); |
163 | 0 | extraOperands.push_back(extraOperand); |
164 | 0 | } |
165 | 0 | } |
166 | 0 | spirvDecorate->decorates[decoration] = extraOperands; |
167 | 0 | } |
168 | | |
169 | | void TQualifier::setSpirvDecorateId(int decoration, const TIntermAggregate* args) |
170 | 0 | { |
171 | 0 | if (!spirvDecorate) |
172 | 0 | spirvDecorate = new TSpirvDecorate; |
173 | |
|
174 | 0 | assert(args); |
175 | 0 | TVector<const TIntermTyped*> extraOperands; |
176 | 0 | for (auto arg : args->getSequence()) { |
177 | 0 | auto extraOperand = arg->getAsTyped(); |
178 | 0 | assert(extraOperand != nullptr); |
179 | 0 | extraOperands.push_back(extraOperand); |
180 | 0 | } |
181 | 0 | spirvDecorate->decorateIds[decoration] = extraOperands; |
182 | 0 | } |
183 | | |
184 | | void TQualifier::setSpirvDecorateString(int decoration, const TIntermAggregate* args) |
185 | 0 | { |
186 | 0 | if (!spirvDecorate) |
187 | 0 | spirvDecorate = new TSpirvDecorate; |
188 | |
|
189 | 0 | assert(args); |
190 | 0 | TVector<const TIntermConstantUnion*> extraOperands; |
191 | 0 | for (auto arg : args->getSequence()) { |
192 | 0 | auto extraOperand = arg->getAsConstantUnion(); |
193 | 0 | assert(extraOperand != nullptr); |
194 | 0 | extraOperands.push_back(extraOperand); |
195 | 0 | } |
196 | 0 | spirvDecorate->decorateStrings[decoration] = extraOperands; |
197 | 0 | } |
198 | | |
199 | | TString TQualifier::getSpirvDecorateQualifierString() const |
200 | 0 | { |
201 | 0 | assert(spirvDecorate); |
202 | |
|
203 | 0 | TString qualifierString; |
204 | |
|
205 | 0 | const auto appendFloat = [&](float f) { qualifierString.append(std::to_string(f).c_str()); }; |
206 | 0 | const auto appendInt = [&](int i) { qualifierString.append(std::to_string(i).c_str()); }; |
207 | 0 | const auto appendUint = [&](unsigned int u) { qualifierString.append(std::to_string(u).c_str()); }; |
208 | 0 | const auto appendBool = [&](bool b) { qualifierString.append(std::to_string(b).c_str()); }; |
209 | 0 | const auto appendStr = [&](const char* s) { qualifierString.append(s); }; |
210 | |
|
211 | 0 | const auto appendDecorate = [&](const TIntermTyped* constant) { |
212 | 0 | if (constant->getAsConstantUnion()) { |
213 | 0 | auto& constArray = constant->getAsConstantUnion()->getConstArray(); |
214 | 0 | if (constant->getBasicType() == EbtFloat) { |
215 | 0 | float value = static_cast<float>(constArray[0].getDConst()); |
216 | 0 | appendFloat(value); |
217 | 0 | } else if (constant->getBasicType() == EbtInt) { |
218 | 0 | int value = constArray[0].getIConst(); |
219 | 0 | appendInt(value); |
220 | 0 | } else if (constant->getBasicType() == EbtUint) { |
221 | 0 | unsigned value = constArray[0].getUConst(); |
222 | 0 | appendUint(value); |
223 | 0 | } else if (constant->getBasicType() == EbtBool) { |
224 | 0 | bool value = constArray[0].getBConst(); |
225 | 0 | appendBool(value); |
226 | 0 | } else if (constant->getBasicType() == EbtString) { |
227 | 0 | const TString* value = constArray[0].getSConst(); |
228 | 0 | appendStr(value->c_str()); |
229 | 0 | } else |
230 | 0 | assert(0); |
231 | 0 | } else { |
232 | 0 | assert(constant->getAsSymbolNode()); |
233 | 0 | appendStr(constant->getAsSymbolNode()->getName().c_str()); |
234 | 0 | } |
235 | 0 | }; |
236 | |
|
237 | 0 | for (auto& decorate : spirvDecorate->decorates) { |
238 | 0 | appendStr("spirv_decorate("); |
239 | 0 | appendInt(decorate.first); |
240 | 0 | for (auto extraOperand : decorate.second) { |
241 | 0 | appendStr(", "); |
242 | 0 | appendDecorate(extraOperand); |
243 | 0 | } |
244 | 0 | appendStr(") "); |
245 | 0 | } |
246 | |
|
247 | 0 | for (auto& decorateId : spirvDecorate->decorateIds) { |
248 | 0 | appendStr("spirv_decorate_id("); |
249 | 0 | appendInt(decorateId.first); |
250 | 0 | for (auto extraOperand : decorateId.second) { |
251 | 0 | appendStr(", "); |
252 | 0 | appendDecorate(extraOperand); |
253 | 0 | } |
254 | 0 | appendStr(") "); |
255 | 0 | } |
256 | |
|
257 | 0 | for (auto& decorateString : spirvDecorate->decorateStrings) { |
258 | 0 | appendStr("spirv_decorate_string("); |
259 | 0 | appendInt(decorateString.first); |
260 | 0 | for (auto extraOperand : decorateString.second) { |
261 | 0 | appendStr(", "); |
262 | 0 | appendDecorate(extraOperand); |
263 | 0 | } |
264 | 0 | appendStr(") "); |
265 | 0 | } |
266 | |
|
267 | 0 | return qualifierString; |
268 | 0 | } |
269 | | |
270 | | // |
271 | | // Handle SPIR-V type specifiers |
272 | | // |
273 | | void TPublicType::setSpirvType(const TSpirvInstruction& spirvInst, const TSpirvTypeParameters* typeParams) |
274 | 0 | { |
275 | 0 | if (!spirvType) |
276 | 0 | spirvType = new TSpirvType; |
277 | |
|
278 | 0 | basicType = EbtSpirvType; |
279 | 0 | spirvType->spirvInst = spirvInst; |
280 | 0 | if (typeParams) |
281 | 0 | spirvType->typeParams = *typeParams; |
282 | 0 | } |
283 | | |
284 | | TSpirvTypeParameters* TParseContext::makeSpirvTypeParameters(const TSourceLoc& loc, const TIntermConstantUnion* constant) |
285 | 0 | { |
286 | 0 | TSpirvTypeParameters* spirvTypeParams = new TSpirvTypeParameters; |
287 | 0 | if (constant->getBasicType() != EbtFloat && |
288 | 0 | constant->getBasicType() != EbtInt && |
289 | 0 | constant->getBasicType() != EbtUint && |
290 | 0 | constant->getBasicType() != EbtBool && |
291 | 0 | constant->getBasicType() != EbtString) |
292 | 0 | error(loc, "this type not allowed", constant->getType().getBasicString(), ""); |
293 | 0 | else |
294 | 0 | spirvTypeParams->push_back(TSpirvTypeParameter(constant)); |
295 | |
|
296 | 0 | return spirvTypeParams; |
297 | 0 | } |
298 | | |
299 | | TSpirvTypeParameters* TParseContext::makeSpirvTypeParameters(const TSourceLoc& /* loc */, |
300 | | const TPublicType& type) |
301 | 0 | { |
302 | 0 | TSpirvTypeParameters* spirvTypeParams = new TSpirvTypeParameters; |
303 | 0 | spirvTypeParams->push_back(TSpirvTypeParameter(new TType(type))); |
304 | 0 | return spirvTypeParams; |
305 | 0 | } |
306 | | |
307 | | TSpirvTypeParameters* TParseContext::mergeSpirvTypeParameters(TSpirvTypeParameters* spirvTypeParams1, TSpirvTypeParameters* spirvTypeParams2) |
308 | 0 | { |
309 | | // Merge SPIR-V type parameters of the second one to the first one |
310 | 0 | for (const auto& spirvTypeParam : *spirvTypeParams2) |
311 | 0 | spirvTypeParams1->push_back(spirvTypeParam); |
312 | 0 | return spirvTypeParams1; |
313 | 0 | } |
314 | | |
315 | | // |
316 | | // Handle SPIR-V instruction qualifiers |
317 | | // |
318 | | TSpirvInstruction* TParseContext::makeSpirvInstruction(const TSourceLoc& loc, const TString& name, const TString& value) |
319 | 0 | { |
320 | 0 | TSpirvInstruction* spirvInst = new TSpirvInstruction; |
321 | 0 | if (name == "set") |
322 | 0 | spirvInst->set = value; |
323 | 0 | else |
324 | 0 | error(loc, "unknown SPIR-V instruction qualifier", name.c_str(), ""); |
325 | |
|
326 | 0 | return spirvInst; |
327 | 0 | } |
328 | | |
329 | | TSpirvInstruction* TParseContext::makeSpirvInstruction(const TSourceLoc& loc, const TString& name, int value) |
330 | 0 | { |
331 | 0 | TSpirvInstruction* spirvInstuction = new TSpirvInstruction; |
332 | 0 | if (name == "id") |
333 | 0 | spirvInstuction->id = value; |
334 | 0 | else |
335 | 0 | error(loc, "unknown SPIR-V instruction qualifier", name.c_str(), ""); |
336 | |
|
337 | 0 | return spirvInstuction; |
338 | 0 | } |
339 | | |
340 | | TSpirvInstruction* TParseContext::mergeSpirvInstruction(const TSourceLoc& loc, TSpirvInstruction* spirvInst1, TSpirvInstruction* spirvInst2) |
341 | 0 | { |
342 | | // Merge qualifiers of the second SPIR-V instruction to those of the first one |
343 | 0 | if (!spirvInst2->set.empty()) { |
344 | 0 | if (spirvInst1->set.empty()) |
345 | 0 | spirvInst1->set = spirvInst2->set; |
346 | 0 | else |
347 | 0 | error(loc, "too many SPIR-V instruction qualifiers", "spirv_instruction", "(set)"); |
348 | 0 | } |
349 | |
|
350 | 0 | if (spirvInst2->id != -1) { |
351 | 0 | if (spirvInst1->id == -1) |
352 | 0 | spirvInst1->id = spirvInst2->id; |
353 | 0 | else |
354 | 0 | error(loc, "too many SPIR-V instruction qualifiers", "spirv_instruction", "(id)"); |
355 | 0 | } |
356 | |
|
357 | 0 | return spirvInst1; |
358 | 0 | } |
359 | | |
360 | | } // end namespace glslang |