return tempNode;
default:
- infoSink.info.message(EPrefixInternalError, "Invalid operator for constant folding", getLine());
return 0;
}
tempNode = new TIntermConstantUnion(tempConstArray, returnType);
parameter.type = registerType(arg);\r
parameter.bufferIndex = argumentInfo.bufferIndex;\r
\r
- if(arg->getQualifier() == EvqConstExpr)\r
+ if(arg->getAsConstantUnion() && arg->getAsConstantUnion()->getUnionArrayPointer())\r
{\r
int component = componentCount(type, argumentInfo.clampedIndex);\r
ConstantUnion *constants = arg->getAsConstantUnion()->getUnionArrayPointer();\r
outputQualifier = qualifier;\r
}\r
\r
+ if(qualifier == EvqConstExpr && (!operand->getAsConstantUnion() || !operand->getAsConstantUnion()->getUnionArrayPointer()))\r
+ {\r
+ return sw::Shader::PARAMETER_TEMP;\r
+ }\r
+\r
switch(qualifier)\r
{\r
case EvqTemporary: return sw::Shader::PARAMETER_TEMP;\r
{\r
case EvqTemporary: return temporaryRegister(operand);\r
case EvqGlobal: return temporaryRegister(operand);\r
- case EvqConstExpr: UNREACHABLE(EvqConstExpr);\r
+ case EvqConstExpr: return temporaryRegister(operand); // Unevaluated constant expression\r
case EvqAttribute: return attributeRegister(operand);\r
case EvqVaryingIn: return varyingRegister(operand);\r
case EvqVaryingOut: return varyingRegister(operand);\r
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());
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;
//
// 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;
//
if (qualifier == EvqConstExpr) {
- if (qualifier != initializer->getType().getQualifier()) {
+ if (qualifier != initializer->getQualifier()) {
std::stringstream extraInfoStream;
extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
std::string extraInfo = extraInfoStream.str();
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()) {
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) {
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;
aggregate->setName(function.getMangledName().c_str());
aggregate->setType(function.getReturnType());
- // store the pragma information for debug and optimize and other vendor specific\r
- // information. This information can be queried from the parse tree\r
- aggregate->setOptimize(pragma().optimize);\r
+ // 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())\r
+ if(functionBody && functionBody->getAsAggregate())
aggregate->setEndLine(functionBody->getAsAggregate()->getEndLine());
symbolTable.pop();
}
// 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;
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) {
// 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)
recover();
}
- if(baseExpression->getType().getQualifier() == EvqConstExpr)
+ if(baseExpression->getAsConstantUnion())
{
// constant folding for vector fields
indexedExpression = addConstVectorNode(fields, baseExpression, fieldLocation);
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);
}
ConstantUnion* getConstPointer() const { return unionArray; }
+ bool isConstant() const { return unionArray != nullptr; }
void shareConstPointer( ConstantUnion *constArray)
{
// 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
TType type($1);
function = new TFunction($2.string, type);
$$ = function;
-
+
context->symbolTable.push();
}
;
| 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);
}
// 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
// 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.
//
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
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(); }
// 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; }
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; }
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;
};
virtual TIntermUnary* getAsUnaryNode() { return this; }
void setOperand(TIntermTyped* o) { operand = o; }
- TIntermTyped* getOperand() { return operand; }
+ TIntermTyped* getOperand() { return operand; }
bool promote(TInfoSink&);
protected:
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
};
//
-// 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.
//
{
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),