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