Removed the redundant functionalities in the assignee checking traverser

This commit is contained in:
qining 2016-05-05 22:34:52 -04:00
parent 1a0d93f416
commit 015150e4b3

View File

@ -211,6 +211,14 @@ ObjectAccessChain subAccessChainFromSecondElement(const ObjectAccessChain& chain
return pos_delimiter == std::string::npos ? "" : chain.substr(pos_delimiter + 1);
}
// A helper function to get the accesschain after removing a given prefix.
ObjectAccessChain getSubAccessChainAfterPrefix(const ObjectAccessChain &chain, const ObjectAccessChain &prefix)
{
size_t pos = chain.find(prefix);
if (pos != 0) return chain;
return chain.substr(prefix.length() + sizeof(StructAccessChainDelimiter));
}
//
// A traverser which traverses the whole AST and populates:
// 1) A mapping from symbol nodes' IDs to their defining operation nodes.
@ -466,8 +474,9 @@ class TNoContractionAssigneeCheckingTraverser : public glslang::TIntermTraverser
};
public:
TNoContractionAssigneeCheckingTraverser()
: TIntermTraverser(true, false, false), accesschain_to_precise_object_(), decision_(Mixed) {}
TNoContractionAssigneeCheckingTraverser(const AccessChainMapping &accesschain_mapping)
: TIntermTraverser(true, false, false), accesschain_mapping_(accesschain_mapping),
precise_object_(nullptr) {}
// Checks the precise'ness of a given assignment node with a precise object
// represented as accesschain. The precise object shares the same symbol
@ -488,125 +497,127 @@ public:
const ObjectAccessChain &precise_object)
{
assert(isAssignOperation(node->getOp()));
accesschain_to_precise_object_ = precise_object;
decision_ = Mixed;
node->traverse(this);
return make_tuple(decision_ != NotPreicse, accesschain_to_precise_object_);
precise_object_ = &precise_object;
ObjectAccessChain assignee_object;
if (glslang::TIntermBinary* BN = node->getAsBinaryNode()) {
// This is a binary assignment node, we need to check the
// precise'ness of the left node.
if (!accesschain_mapping_.count(BN->getLeft())) {
// If the left node is not an object node, it can not be
// 'precise'.
return make_tuple(false, ObjectAccessChain());
}
// The left node (assignee node) is an object node, traverse the
// node to let the 'precise' of nesting objects being transfered to
// nested objects.
BN->getLeft()->traverse(this);
// After traversing the left node, if the left node is 'precise',
// we can conclude this assignment should propagate 'precise'.
if (isPreciseObjectNode(BN->getLeft())) {
return make_tuple(true, ObjectAccessChain());
}
// If the precise'ness of the left node (assignee node) can not
// be determined by now, we need to compare the accesschain string
// of the assignee object with the given precise object.
assignee_object = accesschain_mapping_.at(BN->getLeft());
} else if (glslang::TIntermUnary* UN = node->getAsUnaryNode()) {
// This is a unary assignment node, we need to check the
// precise'ness of the operand node. For unary assignment node, the
// operand node should always be an object node.
if (!accesschain_mapping_.count(UN->getOperand())) {
// If the operand node is not an object node, it can not be
// 'precise'.
return make_tuple(false, ObjectAccessChain());
}
// Traverse the operand node to let the 'precise' being propagated
// from lower nodes to upper nodes.
UN->getOperand()->traverse(this);
// After traversing the operand node, if the operand node is
// 'precise', this assignment should propagate 'precise'.
if (isPreciseObjectNode(UN->getOperand())) {
return make_tuple(true, ObjectAccessChain());
}
// If the precise'ness of the operand node (assignee node) can not
// be determined by now, we need to compare the accesschain string
// of the assignee object with the given precise object.
assignee_object = accesschain_mapping_.at(UN->getOperand());
} else {
// Not a binary or unary node, should not happen.
assert(false);
}
// Compare the accesschain string of the assignee node with the given
// precise object to determine if this assignment should propagate
// 'precise'.
if (assignee_object.find(precise_object) == 0) {
// The accesschain string of the given precise object is a prefix
// of assignee's accesschain string. The assignee should be
// 'precise'.
return make_tuple(true, ObjectAccessChain());
} else if (precise_object.find(assignee_object) == 0) {
// The assignee's accesschain string is a prefix of the given
// precise object, the assignee object contains 'precise' object,
// and we need to pass the remained accesschain to the object nodes
// in the right.
return make_tuple(true, getSubAccessChainAfterPrefix(precise_object, assignee_object));
} else {
// The accesschain strings do not match, the assignee object can
// not be labelled as 'precise' according to the given precise
// object.
return make_tuple(false, ObjectAccessChain());
}
}
protected:
bool visitBinary(glslang::TVisit, glslang::TIntermBinary *node) override;
bool visitUnary(glslang::TVisit, glslang::TIntermUnary *node) override;
void visitSymbol(glslang::TIntermSymbol *node) override;
// The accesschain toward the given precise object. It will be iniailized
// with the accesschain of a given precise object, then trimmed along the
// traversal of the assignee subtree. The remained accesschain at the end
// of traversal shows the path from the assignee node to its nested
// 'precise' object. If the assignee node is 'precise' object object, this
// should be empty.
ObjectAccessChain accesschain_to_precise_object_;
// A state to tell the precise'ness of the assignee node according to the
// accesschain of the given precise object:
//
// 'Mixed': contains both 'precise' and 'non-precise' object
// (accesschain_to_precise_object_ is not empty),
//
// 'Precise': is precise object (accesschain_to_precise_object is empty),
//
// 'NotPrecise': is not precise object (mismatch in the struct dereference
// indices).
DecisionStatus decision_;
// A map from object nodes to their accesschain string (used as object ID).
const AccessChainMapping &accesschain_mapping_;
// A given precise object, represented in it accesschain string. This
// precise object is used to be compared with the assignee node to tell if
// the assignee node is 'precise', contains 'precise' object or not
// 'precise'.
const ObjectAccessChain *precise_object_;
};
// Visit a binary node. As this traverser's job is to check the precise'ness of
// the assignee node in an assignment operation, it only needs to traverse the
// object nodes along the left branches. For struct type object nodes, it needs
// to obtain the struct dereference index from the right node to build the
// accesschain for this node.
// Visit 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)
{
// Traverses the left so that we transfer the 'precise' from nesting object
// to its nested object.
node->getLeft()->traverse(this);
// For dereference operation nodes, we may need to check if the accesschain
// of the given precise object matches with the struct dereference indices
// of the assignee subtree.
if (isDereferenceOperation(node->getOp())) {
// If this binary node is an object node, we should have it in the
// accesschain_mapping_.
if (accesschain_mapping_.count(node)) {
// A binary object node must be a dereference node.
assert(isDereferenceOperation(node->getOp()));
// If the left node is 'precise', this node should also be precise,
// otherwise, compare with the given precise_object_. If the
// accesschain of this node matches with the given precise_object_,
// this node should be marked as 'precise'.
if (isPreciseObjectNode(node->getLeft())) {
// The left node is 'precise', which means the object node in the
// left contains the object represented in this node. If the left node
// is 'precise', this object node should also be 'precise' and no need
// to check the accesschain and struct deference indices anymore.
node->getWritableType().getQualifier().noContraction = true;
decision_ = Precise;
return false;
}
if (node->getOp() == glslang::EOpIndexDirectStruct && decision_ == Mixed) {
std::string struct_index =
std::to_string(getStructIndexFromConstantUnion(node->getRight()));
ObjectAccessChain precise_struct_index = getFrontElement(accesschain_to_precise_object_);
if (precise_struct_index == struct_index) {
// The struct dereference index matches with the record in the
// accesschain to the precise object. Pop the front access
// chain index from the precise object access chain.
accesschain_to_precise_object_ =
subAccessChainFromSecondElement(accesschain_to_precise_object_);
// If the given access chain to precise object is empty now,
// it means we've found the corresponding precise object in
// the assignee subtree.
if (accesschain_to_precise_object_.empty()) {
node->getWritableType().getQualifier().noContraction = true;
decision_ = Precise;
}
} else {
// The access chain index does not match with the record in the precise object id.
// This object should not be labelled as 'precise' here.
decision_ = NotPreicse;
}
} else if (accesschain_mapping_.at(node) == *precise_object_){
node->getWritableType().getQualifier().noContraction = true;
}
}
return false;
}
// Visits an unary node, traverses its operand. If the node is an assignment node,
// determines the precise'ness of the assignee directly based on the assignee node's
// precise'ness.
bool TNoContractionAssigneeCheckingTraverser::visitUnary(glslang::TVisit,
glslang::TIntermUnary *node)
{
node->getOperand()->traverse(this);
if (isAssignOperation(node->getOp())) {
if (isPreciseObjectNode(node->getOperand())) {
decision_ = Precise;
// As the assignee node is 'precise', all (if any) the
// member objects the that node should also be 'precise'. This means
// we won't need to propagate extra access chain info.
accesschain_to_precise_object_.clear();
} else {
decision_ = NotPreicse;
}
}
return false;
}
// Visits a symbol node. The symbol ID of this node should match with the symbol ID, which is
// the front element, in the accesschain of the given 'precise' object.
// Visit a symbol node, if the symbol node ID (its accesschain string) matches
// with the given precise object, this node should be 'precise'.
void TNoContractionAssigneeCheckingTraverser::visitSymbol(glslang::TIntermSymbol *node)
{
ObjectAccessChain symbol_id = generateSymbolLabel(node);
// The root symbol of the given access chain should be the same with the one represented by the symbol node here.
assert(symbol_id == getFrontElement(accesschain_to_precise_object_));
// Pop the symbol node part from the front end of the accesschain string.
accesschain_to_precise_object_ =
subAccessChainFromSecondElement(accesschain_to_precise_object_);
if (accesschain_to_precise_object_.empty()) {
// A symbol node should always be an object node, and should have been added
// to the map from object nodes to their accesschain strings.
assert(accesschain_mapping_.count(node));
if (accesschain_mapping_.at(node) == *precise_object_) {
node->getWritableType().getQualifier().noContraction = true;
decision_ = Precise;
}
// If this symbol node is 'precise', all its members should be 'precise' so the assignee of the processing
// assignment operations is 'precise'.
if (isPreciseObjectNode(node)) {
decision_ = Precise;
}
}
@ -833,7 +844,7 @@ void PropagateNoContraction(const glslang::TIntermediate &intermediate)
// expression to mark arithmetic operations as 'noContration' and update
// 'precise' accesschain worklist with new found object nodes.
// Repeat above steps until the worklist is empty.
TNoContractionAssigneeCheckingTraverser checker;
TNoContractionAssigneeCheckingTraverser checker(accesschain_mapping);
TNoContractionPropagator propagator(&precise_object_accesschains,
accesschain_mapping);