• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2017 LunarG, Inc.
3 // Copyright (C) 2018 Google, Inc.
4 //
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 //    Redistributions of source code must retain the above copyright
12 //    notice, this list of conditions and the following disclaimer.
13 //
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.
18 //
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.
22 //
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.
35 //
36 
37 #include "attribute.h"
38 #include "../Include/intermediate.h"
39 #include "ParseHelper.h"
40 
41 namespace glslang {
42 
43 // extract integers out of attribute arguments stored in attribute aggregate
getInt(int & value,int argNum) const44 bool TAttributeArgs::getInt(int& value, int argNum) const
45 {
46     const TConstUnion* intConst = getConstUnion(EbtInt, argNum);
47 
48     if (intConst == nullptr)
49         return false;
50 
51     value = intConst->getIConst();
52     return true;
53 }
54 
55 // extract strings out of attribute arguments stored in attribute aggregate.
56 // convert to lower case if converToLower is true (for case-insensitive compare convenience)
getString(TString & value,int argNum,bool convertToLower) const57 bool TAttributeArgs::getString(TString& value, int argNum, bool convertToLower) const
58 {
59     const TConstUnion* stringConst = getConstUnion(EbtString, argNum);
60 
61     if (stringConst == nullptr)
62         return false;
63 
64     value = *stringConst->getSConst();
65 
66     // Convenience.
67     if (convertToLower)
68         std::transform(value.begin(), value.end(), value.begin(), ::tolower);
69 
70     return true;
71 }
72 
73 // How many arguments were supplied?
size() const74 int TAttributeArgs::size() const
75 {
76     return args == nullptr ? 0 : (int)args->getSequence().size();
77 }
78 
79 // Helper to get attribute const union.  Returns nullptr on failure.
getConstUnion(TBasicType basicType,int argNum) const80 const TConstUnion* TAttributeArgs::getConstUnion(TBasicType basicType, int argNum) const
81 {
82     if (args == nullptr)
83         return nullptr;
84 
85     if (argNum >= (int)args->getSequence().size())
86         return nullptr;
87 
88     const TConstUnion* constVal = &args->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
89     if (constVal == nullptr || constVal->getType() != basicType)
90         return nullptr;
91 
92     return constVal;
93 }
94 
95 // Implementation of TParseContext parts of attributes
attributeFromName(const TString & name) const96 TAttributeType TParseContext::attributeFromName(const TString& name) const
97 {
98     if (name == "branch" || name == "dont_flatten")
99         return EatBranch;
100     else if (name == "flatten")
101         return EatFlatten;
102     else if (name == "unroll")
103         return EatUnroll;
104     else if (name == "loop" || name == "dont_unroll")
105         return EatLoop;
106     else if (name == "dependency_infinite")
107         return EatDependencyInfinite;
108     else if (name == "dependency_length")
109         return EatDependencyLength;
110     else
111         return EatNone;
112 }
113 
114 // Make an initial leaf for the grammar from a no-argument attribute
makeAttributes(const TString & identifier) const115 TAttributes* TParseContext::makeAttributes(const TString& identifier) const
116 {
117     TAttributes *attributes = nullptr;
118     attributes = NewPoolObject(attributes);
119     TAttributeArgs args = { attributeFromName(identifier), nullptr };
120     attributes->push_back(args);
121     return attributes;
122 }
123 
124 // Make an initial leaf for the grammar from a one-argument attribute
makeAttributes(const TString & identifier,TIntermNode * node) const125 TAttributes* TParseContext::makeAttributes(const TString& identifier, TIntermNode* node) const
126 {
127     TAttributes *attributes = nullptr;
128     attributes = NewPoolObject(attributes);
129 
130     // for now, node is always a simple single expression, but other code expects
131     // a list, so make it so
132     TIntermAggregate* agg = intermediate.makeAggregate(node);
133     TAttributeArgs args = { attributeFromName(identifier), agg };
134     attributes->push_back(args);
135     return attributes;
136 }
137 
138 // Merge two sets of attributes into a single set.
139 // The second argument is destructively consumed.
mergeAttributes(TAttributes * attr1,TAttributes * attr2) const140 TAttributes* TParseContext::mergeAttributes(TAttributes* attr1, TAttributes* attr2) const
141 {
142     attr1->splice(attr1->end(), *attr2);
143     return attr1;
144 }
145 
146 //
147 // Selection attributes
148 //
handleSelectionAttributes(const TAttributes & attributes,TIntermNode * node)149 void TParseContext::handleSelectionAttributes(const TAttributes& attributes, TIntermNode* node)
150 {
151     TIntermSelection* selection = node->getAsSelectionNode();
152     if (selection == nullptr)
153         return;
154 
155     for (auto it = attributes.begin(); it != attributes.end(); ++it) {
156         if (it->size() > 0) {
157             warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
158             continue;
159         }
160 
161         switch (it->name) {
162         case EatFlatten:
163             selection->setFlatten();
164             break;
165         case EatBranch:
166             selection->setDontFlatten();
167             break;
168         default:
169             warn(node->getLoc(), "attribute does not apply to a selection", "", "");
170             break;
171         }
172     }
173 }
174 
175 //
176 // Switch attributes
177 //
handleSwitchAttributes(const TAttributes & attributes,TIntermNode * node)178 void TParseContext::handleSwitchAttributes(const TAttributes& attributes, TIntermNode* node)
179 {
180     TIntermSwitch* selection = node->getAsSwitchNode();
181     if (selection == nullptr)
182         return;
183 
184     for (auto it = attributes.begin(); it != attributes.end(); ++it) {
185         if (it->size() > 0) {
186             warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
187             continue;
188         }
189 
190         switch (it->name) {
191         case EatFlatten:
192             selection->setFlatten();
193             break;
194         case EatBranch:
195             selection->setDontFlatten();
196             break;
197         default:
198             warn(node->getLoc(), "attribute does not apply to a switch", "", "");
199             break;
200         }
201     }
202 }
203 
204 //
205 // Loop attributes
206 //
handleLoopAttributes(const TAttributes & attributes,TIntermNode * node)207 void TParseContext::handleLoopAttributes(const TAttributes& attributes, TIntermNode* node)
208 {
209     TIntermLoop* loop = node->getAsLoopNode();
210     if (loop == nullptr) {
211         // the actual loop might be part of a sequence
212         TIntermAggregate* agg = node->getAsAggregate();
213         if (agg == nullptr)
214             return;
215         for (auto it = agg->getSequence().begin(); it != agg->getSequence().end(); ++it) {
216             loop = (*it)->getAsLoopNode();
217             if (loop != nullptr)
218                 break;
219         }
220         if (loop == nullptr)
221             return;
222     }
223 
224     for (auto it = attributes.begin(); it != attributes.end(); ++it) {
225         if (it->name != EatDependencyLength && it->size() > 0) {
226             warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
227             continue;
228         }
229 
230         int value;
231         switch (it->name) {
232         case EatUnroll:
233             loop->setUnroll();
234             break;
235         case EatLoop:
236             loop->setDontUnroll();
237             break;
238         case EatDependencyInfinite:
239             loop->setLoopDependency(TIntermLoop::dependencyInfinite);
240             break;
241         case EatDependencyLength:
242             if (it->size() == 1 && it->getInt(value)) {
243                 if (value <= 0)
244                     error(node->getLoc(), "must be positive", "dependency_length", "");
245                 loop->setLoopDependency(value);
246             } else
247                 warn(node->getLoc(), "expected a single integer argument", "dependency_length", "");
248             break;
249         default:
250             warn(node->getLoc(), "attribute does not apply to a loop", "", "");
251             break;
252         }
253     }
254 }
255 
256 
257 } // end namespace glslang
258