Commit 0863f0df by Nicolas Capens

Handle constant expressions that have not been constant folded.

Change-Id: I7dd1e6db9a4cee64cb10fb27373d77038b2af63e Reviewed-on: https://swiftshader-review.googlesource.com/5078Tested-by: 's avatarNicolas Capens <capn@google.com> Reviewed-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <capn@google.com>
parent 3a7b29ce
......@@ -1624,7 +1624,6 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNod
return tempNode;
default:
infoSink.info.message(EPrefixInternalError, "Invalid operator for constant folding", getLine());
return 0;
}
tempNode = new TIntermConstantUnion(tempConstArray, returnType);
......
......@@ -2132,7 +2132,7 @@ namespace glsl
parameter.type = registerType(arg);
parameter.bufferIndex = argumentInfo.bufferIndex;
if(arg->getQualifier() == EvqConstExpr)
if(arg->getAsConstantUnion() && arg->getAsConstantUnion()->getUnionArrayPointer())
{
int component = componentCount(type, argumentInfo.clampedIndex);
ConstantUnion *constants = arg->getAsConstantUnion()->getUnionArrayPointer();
......@@ -2459,6 +2459,11 @@ namespace glsl
outputQualifier = qualifier;
}
if(qualifier == EvqConstExpr && (!operand->getAsConstantUnion() || !operand->getAsConstantUnion()->getUnionArrayPointer()))
{
return sw::Shader::PARAMETER_TEMP;
}
switch(qualifier)
{
case EvqTemporary: return sw::Shader::PARAMETER_TEMP;
......@@ -2510,7 +2515,7 @@ namespace glsl
{
case EvqTemporary: return temporaryRegister(operand);
case EvqGlobal: return temporaryRegister(operand);
case EvqConstExpr: UNREACHABLE(EvqConstExpr);
case EvqConstExpr: return temporaryRegister(operand); // Unevaluated constant expression
case EvqAttribute: return attributeRegister(operand);
case EvqVaryingIn: return varyingRegister(operand);
case EvqVaryingOut: return varyingRegister(operand);
......
......@@ -228,7 +228,7 @@ void TParseContext::unaryOpError(const TSourceLoc &line, const char* op, TString
void TParseContext::binaryOpError(const TSourceLoc &line, const char* op, TString left, TString right)
{
std::stringstream extraInfoStream;
extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '" << left
extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '" << left
<< "' and a right operand of type '" << right << "' (or there is no acceptable conversion)";
std::string extraInfo = extraInfoStream.str();
error(line, " wrong operand types ", op, extraInfo.c_str());
......@@ -1191,11 +1191,12 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id
ASSERT(intermNode != nullptr);
TType type = TType(pType);
TVariable *variable = nullptr;
if(type.isArray() && (type.getArraySize() == 0))
{
type.setArraySize(initializer->getArraySize());
}
TVariable *variable = nullptr;
if(!declareVariable(line, identifier, type, &variable))
{
return true;
......@@ -1218,7 +1219,7 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id
//
// identifier must be of type constant, a global, or a temporary
//
TQualifier qualifier = variable->getType().getQualifier();
TQualifier qualifier = type.getQualifier();
if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConstExpr)) {
error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString());
return true;
......@@ -1228,7 +1229,7 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id
//
if (qualifier == EvqConstExpr) {
if (qualifier != initializer->getType().getQualifier()) {
if (qualifier != initializer->getQualifier()) {
std::stringstream extraInfoStream;
extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
std::string extraInfo = extraInfoStream.str();
......@@ -1236,12 +1237,14 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id
variable->getType().setQualifier(EvqTemporary);
return true;
}
if (type != initializer->getType()) {
error(line, " non-matching types for const initializer ",
variable->getType().getQualifierString());
variable->getType().setQualifier(EvqTemporary);
return true;
}
if (initializer->getAsConstantUnion()) {
variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
} else if (initializer->getAsSymbolNode()) {
......@@ -1250,17 +1253,10 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id
ConstantUnion* constArray = tVar->getConstPointer();
variable->shareConstPointer(constArray);
} else {
std::stringstream extraInfoStream;
extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
std::string extraInfo = extraInfoStream.str();
error(line, " cannot assign to", "=", extraInfo.c_str());
variable->getType().setQualifier(EvqTemporary);
return true;
}
}
if (qualifier != EvqConstExpr) {
if (!variable->isConstant()) {
TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line);
*intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
if(*intermNode == nullptr) {
......@@ -1273,25 +1269,6 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id
return false;
}
bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode)
{
ASSERT(aggrNode != NULL);
if (!aggrNode->isConstructor())
return false;
bool allConstant = true;
// check if all the child nodes are constants so that they can be inserted into
// the parent node
TIntermSequence &sequence = aggrNode->getSequence() ;
for (TIntermSequence::iterator p = sequence.begin(); p != sequence.end(); ++p) {
if (!(*p)->getAsTyped()->getAsConstantUnion())
return false;
}
return allConstant;
}
TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier, bool invariant, TLayoutQualifier layoutQualifier, const TPublicType &typeSpecifier)
{
TPublicType returnType = typeSpecifier;
......@@ -1818,12 +1795,12 @@ TIntermAggregate *TParseContext::addFunctionDefinition(const TFunction &function
aggregate->setName(function.getMangledName().c_str());
aggregate->setType(function.getReturnType());
// store the pragma information for debug and optimize and other vendor specific
// information. This information can be queried from the parse tree
aggregate->setOptimize(pragma().optimize);
// store the pragma information for debug and optimize and other vendor specific
// information. This information can be queried from the parse tree
aggregate->setOptimize(pragma().optimize);
aggregate->setDebug(pragma().debug);
if(functionBody && functionBody->getAsAggregate())
if(functionBody && functionBody->getAsAggregate())
aggregate->setEndLine(functionBody->getAsAggregate()->getEndLine());
symbolTable.pop();
......@@ -2117,8 +2094,8 @@ TIntermTyped* TParseContext::addConstructor(TIntermNode* arguments, const TType*
}
// Turn the argument list itself into a constructor
TIntermTyped *constructor = intermediate.setAggregateOperator(aggregateArguments, op, line);
TIntermTyped *constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type);
TIntermAggregate *constructor = intermediate.setAggregateOperator(aggregateArguments, op, line);
TIntermTyped *constConstructor = foldConstConstructor(constructor, *type);
if(constConstructor)
{
return constConstructor;
......@@ -2129,9 +2106,8 @@ TIntermTyped* TParseContext::addConstructor(TIntermNode* arguments, const TType*
TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type)
{
bool canBeFolded = areAllChildConst(aggrNode);
aggrNode->setType(type);
if (canBeFolded) {
if (aggrNode->isConstantFoldable()) {
bool returnVal = false;
ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()];
if (aggrNode->getSequence().size() == 1) {
......@@ -2153,7 +2129,7 @@ TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, co
// This function returns the tree representation for the vector field(s) being accessed from contant vector.
// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is
// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol
// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of
// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of
// a constant matrix.
//
TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, const TSourceLoc &line)
......@@ -2625,7 +2601,7 @@ TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre
recover();
}
if(baseExpression->getType().getQualifier() == EvqConstExpr)
if(baseExpression->getAsConstantUnion())
{
// constant folding for vector fields
indexedExpression = addConstVectorNode(fields, baseExpression, fieldLocation);
......
......@@ -143,7 +143,6 @@ public:
void handlePragmaDirective(const TSourceLoc &line, const char* name, const char* value);
bool containsSampler(TType& type);
bool areAllChildConst(TIntermAggregate* aggrNode);
const TFunction* findFunction(const TSourceLoc &line, TFunction* pfnCall, bool *builtIn = 0);
bool executeInitializer(const TSourceLoc &line, const TString &identifier, const TPublicType &pType,
TIntermTyped *initializer, TIntermNode **intermNode);
......
......@@ -95,6 +95,7 @@ public:
}
ConstantUnion* getConstPointer() const { return unionArray; }
bool isConstant() const { return unionArray != nullptr; }
void shareConstPointer( ConstantUnion *constArray)
{
......
......@@ -217,8 +217,8 @@ variable_identifier
// don't delete $1.string, it's used by error recovery, and the pool
// pop will reclaim the memory
if (variable->getType().getQualifier() == EvqConstExpr ) {
ConstantUnion* constArray = variable->getConstPointer();
ConstantUnion *constArray = variable->getConstPointer();
if (constArray) {
TType t(variable->getType());
$$ = context->intermediate.addConstantUnion(constArray, t, @1);
} else
......@@ -686,7 +686,7 @@ function_header
TType type($1);
function = new TFunction($2.string, type);
$$ = function;
context->symbolTable.push();
}
;
......@@ -914,7 +914,7 @@ type_qualifier
| interpolation_qualifier {
context->error(@1, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getQualifierString($1.qualifier));
context->recover();
TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
$$.setBasic(EbtVoid, qual, @1);
}
......
......@@ -2365,8 +2365,8 @@ yyreduce:
// don't delete $1.string, it's used by error recovery, and the pool
// pop will reclaim the memory
if (variable->getType().getQualifier() == EvqConstExpr ) {
ConstantUnion* constArray = variable->getConstPointer();
ConstantUnion *constArray = variable->getConstPointer();
if (constArray) {
TType t(variable->getType());
(yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(constArray, t, (yylsp[0]));
} else
......
......@@ -8,7 +8,7 @@
// Definition of the in-memory high-level intermediate representation
// of shaders. This is a tree that parser creates.
//
// Nodes in the tree are defined as a hierarchy of classes derived from
// Nodes in the tree are defined as a hierarchy of classes derived from
// TIntermNode. Each is a node in a tree. There is no preset branching factor;
// each node can have it's own type of list of children.
//
......@@ -26,7 +26,7 @@
enum TOperator {
EOpNull, // if in a node, should only mean a node is still being built
EOpSequence, // denotes a list of statements, or parameters, etc.
EOpFunctionCall,
EOpFunctionCall,
EOpFunction, // For function definition
EOpParameters, // an aggregate listing the parameters to a function
......@@ -306,7 +306,7 @@ public:
TPrecision getPrecision() const { return type.getPrecision(); }
int getNominalSize() const { return type.getNominalSize(); }
int getSecondarySize() const { return type.getSecondarySize(); }
bool isInterfaceBlock() const { return type.isInterfaceBlock(); }
bool isMatrix() const { return type.isMatrix(); }
bool isArray() const { return type.isArray(); }
......@@ -400,14 +400,14 @@ public:
// if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from
// per process globalpoolallocator, then it causes increased memory usage per compile
// it is essential to use "symbol = sym" to assign to symbol
TIntermSymbol(int i, const TString& sym, const TType& t) :
TIntermTyped(t), id(i) { symbol = sym; }
TIntermSymbol(int i, const TString& sym, const TType& t) :
TIntermTyped(t), id(i) { symbol = sym; }
int getId() const { return id; }
const TString& getSymbol() const { return symbol; }
void setId(int newId) { id = newId; }
virtual void traverse(TIntermTraverser*);
virtual TIntermSymbol* getAsSymbolNode() { return this; }
......@@ -418,10 +418,13 @@ protected:
class TIntermConstantUnion : public TIntermTyped {
public:
TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { }
TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer)
{
getTypePointer()->setQualifier(EvqConstExpr);
}
ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; }
int getIConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getIConst() : 0; }
int getUConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getUConst() : 0; }
float getFConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getFConst() : 0.0f; }
......@@ -452,7 +455,7 @@ public:
protected:
TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {}
TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {}
TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {}
TOperator op;
};
......@@ -489,7 +492,7 @@ public:
virtual TIntermUnary* getAsUnaryNode() { return this; }
void setOperand(TIntermTyped* o) { operand = o; }
TIntermTyped* getOperand() { return operand; }
TIntermTyped* getOperand() { return operand; }
bool promote(TInfoSink&);
protected:
......@@ -527,6 +530,19 @@ public:
void setEndLine(const TSourceLoc& line) { endLine = line; }
const TSourceLoc& getEndLine() const { return endLine; }
bool isConstantFoldable()
{
for(TIntermNode *node : sequence)
{
if(!node->getAsConstantUnion() || !node->getAsConstantUnion()->getUnionArrayPointer())
{
return false;
}
}
return true;
}
protected:
TIntermAggregate(const TIntermAggregate&); // disallow copy constructor
TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator
......@@ -617,7 +633,7 @@ enum Visit
};
//
// For traversing the tree. User should derive from this,
// For traversing the tree. User should derive from this,
// put their traversal specific data in it, and then pass
// it to a Traverse method.
//
......@@ -628,7 +644,7 @@ class TIntermTraverser
{
public:
POOL_ALLOCATOR_NEW_DELETE();
TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) :
TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) :
preVisit(preVisit),
inVisit(inVisit),
postVisit(postVisit),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment