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
operator ==(const TSpirvTypeParameter & rhs) const46 bool TSpirvTypeParameter::operator==(const TSpirvTypeParameter& rhs) const
47 {
48 if (getAsConstant() != nullptr)
49 return getAsConstant()->getConstArray() == rhs.getAsConstant()->getConstArray();
50
51 assert(getAsType() != nullptr);
52 return *getAsType() == *rhs.getAsType();
53 }
54
55 //
56 // Handle SPIR-V requirements
57 //
makeSpirvRequirement(const TSourceLoc & loc,const TString & name,const TIntermAggregate * extensions,const TIntermAggregate * capabilities)58 TSpirvRequirement* TParseContext::makeSpirvRequirement(const TSourceLoc& loc, const TString& name,
59 const TIntermAggregate* extensions,
60 const TIntermAggregate* capabilities)
61 {
62 TSpirvRequirement* spirvReq = new TSpirvRequirement;
63
64 if (name == "extensions") {
65 assert(extensions);
66 for (auto extension : extensions->getSequence()) {
67 assert(extension->getAsConstantUnion());
68 spirvReq->extensions.insert(*extension->getAsConstantUnion()->getConstArray()[0].getSConst());
69 }
70 } else if (name == "capabilities") {
71 assert(capabilities);
72 for (auto capability : capabilities->getSequence()) {
73 assert(capability->getAsConstantUnion());
74 spirvReq->capabilities.insert(capability->getAsConstantUnion()->getConstArray()[0].getIConst());
75 }
76 } else
77 error(loc, "unknown SPIR-V requirement", name.c_str(), "");
78
79 return spirvReq;
80 }
81
mergeSpirvRequirements(const TSourceLoc & loc,TSpirvRequirement * spirvReq1,TSpirvRequirement * spirvReq2)82 TSpirvRequirement* TParseContext::mergeSpirvRequirements(const TSourceLoc& loc, TSpirvRequirement* spirvReq1,
83 TSpirvRequirement* spirvReq2)
84 {
85 // Merge the second SPIR-V requirement to the first one
86 if (!spirvReq2->extensions.empty()) {
87 if (spirvReq1->extensions.empty())
88 spirvReq1->extensions = spirvReq2->extensions;
89 else
90 error(loc, "too many SPIR-V requirements", "extensions", "");
91 }
92
93 if (!spirvReq2->capabilities.empty()) {
94 if (spirvReq1->capabilities.empty())
95 spirvReq1->capabilities = spirvReq2->capabilities;
96 else
97 error(loc, "too many SPIR-V requirements", "capabilities", "");
98 }
99
100 return spirvReq1;
101 }
102
insertSpirvRequirement(const TSpirvRequirement * spirvReq)103 void TIntermediate::insertSpirvRequirement(const TSpirvRequirement* spirvReq)
104 {
105 if (!spirvRequirement)
106 spirvRequirement = new TSpirvRequirement;
107
108 for (auto extension : spirvReq->extensions)
109 spirvRequirement->extensions.insert(extension);
110
111 for (auto capability : spirvReq->capabilities)
112 spirvRequirement->capabilities.insert(capability);
113 }
114
115 //
116 // Handle SPIR-V execution modes
117 //
insertSpirvExecutionMode(int executionMode,const TIntermAggregate * args)118 void TIntermediate::insertSpirvExecutionMode(int executionMode, const TIntermAggregate* args)
119 {
120 if (!spirvExecutionMode)
121 spirvExecutionMode = new TSpirvExecutionMode;
122
123 TVector<const TIntermConstantUnion*> extraOperands;
124 if (args) {
125 for (auto arg : args->getSequence()) {
126 auto extraOperand = arg->getAsConstantUnion();
127 assert(extraOperand != nullptr);
128 extraOperands.push_back(extraOperand);
129 }
130 }
131 spirvExecutionMode->modes[executionMode] = extraOperands;
132 }
133
insertSpirvExecutionModeId(int executionMode,const TIntermAggregate * args)134 void TIntermediate::insertSpirvExecutionModeId(int executionMode, const TIntermAggregate* args)
135 {
136 if (!spirvExecutionMode)
137 spirvExecutionMode = new TSpirvExecutionMode;
138
139 assert(args);
140 TVector<const TIntermTyped*> extraOperands;
141
142 for (auto arg : args->getSequence()) {
143 auto extraOperand = arg->getAsTyped();
144 assert(extraOperand != nullptr && extraOperand->getQualifier().isConstant());
145 extraOperands.push_back(extraOperand);
146 }
147 spirvExecutionMode->modeIds[executionMode] = extraOperands;
148 }
149
150 //
151 // Handle SPIR-V decorate qualifiers
152 //
setSpirvDecorate(int decoration,const TIntermAggregate * args)153 void TQualifier::setSpirvDecorate(int decoration, const TIntermAggregate* args)
154 {
155 if (!spirvDecorate)
156 spirvDecorate = new TSpirvDecorate;
157
158 TVector<const TIntermConstantUnion*> extraOperands;
159 if (args) {
160 for (auto arg : args->getSequence()) {
161 auto extraOperand = arg->getAsConstantUnion();
162 assert(extraOperand != nullptr);
163 extraOperands.push_back(extraOperand);
164 }
165 }
166 spirvDecorate->decorates[decoration] = extraOperands;
167 }
168
setSpirvDecorateId(int decoration,const TIntermAggregate * args)169 void TQualifier::setSpirvDecorateId(int decoration, const TIntermAggregate* args)
170 {
171 if (!spirvDecorate)
172 spirvDecorate = new TSpirvDecorate;
173
174 assert(args);
175 TVector<const TIntermTyped*> extraOperands;
176 for (auto arg : args->getSequence()) {
177 auto extraOperand = arg->getAsTyped();
178 assert(extraOperand != nullptr);
179 extraOperands.push_back(extraOperand);
180 }
181 spirvDecorate->decorateIds[decoration] = extraOperands;
182 }
183
setSpirvDecorateString(int decoration,const TIntermAggregate * args)184 void TQualifier::setSpirvDecorateString(int decoration, const TIntermAggregate* args)
185 {
186 if (!spirvDecorate)
187 spirvDecorate = new TSpirvDecorate;
188
189 assert(args);
190 TVector<const TIntermConstantUnion*> extraOperands;
191 for (auto arg : args->getSequence()) {
192 auto extraOperand = arg->getAsConstantUnion();
193 assert(extraOperand != nullptr);
194 extraOperands.push_back(extraOperand);
195 }
196 spirvDecorate->decorateStrings[decoration] = extraOperands;
197 }
198
getSpirvDecorateQualifierString() const199 TString TQualifier::getSpirvDecorateQualifierString() const
200 {
201 assert(spirvDecorate);
202
203 TString qualifierString;
204
205 const auto appendFloat = [&](float f) { qualifierString.append(std::to_string(f).c_str()); };
206 const auto appendInt = [&](int i) { qualifierString.append(std::to_string(i).c_str()); };
207 const auto appendUint = [&](unsigned int u) { qualifierString.append(std::to_string(u).c_str()); };
208 const auto appendBool = [&](bool b) { qualifierString.append(std::to_string(b).c_str()); };
209 const auto appendStr = [&](const char* s) { qualifierString.append(s); };
210
211 const auto appendDecorate = [&](const TIntermTyped* constant) {
212 if (constant->getAsConstantUnion()) {
213 auto& constArray = constant->getAsConstantUnion()->getConstArray();
214 if (constant->getBasicType() == EbtFloat) {
215 float value = static_cast<float>(constArray[0].getDConst());
216 appendFloat(value);
217 } else if (constant->getBasicType() == EbtInt) {
218 int value = constArray[0].getIConst();
219 appendInt(value);
220 } else if (constant->getBasicType() == EbtUint) {
221 unsigned value = constArray[0].getUConst();
222 appendUint(value);
223 } else if (constant->getBasicType() == EbtBool) {
224 bool value = constArray[0].getBConst();
225 appendBool(value);
226 } else if (constant->getBasicType() == EbtString) {
227 const TString* value = constArray[0].getSConst();
228 appendStr(value->c_str());
229 } else
230 assert(0);
231 } else {
232 assert(constant->getAsSymbolNode());
233 appendStr(constant->getAsSymbolNode()->getName().c_str());
234 }
235 };
236
237 for (auto& decorate : spirvDecorate->decorates) {
238 appendStr("spirv_decorate(");
239 appendInt(decorate.first);
240 for (auto extraOperand : decorate.second) {
241 appendStr(", ");
242 appendDecorate(extraOperand);
243 }
244 appendStr(") ");
245 }
246
247 for (auto& decorateId : spirvDecorate->decorateIds) {
248 appendStr("spirv_decorate_id(");
249 appendInt(decorateId.first);
250 for (auto extraOperand : decorateId.second) {
251 appendStr(", ");
252 appendDecorate(extraOperand);
253 }
254 appendStr(") ");
255 }
256
257 for (auto& decorateString : spirvDecorate->decorateStrings) {
258 appendStr("spirv_decorate_string(");
259 appendInt(decorateString.first);
260 for (auto extraOperand : decorateString.second) {
261 appendStr(", ");
262 appendDecorate(extraOperand);
263 }
264 appendStr(") ");
265 }
266
267 return qualifierString;
268 }
269
270 //
271 // Handle SPIR-V type specifiers
272 //
setSpirvType(const TSpirvInstruction & spirvInst,const TSpirvTypeParameters * typeParams)273 void TPublicType::setSpirvType(const TSpirvInstruction& spirvInst, const TSpirvTypeParameters* typeParams)
274 {
275 if (!spirvType)
276 spirvType = new TSpirvType;
277
278 basicType = EbtSpirvType;
279 spirvType->spirvInst = spirvInst;
280 if (typeParams)
281 spirvType->typeParams = *typeParams;
282 }
283
makeSpirvTypeParameters(const TSourceLoc & loc,const TIntermConstantUnion * constant)284 TSpirvTypeParameters* TParseContext::makeSpirvTypeParameters(const TSourceLoc& loc, const TIntermConstantUnion* constant)
285 {
286 TSpirvTypeParameters* spirvTypeParams = new TSpirvTypeParameters;
287 if (constant->getBasicType() != EbtFloat &&
288 constant->getBasicType() != EbtInt &&
289 constant->getBasicType() != EbtUint &&
290 constant->getBasicType() != EbtBool &&
291 constant->getBasicType() != EbtString)
292 error(loc, "this type not allowed", constant->getType().getBasicString(), "");
293 else
294 spirvTypeParams->push_back(TSpirvTypeParameter(constant));
295
296 return spirvTypeParams;
297 }
298
makeSpirvTypeParameters(const TSourceLoc &,const TPublicType & type)299 TSpirvTypeParameters* TParseContext::makeSpirvTypeParameters(const TSourceLoc& /* loc */,
300 const TPublicType& type)
301 {
302 TSpirvTypeParameters* spirvTypeParams = new TSpirvTypeParameters;
303 spirvTypeParams->push_back(TSpirvTypeParameter(new TType(type)));
304 return spirvTypeParams;
305 }
306
mergeSpirvTypeParameters(TSpirvTypeParameters * spirvTypeParams1,TSpirvTypeParameters * spirvTypeParams2)307 TSpirvTypeParameters* TParseContext::mergeSpirvTypeParameters(TSpirvTypeParameters* spirvTypeParams1, TSpirvTypeParameters* spirvTypeParams2)
308 {
309 // Merge SPIR-V type parameters of the second one to the first one
310 for (const auto& spirvTypeParam : *spirvTypeParams2)
311 spirvTypeParams1->push_back(spirvTypeParam);
312 return spirvTypeParams1;
313 }
314
315 //
316 // Handle SPIR-V instruction qualifiers
317 //
makeSpirvInstruction(const TSourceLoc & loc,const TString & name,const TString & value)318 TSpirvInstruction* TParseContext::makeSpirvInstruction(const TSourceLoc& loc, const TString& name, const TString& value)
319 {
320 TSpirvInstruction* spirvInst = new TSpirvInstruction;
321 if (name == "set")
322 spirvInst->set = value;
323 else
324 error(loc, "unknown SPIR-V instruction qualifier", name.c_str(), "");
325
326 return spirvInst;
327 }
328
makeSpirvInstruction(const TSourceLoc & loc,const TString & name,int value)329 TSpirvInstruction* TParseContext::makeSpirvInstruction(const TSourceLoc& loc, const TString& name, int value)
330 {
331 TSpirvInstruction* spirvInstuction = new TSpirvInstruction;
332 if (name == "id")
333 spirvInstuction->id = value;
334 else
335 error(loc, "unknown SPIR-V instruction qualifier", name.c_str(), "");
336
337 return spirvInstuction;
338 }
339
mergeSpirvInstruction(const TSourceLoc & loc,TSpirvInstruction * spirvInst1,TSpirvInstruction * spirvInst2)340 TSpirvInstruction* TParseContext::mergeSpirvInstruction(const TSourceLoc& loc, TSpirvInstruction* spirvInst1, TSpirvInstruction* spirvInst2)
341 {
342 // Merge qualifiers of the second SPIR-V instruction to those of the first one
343 if (!spirvInst2->set.empty()) {
344 if (spirvInst1->set.empty())
345 spirvInst1->set = spirvInst2->set;
346 else
347 error(loc, "too many SPIR-V instruction qualifiers", "spirv_instruction", "(set)");
348 }
349
350 if (spirvInst2->id != -1) {
351 if (spirvInst1->id == -1)
352 spirvInst1->id = spirvInst2->id;
353 else
354 error(loc, "too many SPIR-V instruction qualifiers", "spirv_instruction", "(id)");
355 }
356
357 return spirvInst1;
358 }
359
360 } // end namespace glslang
361