2 // Copyright (C) 2017 LunarG, Inc.
3 // Copyright (C) 2018 Google, Inc.
5 // All rights reserved.
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
11 // Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
14 // Redistributions in binary form must reproduce the above
15 // copyright notice, this list of conditions and the following
16 // disclaimer in the documentation and/or other materials provided
17 // with the distribution.
19 // Neither the name of Google, Inc., nor the names of its
20 // contributors may be used to endorse or promote products derived
21 // from this software without specific prior written permission.
23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 // POSSIBILITY OF SUCH DAMAGE.
39 #include "attribute.h"
40 #include "../Include/intermediate.h"
41 #include "ParseHelper.h"
45 // extract integers out of attribute arguments stored in attribute aggregate
46 bool TAttributeArgs::getInt(int& value, int argNum) const
48 const TConstUnion* intConst = getConstUnion(EbtInt, argNum);
50 if (intConst == nullptr)
53 value = intConst->getIConst();
58 // extract strings out of attribute arguments stored in attribute aggregate.
59 // convert to lower case if converToLower is true (for case-insensitive compare convenience)
60 bool TAttributeArgs::getString(TString& value, int argNum, bool convertToLower) const
62 const TConstUnion* stringConst = getConstUnion(EbtString, argNum);
64 if (stringConst == nullptr)
67 value = *stringConst->getSConst();
71 std::transform(value.begin(), value.end(), value.begin(), ::tolower);
76 // How many arguments were supplied?
77 int TAttributeArgs::size() const
79 return args == nullptr ? 0 : (int)args->getSequence().size();
82 // Helper to get attribute const union. Returns nullptr on failure.
83 const TConstUnion* TAttributeArgs::getConstUnion(TBasicType basicType, int argNum) const
88 if (argNum >= (int)args->getSequence().size())
91 if (args->getSequence()[argNum]->getAsConstantUnion() == nullptr)
94 const TConstUnion* constVal = &args->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
95 if (constVal == nullptr || constVal->getType() != basicType)
101 // Implementation of TParseContext parts of attributes
102 TAttributeType TParseContext::attributeFromName(const TString& name) const
104 if (name == "branch" || name == "dont_flatten")
106 else if (name == "flatten")
108 else if (name == "unroll")
110 else if (name == "loop" || name == "dont_unroll")
112 else if (name == "dependency_infinite")
113 return EatDependencyInfinite;
114 else if (name == "dependency_length")
115 return EatDependencyLength;
116 else if (name == "min_iterations")
117 return EatMinIterations;
118 else if (name == "max_iterations")
119 return EatMaxIterations;
120 else if (name == "iteration_multiple")
121 return EatIterationMultiple;
122 else if (name == "peel_count")
124 else if (name == "partial_count")
125 return EatPartialCount;
126 else if (name == "subgroup_uniform_control_flow")
127 return EatSubgroupUniformControlFlow;
132 // Make an initial leaf for the grammar from a no-argument attribute
133 TAttributes* TParseContext::makeAttributes(const TString& identifier) const
135 TAttributes *attributes = nullptr;
136 attributes = NewPoolObject(attributes);
137 TAttributeArgs args = { attributeFromName(identifier), nullptr };
138 attributes->push_back(args);
142 // Make an initial leaf for the grammar from a one-argument attribute
143 TAttributes* TParseContext::makeAttributes(const TString& identifier, TIntermNode* node) const
145 TAttributes *attributes = nullptr;
146 attributes = NewPoolObject(attributes);
148 // for now, node is always a simple single expression, but other code expects
149 // a list, so make it so
150 TIntermAggregate* agg = intermediate.makeAggregate(node);
151 TAttributeArgs args = { attributeFromName(identifier), agg };
152 attributes->push_back(args);
156 // Merge two sets of attributes into a single set.
157 // The second argument is destructively consumed.
158 TAttributes* TParseContext::mergeAttributes(TAttributes* attr1, TAttributes* attr2) const
160 attr1->splice(attr1->end(), *attr2);
165 // Selection attributes
167 void TParseContext::handleSelectionAttributes(const TAttributes& attributes, TIntermNode* node)
169 TIntermSelection* selection = node->getAsSelectionNode();
170 if (selection == nullptr)
173 for (auto it = attributes.begin(); it != attributes.end(); ++it) {
174 if (it->size() > 0) {
175 warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
181 selection->setFlatten();
184 selection->setDontFlatten();
187 warn(node->getLoc(), "attribute does not apply to a selection", "", "");
196 void TParseContext::handleSwitchAttributes(const TAttributes& attributes, TIntermNode* node)
198 TIntermSwitch* selection = node->getAsSwitchNode();
199 if (selection == nullptr)
202 for (auto it = attributes.begin(); it != attributes.end(); ++it) {
203 if (it->size() > 0) {
204 warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
210 selection->setFlatten();
213 selection->setDontFlatten();
216 warn(node->getLoc(), "attribute does not apply to a switch", "", "");
225 void TParseContext::handleLoopAttributes(const TAttributes& attributes, TIntermNode* node)
227 TIntermLoop* loop = node->getAsLoopNode();
228 if (loop == nullptr) {
229 // the actual loop might be part of a sequence
230 TIntermAggregate* agg = node->getAsAggregate();
233 for (auto it = agg->getSequence().begin(); it != agg->getSequence().end(); ++it) {
234 loop = (*it)->getAsLoopNode();
242 for (auto it = attributes.begin(); it != attributes.end(); ++it) {
244 const auto noArgument = [&](const char* feature) {
245 if (it->size() > 0) {
246 warn(node->getLoc(), "expected no arguments", feature, "");
252 const auto positiveSignedArgument = [&](const char* feature, int& value) {
253 if (it->size() == 1 && it->getInt(value)) {
255 error(node->getLoc(), "must be positive", feature, "");
259 warn(node->getLoc(), "expected a single integer argument", feature, "");
265 const auto unsignedArgument = [&](const char* feature, unsigned int& uiValue) {
267 if (!(it->size() == 1 && it->getInt(value))) {
268 warn(node->getLoc(), "expected a single integer argument", feature, "");
271 uiValue = (unsigned int)value;
275 const auto positiveUnsignedArgument = [&](const char* feature, unsigned int& uiValue) {
277 if (it->size() == 1 && it->getInt(value)) {
279 error(node->getLoc(), "must be greater than or equal to 1", feature, "");
283 warn(node->getLoc(), "expected a single integer argument", feature, "");
286 uiValue = (unsigned int)value;
290 const auto spirv14 = [&](const char* feature) {
291 if (spvVersion.spv > 0 && spvVersion.spv < EShTargetSpv_1_4)
292 warn(node->getLoc(), "attribute requires a SPIR-V 1.4 target-env", feature, "");
296 unsigned uiValue = 0;
299 if (noArgument("unroll"))
303 if (noArgument("dont_unroll"))
304 loop->setDontUnroll();
306 case EatDependencyInfinite:
307 if (noArgument("dependency_infinite"))
308 loop->setLoopDependency(TIntermLoop::dependencyInfinite);
310 case EatDependencyLength:
311 if (positiveSignedArgument("dependency_length", value))
312 loop->setLoopDependency(value);
314 case EatMinIterations:
315 spirv14("min_iterations");
316 if (unsignedArgument("min_iterations", uiValue))
317 loop->setMinIterations(uiValue);
319 case EatMaxIterations:
320 spirv14("max_iterations");
321 if (unsignedArgument("max_iterations", uiValue))
322 loop->setMaxIterations(uiValue);
324 case EatIterationMultiple:
325 spirv14("iteration_multiple");
326 if (positiveUnsignedArgument("iteration_multiple", uiValue))
327 loop->setIterationMultiple(uiValue);
330 spirv14("peel_count");
331 if (unsignedArgument("peel_count", uiValue))
332 loop->setPeelCount(uiValue);
334 case EatPartialCount:
335 spirv14("partial_count");
336 if (unsignedArgument("partial_count", uiValue))
337 loop->setPartialCount(uiValue);
340 warn(node->getLoc(), "attribute does not apply to a loop", "", "");
348 // Function attributes
350 void TParseContext::handleFunctionAttributes(const TSourceLoc& loc, const TAttributes& attributes)
352 for (auto it = attributes.begin(); it != attributes.end(); ++it) {
353 if (it->size() > 0) {
354 warn(loc, "attribute with arguments not recognized, skipping", "", "");
359 case EatSubgroupUniformControlFlow:
360 intermediate.setSubgroupUniformControlFlow();
363 warn(loc, "attribute does not apply to a function", "", "");
369 } // end namespace glslang
371 #endif // GLSLANG_WEB