// // Copyright (C) 2015-2016 Google, Inc. // // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // // Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // // Visit the nodes in the glslang intermediate tree representation to // propagate the 'noContraction' qualifier. // #include "propagateNoContraction.h" #include <cstdlib> #include <string> #include <tuple> #include <unordered_map> #include <unordered_set> #include "localintermediate.h" namespace { // Use a string to hold the access chain information, as in most cases the // access chain is short and may contain only one element, which is the symbol // ID. // Example: struct {float a; float b;} s; // Object s.a will be represented with: <symbol ID of s>/0 // Object s.b will be represented with: <symbol ID of s>/1 // Object s will be represented with: <symbol ID of s> // For members of vector, matrix and arrays, they will be represented with the // same symbol ID of their container symbol objects. This is because their // preciseness is always the same as their container symbol objects. ObjectAccessChain; // The delimiter used in the ObjectAccessChain string to separate symbol ID and // different level of struct indices. const char ObjectAccesschainDelimiter = …; // Mapping from Symbol IDs of symbol nodes, to their defining operation // nodes. NodeMapping; // Mapping from object nodes to their access chain info string. AccessChainMapping; // Set of object IDs. ObjectAccesschainSet; // Set of return branch nodes. ReturnBranchNodeSet; // A helper function to tell whether a node is 'noContraction'. Returns true if // the node has 'noContraction' qualifier, otherwise false. bool isPreciseObjectNode(glslang::TIntermTyped* node) { … } // Returns true if the opcode is a dereferencing one. bool isDereferenceOperation(glslang::TOperator op) { … } // Returns true if the opcode leads to an assignment operation. bool isAssignOperation(glslang::TOperator op) { … } // A helper function to get the unsigned int from a given constant union node. // Note the node should only hold a uint scalar. unsigned getStructIndexFromConstantUnion(glslang::TIntermTyped* node) { … } // A helper function to generate symbol_label. ObjectAccessChain generateSymbolLabel(glslang::TIntermSymbol* node) { … } // Returns true if the operation is an arithmetic operation and valid for // the 'NoContraction' decoration. bool isArithmeticOperation(glslang::TOperator op) { … } // A helper class to help manage the populating_initial_no_contraction_ flag. template <typename T> class StateSettingGuard { … }; // A helper function to get the front element from a given ObjectAccessChain ObjectAccessChain getFrontElement(const ObjectAccessChain& chain) { … } // A helper function to get the access chain starting from the second element. ObjectAccessChain subAccessChainFromSecondElement(const ObjectAccessChain& chain) { … } // A helper function to get the access chain after removing a given prefix. ObjectAccessChain getSubAccessChainAfterPrefix(const ObjectAccessChain& chain, const ObjectAccessChain& prefix) { … } // // A traverser which traverses the whole AST and populates: // 1) A mapping from symbol nodes' IDs to their defining operation nodes. // 2) A set of access chains of the initial precise object nodes. // class TSymbolDefinitionCollectingTraverser : public glslang::TIntermTraverser { … }; TSymbolDefinitionCollectingTraverser::TSymbolDefinitionCollectingTraverser( NodeMapping* symbol_definition_mapping, AccessChainMapping* accesschain_mapping, ObjectAccesschainSet* precise_objects, std::unordered_set<glslang::TIntermBranch*>* precise_return_nodes) : … { … } // Visits a symbol node, set the current_object_ to the // current node symbol ID, and record a mapping from this node to the current // current_object_, which is the just obtained symbol // ID. void TSymbolDefinitionCollectingTraverser::visitSymbol(glslang::TIntermSymbol* node) { … } // Visits an aggregate node, traverses all of its children. bool TSymbolDefinitionCollectingTraverser::visitAggregate(glslang::TVisit, glslang::TIntermAggregate* node) { … } bool TSymbolDefinitionCollectingTraverser::visitBranch(glslang::TVisit, glslang::TIntermBranch* node) { … } // Visits a unary node. This might be an implicit assignment like i++, i--. etc. bool TSymbolDefinitionCollectingTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node) { … } // Visits a binary node and updates the mapping from symbol IDs to the definition // nodes. Also collects the access chains for the initial precise objects. bool TSymbolDefinitionCollectingTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node) { … } // Traverses the AST and returns a tuple of four members: // 1) a mapping from symbol IDs to the definition nodes (aka. assignment nodes) of these symbols. // 2) a mapping from object nodes in the AST to the access chains of these objects. // 3) a set of access chains of precise objects. // 4) a set of return nodes with precise expressions. std::tuple<NodeMapping, AccessChainMapping, ObjectAccesschainSet, ReturnBranchNodeSet> getSymbolToDefinitionMappingAndPreciseSymbolIDs(const glslang::TIntermediate& intermediate) { … } // // A traverser that determine whether the left node (or operand node for unary // node) of an assignment node is 'precise', containing 'precise' or not, // according to the access chain a given precise object which share the same // symbol as the left node. // // Post-orderly traverses the left node subtree of an binary assignment node and: // // 1) Propagates the 'precise' from the left object nodes to this object node. // // 2) Builds object access chain along the traversal, and also compares with // the access chain of the given 'precise' object along with the traversal to // tell if the node to be defined is 'precise' or not. // class TNoContractionAssigneeCheckingTraverser : public glslang::TIntermTraverser { … }; // Visits a binary node. If the node is an object node, it must be a dereference // node. In such cases, if the left node is 'precise', this node should also be // 'precise'. bool TNoContractionAssigneeCheckingTraverser::visitBinary(glslang::TVisit, glslang::TIntermBinary* node) { … } // Visits a symbol node, if the symbol node ID (its access chain string) matches // with the given precise object, this node should be 'precise'. void TNoContractionAssigneeCheckingTraverser::visitSymbol(glslang::TIntermSymbol* node) { … } // // A traverser that only traverses the right side of binary assignment nodes // and the operand node of unary assignment nodes. // // 1) Marks arithmetic operations as 'NoContraction'. // // 2) Find the object which should be marked as 'precise' in the right and // update the 'precise' object work list. // class TNoContractionPropagator : public glslang::TIntermTraverser { … }; } namespace glslang { void PropagateNoContraction(const glslang::TIntermediate& intermediate) { … } }