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 44 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) 57 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? 74 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. 80 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 96 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 115 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 125 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. 140 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 // 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 // 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 // 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