Home | History | Annotate | Download | only in MachineIndependent
      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