• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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