Commit 55218627 by John Kessenich

Implement the full scheme for ES precision qualifiers, generalizing existing…

Implement the full scheme for ES precision qualifiers, generalizing existing storage qualifiers to be able to include multiple independent kinds of qualifiers. git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@20317 e7fa87d3-cd2b-0410-9028-fcbf551c1848
parent 674014bf
......@@ -55,7 +55,7 @@ enum TBasicType {
EbtSamplerRectShadow, // ARB_texture_rectangle
EbtGuardSamplerEnd, // non type: see implementation of IsSampler()
EbtStruct,
EbtAddress, // should be deprecated??
EbtNumTypes
};
__inline bool IsSampler(TBasicType type)
......@@ -69,7 +69,7 @@ __inline bool IsSampler(TBasicType type)
// to allocate variables in. Since built-ins tend to go to different registers
// than varying or uniform, it makes sense they are peers, not sub-classes.
//
enum TQualifier {
enum TStorageQualifier {
EvqTemporary, // For temporaries (within a function), read/write
EvqGlobal, // For globals read/write
EvqConst, // User defined constants and non-output parameters in functions
......@@ -104,7 +104,7 @@ enum TQualifier {
//
// This is just for debug print out, carried along with the definitions above.
//
__inline const char* getQualifierString(TQualifier q)
__inline const char* getStorageQualifierString(TStorageQualifier q)
{
switch (q) {
case EvqTemporary: return "Temporary"; break;
......@@ -129,4 +129,22 @@ __inline const char* getQualifierString(TQualifier q)
}
}
enum TPrecisionQualifier {
EpqNone,
EpqLow,
EpqMedium,
EpqHigh
};
__inline const char* getPrecisionQualifierString(TPrecisionQualifier p)
{
switch(p) {
case EpqNone: return ""; break;
case EpqLow: return "lowp"; break;
case EpqMedium: return "mediump"; break;
case EpqHigh: return "highp"; break;
default: return "unknown precision qualifier";
}
}
#endif // _BASICTYPES_INCLUDED_
......@@ -56,13 +56,20 @@ inline TTypeList* NewPoolTTypeList()
//
// This is a workaround for a problem with the yacc stack, It can't have
// types that it thinks have non-trivial constructors. It should
// types that it thinks have non-trivial constructors. It should
// just be used while recognizing the grammar, not anything else. Pointers
// could be used, but also trying to avoid lots of memory management overhead.
//
// Not as bad as it looks, there is no actual assumption that the fields
// match up or are name the same or anything like that.
//
class TQualifier {
public:
TStorageQualifier storage : 7;
TPrecisionQualifier precision : 3;
};
class TPublicType {
public:
TBasicType type;
......@@ -74,10 +81,9 @@ public:
TType* userDef;
int line;
void setBasic(TBasicType bt, TQualifier q, int ln = 0)
{
type = bt;
qualifier = q;
void initType(int ln = 0)
{
type = EbtVoid;
size = 1;
matrix = false;
array = false;
......@@ -86,6 +92,18 @@ public:
line = ln;
}
void initQualifiers(bool global = false)
{
qualifier.storage = global ? EvqGlobal : EvqTemporary;
qualifier.precision = EpqNone;
}
void init(int line = 0, bool global = false)
{
initType(line);
initQualifiers(global);
}
void setAggregate(int s, bool m = false)
{
size = s;
......@@ -107,22 +125,28 @@ typedef std::map<TTypeList*, TTypeList*>::iterator TStructureMapIterator;
class TType {
public:
POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
explicit TType(TBasicType t, TQualifier q = EvqTemporary, int s = 1, bool m = false, bool a = false) :
type(t), qualifier(q), size(s), matrix(m), array(a), arraySize(0),
structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0), typeName(0)
{ }
explicit TType(TBasicType t, TStorageQualifier q = EvqTemporary, int s = 1, bool m = false, bool a = false) :
type(t), size(s), matrix(m), array(a), arraySize(0),
structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0),
fieldName(0), mangled(0), typeName(0) {
qualifier.storage = q;
qualifier.precision = EpqNone;
}
explicit TType(const TPublicType &p) :
type(p.type), qualifier(p.qualifier), size(p.size), matrix(p.matrix), array(p.array), arraySize(p.arraySize),
type(p.type), size(p.size), matrix(p.matrix), array(p.array), arraySize(p.arraySize),
structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0), typeName(0)
{
if (p.userDef) {
structure = p.userDef->getStruct();
typeName = NewPoolTString(p.userDef->getTypeName().c_str());
}
qualifier = p.qualifier;
if (p.userDef) {
structure = p.userDef->getStruct();
typeName = NewPoolTString(p.userDef->getTypeName().c_str());
}
}
explicit TType(TTypeList* userDef, const TString& n) :
type(EbtStruct), qualifier(EvqTemporary), size(1), matrix(false), array(false), arraySize(0),
type(EbtStruct), size(1), matrix(false), array(false), arraySize(0),
structure(userDef), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0) {
qualifier.storage = EvqTemporary;
qualifier.precision = EpqNone;
typeName = NewPoolTString(n.c_str());
}
explicit TType() {}
......@@ -180,47 +204,47 @@ public:
return newType;
}
virtual void setType(TBasicType t, int s, bool m, bool a, int aS = 0)
{ type = t; size = s; matrix = m; array = a; arraySize = aS; }
virtual void setType(TBasicType t, int s, bool m, TType* userDef = 0)
{ type = t;
size = s;
matrix = m;
{ type = t;
size = s;
matrix = m;
if (userDef)
structure = userDef->getStruct();
structure = userDef->getStruct();
// leave array information intact.
}
virtual void setTypeName(const TString& n) { typeName = NewPoolTString(n.c_str()); }
virtual void setFieldName(const TString& n) { fieldName = NewPoolTString(n.c_str()); }
virtual const TString& getTypeName() const
{
{
assert(typeName);
return *typeName;
return *typeName;
}
virtual const TString& getFieldName() const
{
{
assert(fieldName);
return *fieldName;
return *fieldName;
}
virtual TBasicType getBasicType() const { return type; }
virtual TQualifier getQualifier() const { return qualifier; }
virtual void changeQualifier(TQualifier q) { qualifier = q; }
virtual TQualifier& getQualifier() { return qualifier; }
virtual const TQualifier& getQualifier() const { return qualifier; }
// One-dimensional size of single instance type
virtual int getNominalSize() const { return size; }
virtual int getNominalSize() const { return size; }
// Full-dimensional size of single instance of type
virtual int getInstanceSize() const
virtual int getInstanceSize() const
{
if (matrix)
return size * size;
else
return size;
}
virtual bool isMatrix() const { return matrix ? true : false; }
virtual bool isArray() const { return array ? true : false; }
int getArraySize() const { return arraySize; }
......@@ -251,18 +275,19 @@ public:
}
}
const char* getBasicString() const { return TType::getBasicString(type); }
const char* getQualifierString() const { return ::getQualifierString(qualifier); }
const char* getStorageQualifierString() const { return ::getStorageQualifierString(qualifier.storage); }
const char* getPrecisionQualifierString() const { return ::getPrecisionQualifierString(qualifier.precision); }
TTypeList* getStruct() { return structure; }
int getObjectSize() const
{
int totalSize;
if (getBasicType() == EbtStruct)
totalSize = getStructSize();
else if (matrix)
totalSize = size * size;
else
totalSize = size * size;
else
totalSize = size;
if (isArray())
......@@ -275,10 +300,10 @@ public:
TString& getMangledName() {
if (!mangled) {
mangled = NewPoolTString("");
buildMangledName(*mangled);
buildMangledName(*mangled);
*mangled += ';' ;
}
return *mangled;
}
bool sameElementType(const TType& right) const {
......@@ -299,16 +324,17 @@ public:
return !operator==(right);
}
TString getCompleteString() const;
protected:
void buildMangledName(TString&);
int getStructSize() const;
TBasicType type : 6;
TQualifier qualifier : 7;
TBasicType type : 8;
int size : 8; // size of vector or matrix, not size of array
unsigned int matrix : 1;
unsigned int array : 1;
TQualifier qualifier;
int arraySize;
TTypeList* structure; // 0 unless this is a struct
......
......@@ -285,14 +285,14 @@ public:
virtual TType* getTypePointer() { return &type; }
virtual TBasicType getBasicType() const { return type.getBasicType(); }
virtual TQualifier getQualifier() const { return type.getQualifier(); }
virtual TQualifier& getQualifier() { return type.getQualifier(); }
virtual int getNominalSize() const { return type.getNominalSize(); }
virtual int getSize() const { return type.getInstanceSize(); }
virtual bool isMatrix() const { return type.isMatrix(); }
virtual bool isArray() const { return type.isArray(); }
virtual bool isVector() const { return type.isVector(); }
const char* getBasicString() const { return type.getBasicString(); }
const char* getQualifierString() const { return type.getQualifierString(); }
const char* getStorageQualifierString() const { return type.getStorageQualifierString(); }
TString getCompleteString() const { return type.getCompleteString(); }
protected:
......@@ -451,7 +451,7 @@ public:
virtual void traverse(TIntermTraverser*);
virtual void setUserDefined() { userDefined = true; }
virtual bool isUserDefined() { return userDefined; }
virtual TQualifierList& getQualifier() { return qualifier; }
virtual TQualifierList& getQualifierList() { return qualifier; }
void setOptimize(bool o) { optimize = o; }
void setDebug(bool d) { debug = d; }
bool getOptimize() { return optimize; }
......
......@@ -546,13 +546,14 @@ TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nod
TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc line)
{
if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) {
if (left->getType().getQualifier().storage == EvqConst &&
right->getType().getQualifier().storage == EvqConst) {
return right;
} else {
TIntermTyped *commaAggregate = growAggregate(left, right, line);
commaAggregate->getAsAggregate()->setOperator(EOpComma);
commaAggregate->setType(right->getType());
commaAggregate->getTypePointer()->changeQualifier(EvqTemporary);
commaAggregate->getTypePointer()->getQualifier().storage = EvqTemporary;
return commaAggregate;
}
}
......@@ -830,7 +831,11 @@ bool TIntermBinary::promote(TInfoSink& infoSink)
// operand. Then only deviations from this need be coded.
//
setType(left->getType());
type.changeQualifier(EvqTemporary);
type.getQualifier().storage = EvqTemporary;
// Fix precision qualifiers
if (right->getQualifier().precision > getQualifier().precision)
getQualifier().precision = right->getQualifier().precision;
//
// Array operations.
......@@ -1510,7 +1515,8 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC
const TType& t = node->getType();
return addConstantUnion(leftUnionArray, TType(promoteTo, t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine());
return addConstantUnion(leftUnionArray, TType(promoteTo, t.getQualifier().storage, t.getNominalSize(), t.isMatrix(),
t.isArray()), node->getLine());
}
void TIntermAggregate::addToPragmaTable(const TPragmaTable& pTable)
......
......@@ -44,6 +44,25 @@
//
////////////////////////////////////////////////////////////////////////
TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, EShLanguage L, TInfoSink& is) :
intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0),
recoveredFromError(false), numErrors(0), lexAfterType(false), loopNestingLevel(0),
switchNestingLevel(0), inTypeParen(false),
version(110), profile(ENoProfile), futureCompatibility(false),
contextPragma(true, false)
{
// Default precisions for version 110, to be overridden for
// other versions/profiles/stage combinations
for (int type = 0; type < EbtNumTypes; ++type)
defaultPrecision[type] = EpqHigh;
defaultPrecision[EbtVoid] = EpqNone;
defaultPrecision[EbtDouble] = EpqNone;
defaultPrecision[EbtBool] = EpqNone;
defaultPrecision[EbtVoid] = EpqNone;
}
//
// Look at a '.' field selector string and change it into offsets
// for a vector.
......@@ -331,7 +350,7 @@ bool TParseContext::lValueErrorCheck(int line, char* op, TIntermTyped* node)
symbol = symNode->getSymbol().c_str();
char* message = 0;
switch (node->getQualifier()) {
switch (node->getQualifier().storage) {
case EvqConst: message = "can't modify a const"; break;
case EvqConstReadOnly: message = "can't modify a const"; break;
case EvqAttribute: message = "can't modify an attribute"; break;
......@@ -395,7 +414,7 @@ bool TParseContext::lValueErrorCheck(int line, char* op, TIntermTyped* node)
//
bool TParseContext::constErrorCheck(TIntermTyped* node)
{
if (node->getQualifier() == EvqConst)
if (node->getQualifier().storage == EvqConst)
return false;
error(node->getLine(), "constant expression required", "", "");
......@@ -503,14 +522,14 @@ bool TParseContext::constructorErrorCheck(int line, TIntermNode* node, TFunction
overFull = true;
if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize())
full = true;
if (function[i].type->getQualifier() != EvqConst)
if (function[i].type->getQualifier().storage != EvqConst)
constType = false;
if (function[i].type->isArray())
arrayArg = true;
}
if (constType)
type->changeQualifier(EvqConst);
type->getQualifier().storage = EvqConst;
if (type->isArray() && type->getArraySize() != function.getParamCount()) {
error(line, "array constructor needs one argument per array element", "constructor", "");
......@@ -623,19 +642,19 @@ bool TParseContext::samplerErrorCheck(int line, const TPublicType& pType, const
bool TParseContext::globalQualifierFixAndErrorCheck(int line, TQualifier& qualifier)
{
switch (qualifier) {
switch (qualifier.storage) {
case EvqIn:
profileRequires(line, ENoProfile, 130, 0, "in for stage inputs");
profileRequires(line, EEsProfile, 300, 0, "in for stage inputs");
qualifier = EvqVaryingIn;
qualifier.storage = EvqVaryingIn;
break;
case EvqOut:
profileRequires(line, ENoProfile, 130, 0, "out for stage outputs");
profileRequires(line, EEsProfile, 300, 0, "out for stage outputs");
qualifier = EvqVaryingOut;
qualifier.storage = EvqVaryingOut;
break;
case EvqInOut:
qualifier = EvqVaryingIn;
qualifier.storage = EvqVaryingIn;
error(line, "cannot use 'inout' at global scope", "", "");
return true;
......@@ -646,20 +665,34 @@ bool TParseContext::globalQualifierFixAndErrorCheck(int line, TQualifier& qualif
bool TParseContext::structQualifierErrorCheck(int line, const TPublicType& pType)
{
if ((pType.qualifier == EvqVaryingIn || pType.qualifier == EvqVaryingOut || pType.qualifier == EvqAttribute) &&
if ((pType.qualifier.storage == EvqVaryingIn ||
pType.qualifier.storage == EvqVaryingOut ||
pType.qualifier.storage == EvqAttribute) &&
pType.type == EbtStruct) {
error(line, "cannot be used with a structure", getQualifierString(pType.qualifier), "");
error(line, "cannot be used with a structure", getStorageQualifierString(pType.qualifier.storage), "");
return true;
}
if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform"))
if (pType.qualifier.storage != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform"))
return true;
return false;
}
bool TParseContext::parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type)
void TParseContext::setDefaultPrecision(int line, TBasicType type, TPrecisionQualifier qualifier)
{
// TODO: push and pop for nested scopes
if (IsSampler(type) || type == EbtInt || type == EbtFloat) {
defaultPrecision[type] = qualifier;
} else {
error(line, "cannot apply precision statement to this type", TType::getBasicString(type), "");
recover();
}
}
bool TParseContext::parameterSamplerErrorCheck(int line, TStorageQualifier qualifier, const TType& type)
{
if ((qualifier == EvqOut || qualifier == EvqInOut) &&
type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) {
......@@ -741,12 +774,12 @@ bool TParseContext::arraySizeErrorCheck(int line, TIntermTyped* expr, int& size)
//
bool TParseContext::arrayQualifierErrorCheck(int line, TPublicType type)
{
if (type.qualifier == EvqAttribute) {
if (type.qualifier.storage == EvqAttribute) {
error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str(), "");
return true;
}
if (type.qualifier == EvqConst)
if (type.qualifier.storage == EvqConst)
profileRequires(line, ENoProfile, 120, "GL_3DL_array_objects", "const array");
return false;
......@@ -899,8 +932,8 @@ bool TParseContext::nonInitConstErrorCheck(int line, TString& identifier, TPubli
//
// Make the qualifier make sense.
//
if (type.qualifier == EvqConst) {
type.qualifier = EvqTemporary;
if (type.qualifier.storage == EvqConst) {
type.qualifier.storage = EvqTemporary;
error(line, "variables with qualifier 'const' must be initialized", identifier.c_str(), "");
return true;
}
......@@ -933,24 +966,24 @@ bool TParseContext::nonInitErrorCheck(int line, TString& identifier, TPublicType
return false;
}
bool TParseContext::paramErrorCheck(int line, TQualifier qualifier, TType* type)
bool TParseContext::paramErrorCheck(int line, TStorageQualifier qualifier, TType* type)
{
switch (qualifier) {
case EvqConst:
case EvqConstReadOnly:
type->changeQualifier(EvqConstReadOnly);
type->getQualifier().storage = EvqConstReadOnly;
return false;
case EvqIn:
case EvqOut:
case EvqInOut:
type->changeQualifier(qualifier);
type->getQualifier().storage = qualifier;
return false;
case EvqTemporary:
type->changeQualifier(EvqIn);
type->getQualifier().storage = EvqIn;
return false;
default:
type->changeQualifier(EvqIn);
error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier), "");
type->getQualifier().storage = EvqIn;
error(line, "qualifier not allowed on function parameter", getStorageQualifierString(qualifier), "");
return true;
}
}
......@@ -1016,9 +1049,9 @@ bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPu
//
// identifier must be of type constant, a global, or a temporary
//
TQualifier qualifier = variable->getType().getQualifier();
TStorageQualifier qualifier = variable->getType().getQualifier().storage;
if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) {
error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString(), "");
error(line, " cannot initialize this type of qualifier ", variable->getType().getStorageQualifierString(), "");
return true;
}
//
......@@ -1026,15 +1059,15 @@ bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPu
//
if (qualifier == EvqConst) {
if (qualifier != initializer->getType().getQualifier()) {
if (qualifier != initializer->getType().getQualifier().storage) {
error(line, " assigning non-constant to", "=", "'%s'", variable->getType().getCompleteString().c_str());
variable->getType().changeQualifier(EvqTemporary);
variable->getType().getQualifier().storage = EvqTemporary;
return true;
}
if (type != initializer->getType()) {
error(line, " non-matching types for const initializer ",
variable->getType().getQualifierString(), "");
variable->getType().changeQualifier(EvqTemporary);
variable->getType().getStorageQualifierString(), "");
variable->getType().getQualifier().storage = EvqTemporary;
return true;
}
if (initializer->getAsConstantUnion()) {
......@@ -1053,7 +1086,7 @@ bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPu
variable->shareConstPointer(constArray);
} else {
error(line, " cannot assign to", "=", "'%s'", variable->getType().getCompleteString().c_str());
variable->getType().changeQualifier(EvqTemporary);
variable->getType().getQualifier().storage = EvqTemporary;
return true;
}
}
......
......@@ -45,7 +45,7 @@ struct TMatrixFields {
bool wholeRow;
bool wholeCol;
int row;
int col;
int col;
};
typedef enum {
......@@ -67,12 +67,7 @@ struct TPragma {
// they can be passed to the parser without needing a global.
//
struct TParseContext {
TParseContext(TSymbolTable& symt, TIntermediate& interm, EShLanguage L, TInfoSink& is) :
intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0),
recoveredFromError(false), numErrors(0), lexAfterType(false), loopNestingLevel(0),
switchNestingLevel(0), inTypeParen(false),
version(110), profile(ENoProfile), futureCompatibility(false),
contextPragma(true, false) { }
TParseContext(TSymbolTable& symt, TIntermediate& interm, EShLanguage L, TInfoSink& is);
TIntermediate& intermediate; // to hold and build a parse tree
TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed
TInfoSink& infoSink;
......@@ -91,18 +86,19 @@ struct TParseContext {
EProfile profile; // the declared profile in the shader (core by default)
bool futureCompatibility; // true if requesting errors for future compatibility (false by default)
TMap<TString, TBehavior> extensionBehavior; // for each extension string, what it's current enablement is
struct TPragma contextPragma;
TString HashErrMsg;
TPrecisionQualifier defaultPrecision[EbtNumTypes];
TString HashErrMsg;
bool AfterEOF;
void initializeExtensionBehavior();
void C_DECL error(TSourceLoc, const char *szReason, const char *szToken,
void C_DECL error(TSourceLoc, const char *szReason, const char *szToken,
const char *szExtraInfoFormat, ...);
bool reservedErrorCheck(int line, const TString& identifier);
void recover();
bool parseVectorFields(const TString&, int vecSize, TVectorFields&, int line);
bool parseMatrixFields(const TString&, int matSize, TMatrixFields&, int line);
void assignError(int line, const char* op, TString left, TString right);
......@@ -125,13 +121,14 @@ struct TParseContext {
bool samplerErrorCheck(int line, const TPublicType& pType, const char* reason);
bool globalQualifierFixAndErrorCheck(int line, TQualifier&);
bool structQualifierErrorCheck(int line, const TPublicType& pType);
bool parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type);
void setDefaultPrecision(int line, TBasicType, TPrecisionQualifier);
bool parameterSamplerErrorCheck(int line, TStorageQualifier qualifier, const TType& type);
bool containsSampler(TType& type);
bool nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type);
bool nonInitErrorCheck(int line, TString& identifier, TPublicType& type);
bool paramErrorCheck(int line, TQualifier qualifier, TType* type);
bool paramErrorCheck(int line, TStorageQualifier qualifier, TType* type);
const TFunction* findFunction(int line, TFunction* pfnCall, bool *builtIn = 0);
bool executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
bool executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0);
bool areAllChildConst(TIntermAggregate* aggrNode);
TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, TSourceLoc);
......
......@@ -36,7 +36,7 @@
class TAliveTraverser : public TIntermTraverser {
public:
TAliveTraverser(TQualifier q) : TIntermTraverser(), found(false), qualifier(q)
TAliveTraverser(TStorageQualifier q) : TIntermTraverser(), found(false), qualifier(q)
{
visitSymbol = AliveSymbol;
visitSelection = AliveSelection;
......@@ -45,7 +45,7 @@ public:
bool wasFound() { return found; }
protected:
bool found;
TQualifier qualifier;
TStorageQualifier qualifier;
friend void AliveSymbol(TIntermSymbol*, TIntermTraverser*);
friend bool AliveSelection(bool, TIntermSelection*, TIntermTraverser*);
......@@ -59,7 +59,7 @@ protected:
// ?? It does not do this well yet, this is just a place holder
// that simply determines if it was reference at all, anywhere.
//
bool QualifierWritten(TIntermNode* node, TQualifier qualifier)
bool QualifierWritten(TIntermNode* node, TStorageQualifier qualifier)
{
TAliveTraverser it(qualifier);
......@@ -76,7 +76,7 @@ void AliveSymbol(TIntermSymbol* node, TIntermTraverser* it)
//
// If it's what we're looking for, record it.
//
if (node->getQualifier() == lit->qualifier)
if (node->getQualifier().storage == lit->qualifier)
lit->found = true;
}
......
......@@ -32,4 +32,4 @@
//POSSIBILITY OF SUCH DAMAGE.
//
bool QualifierWritten(TIntermNode* root, TQualifier);
bool QualifierWritten(TIntermNode* root, TStorageQualifier);
......@@ -92,12 +92,11 @@ int ShInitialize()
SetGlobalPoolAllocatorPtr(gPoolAllocator);
symTables[EShLangVertex].pop();
symTables[EShLangFragment].pop();
symTables[EShLangVertex].pop(0);
symTables[EShLangFragment].pop(0);
builtInPoolAllocator->popAll();
delete builtInPoolAllocator;
delete builtInPoolAllocator;
}
return ret ? 1 : 0;
......@@ -343,7 +342,7 @@ int ShCompile(
// throwing away all but the built-ins.
//
while (! symbolTable.atSharedBuiltInLevel())
symbolTable.pop();
symbolTable.pop(0);
FinalizePreprocessor();
//
......
......@@ -111,7 +111,7 @@ int TType::getStructSize() const
void TVariable::dump(TInfoSink& infoSink) const
{
infoSink.debug << getName().c_str() << ": " << type.getQualifierString() << " " << type.getBasicString();
infoSink.debug << getName().c_str() << ": " << type.getStorageQualifierString() << " " << type.getBasicString();
if (type.isArray()) {
infoSink.debug << "[0]";
}
......@@ -154,6 +154,8 @@ TSymbolTableLevel::~TSymbolTableLevel()
{
for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
delete (*it).second;
delete [] defaultPrecision;
}
//
......
......@@ -46,7 +46,7 @@
// so that symbol table lookups are never ambiguous. This allows
// a simpler symbol table structure.
//
// * Pushing and popping of scope, so symbol table will really be a stack
// * Pushing and popping of scope, so symbol table will really be a stack
// of symbol tables. Searched from the top, with new inserts going into
// the top.
//
......@@ -61,11 +61,11 @@
#include "../Include/Common.h"
#include "../Include/intermediate.h"
#include "../Include/InfoSink.h"
//
// Symbol base class. (Can build functions or variables out of these...)
//
class TSymbol {
class TSymbol {
public:
POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
TSymbol(const TString *n) : name(n) { }
......@@ -87,29 +87,29 @@ protected:
//
// Variable class, meaning a symbol that's not a function.
//
//
// There could be a separate class heirarchy for Constant variables;
// Only one of int, bool, or float, (or none) is correct for
// any particular use, but it's easy to do this way, and doesn't
// seem worth having separate classes, and "getConst" can't simply return
// different values for different types polymorphically, so this is
// different values for different types polymorphically, so this is
// just simple and pragmatic.
//
class TVariable : public TSymbol {
public:
TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0), arrayInformationType(0) { }
virtual ~TVariable() { }
virtual bool isVariable() const { return true; }
TType& getType() { return type; }
virtual bool isVariable() const { return true; }
TType& getType() { return type; }
const TType& getType() const { return type; }
bool isUserType() const { return userType; }
void changeQualifier(TQualifier qualifier) { type.changeQualifier(qualifier); }
void setStorageQualifier(TStorageQualifier qualifier) { type.getQualifier().storage = qualifier; }
void updateArrayInformationType(TType *t) { arrayInformationType = t; }
TType* getArrayInformationType() { return arrayInformationType; }
virtual void dump(TInfoSink &infoSink) const;
constUnion* getConstPointer() {
constUnion* getConstPointer() {
if (!unionArray)
unionArray = new constUnion[type.getObjectSize()];
......@@ -121,11 +121,11 @@ public:
void shareConstPointer( constUnion *constArray)
{
delete unionArray;
unionArray = constArray;
unionArray = constArray;
}
TVariable(const TVariable&, TStructureMap& remapper); // copy constructor
virtual TVariable* clone(TStructureMap& remapper);
protected:
TType type;
bool userType;
......@@ -149,7 +149,7 @@ struct TParameter {
};
//
// The function sub-class of a symbol.
// The function sub-class of a symbol.
//
class TFunction : public TSymbol {
public:
......@@ -158,21 +158,21 @@ public:
returnType(TType(EbtVoid)),
op(o),
defined(false) { }
TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull) :
TSymbol(name),
TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull) :
TSymbol(name),
returnType(retType),
mangledName(*name + '('),
op(tOp),
defined(false) { }
virtual ~TFunction();
virtual bool isFunction() const { return true; }
void addParameter(TParameter& p)
{
virtual bool isFunction() const { return true; }
void addParameter(TParameter& p)
{
parameters.push_back(p);
mangledName = mangledName + p.type->getMangledName();
}
const TString& getMangledName() const { return mangledName; }
const TType& getReturnType() const { return returnType; }
void relateToOperator(TOperator o) { op = o; }
......@@ -180,14 +180,14 @@ public:
void setDefined() { defined = true; }
bool isDefined() { return defined; }
int getParamCount() const { return static_cast<int>(parameters.size()); }
int getParamCount() const { return static_cast<int>(parameters.size()); }
TParameter& operator [](int i) { return parameters[i]; }
const TParameter& operator [](int i) const { return parameters[i]; }
virtual void dump(TInfoSink &infoSink) const;
TFunction(const TFunction&, TStructureMap& remapper);
virtual TFunction* clone(TStructureMap& remapper);
protected:
typedef TVector<TParameter> TParamList;
TParamList parameters;
......@@ -201,17 +201,17 @@ protected:
class TSymbolTableLevel {
public:
POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
TSymbolTableLevel() { }
TSymbolTableLevel() : defaultPrecision (0) { }
~TSymbolTableLevel();
bool insert(TSymbol& symbol)
bool insert(TSymbol& symbol)
{
//
// returning true means symbol was added to the table
//
tInsertResult result;
result = level.insert(tLevelPair(symbol.getMangledName(), &symbol));
return result.second;
}
......@@ -224,17 +224,44 @@ public:
return (*it).second;
}
// Use this to do a lazy 'push' of precision defaults the first time
// a precision statement is seen in a new scope. Leave it at 0 for
// when no push was needed. Thus, it is not the current defaults,
// it is what to restore the defaults to when popping a level.
void setPreviousDefaultPrecisions(const TPrecisionQualifier *p)
{
// can call multiple times at one scope, will only latch on first call,
// as we're tracking the previous scope's values, not the current values
if (defaultPrecision != 0)
return;
defaultPrecision = new TPrecisionQualifier[EbtNumTypes];
for (int t = 0; t < EbtNumTypes; ++t)
defaultPrecision[t] = p[t];
}
void getPreviousDefaultPrecisions(TPrecisionQualifier *p)
{
// can be called for table level pops that didn't set the
// defaults
if (defaultPrecision == 0 || p == 0)
return;
for (int t = 0; t < EbtNumTypes; ++t)
p[t] = defaultPrecision[t];
}
void relateToOperator(const char* name, TOperator op);
void dump(TInfoSink &infoSink) const;
TSymbolTableLevel* clone(TStructureMap& remapper);
protected:
typedef std::map<TString, TSymbol*, std::less<TString>, pool_allocator<std::pair<const TString, TSymbol*> > > tLevel;
typedef const tLevel::value_type tLevelPair;
typedef std::pair<tLevel::iterator, bool> tInsertResult;
tLevel level;
TPrecisionQualifier *defaultPrecision;
};
class TSymbolTable {
......@@ -258,7 +285,7 @@ public:
{
// level 0 is always built In symbols, so we never pop that out
while (table.size() > 1)
pop();
pop(0);
}
//
......@@ -270,13 +297,17 @@ public:
bool atBuiltInLevel() { return atSharedBuiltInLevel() || atDynamicBuiltInLevel(); }
bool atSharedBuiltInLevel() { return table.size() == 1; }
bool atGlobalLevel() { return table.size() <= 3; }
void push() {
void push()
{
table.push_back(new TSymbolTableLevel);
}
void pop() {
delete table[currentLevel()];
table.pop_back();
void pop(TPrecisionQualifier *p)
{
table[currentLevel()]->getPreviousDefaultPrecisions(p);
delete table[currentLevel()];
table.pop_back();
}
bool insert(TSymbol& symbol)
......@@ -284,8 +315,8 @@ public:
symbol.setUniqueId(++uniqueId);
return table[currentLevel()]->insert(symbol);
}
TSymbol* find(const TString& name, bool* builtIn = 0, bool *sameScope = 0)
TSymbol* find(const TString& name, bool* builtIn = 0, bool *sameScope = 0)
{
int level = currentLevel();
TSymbol* symbol;
......@@ -307,7 +338,9 @@ public:
void dump(TInfoSink &infoSink) const;
void copyTable(const TSymbolTable& copyOf);
protected:
void setPreviousDefaultPrecisions(TPrecisionQualifier *p) { table[currentLevel()]->setPreviousDefaultPrecisions(p); }
protected:
int currentLevel() const { return static_cast<int>(table.size()) - 1; }
bool atDynamicBuiltInLevel() { return table.size() == 2; }
......
......@@ -732,6 +732,24 @@ void SetVersion(int version)
{
TParseContext& parseContext = *((TParseContext *)cpp->pC);
parseContext.version = version;
if (version == 100 || version == 300) {
for (int type = 0; type < EbtNumTypes; ++type)
parseContext.defaultPrecision[type] = EpqNone;
if (parseContext.language == EShLangVertex) {
parseContext.defaultPrecision[EbtInt] = EpqHigh;
parseContext.defaultPrecision[EbtFloat] = EpqHigh;
parseContext.defaultPrecision[EbtSampler2D] = EpqLow;
parseContext.defaultPrecision[EbtSamplerCube] = EpqLow;
}
if (parseContext.language == EShLangFragment) {
parseContext.defaultPrecision[EbtInt] = EpqMedium;
parseContext.defaultPrecision[EbtSampler2D] = EpqLow;
parseContext.defaultPrecision[EbtSamplerCube] = EpqLow;
}
}
}
const int FirstProfileVersion = 150;
......
......@@ -60,10 +60,12 @@ TString TType::getCompleteString() const
char *p = &buf[0];
char *end = &buf[maxSize];
if (qualifier != EvqTemporary && qualifier != EvqGlobal)
p += sprintf_s(p, end - p, "%s ", getQualifierString());
if (qualifier.storage != EvqTemporary && qualifier.storage != EvqGlobal)
p += sprintf_s(p, end - p, "%s ", getStorageQualifierString());
if (array)
p += sprintf_s(p, end - p, "array of ");
if (qualifier.precision != EpqNone)
p += sprintf_s(p, end - p, "%s ", getPrecisionQualifierString());
if (matrix)
p += sprintf_s(p, end - p, "%dX%d matrix of ", size, size);
else if (size > 1)
......
......@@ -69,15 +69,15 @@ void ParseSymbol(TIntermSymbol* node, TIntermTraverser* it)
{
TConstTraverser* oit = static_cast<TConstTraverser*>(it);
oit->infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLine());
return;
return;
}
bool ParseBinary(bool /* preVisit */, TIntermBinary* node, TIntermTraverser* it)
{
TConstTraverser* oit = static_cast<TConstTraverser*>(it);
TQualifier qualifier = node->getType().getQualifier();
TStorageQualifier qualifier = node->getType().getQualifier().storage;
if (qualifier != EvqConst) {
const int maxSize = 200;
......@@ -85,6 +85,7 @@ bool ParseBinary(bool /* preVisit */, TIntermBinary* node, TIntermTraverser* it)
sprintf_s(buf, maxSize, "'constructor' : assigning non-constant to %s", oit->type.getCompleteString().c_str());
oit->infoSink.info.message(EPrefixError, buf, node->getLine());
oit->error = true;
return false;
}
......@@ -102,6 +103,7 @@ bool ParseUnary(bool /* preVisit */, TIntermUnary* node, TIntermTraverser* it)
sprintf_s(buf, maxSize, "'constructor' : assigning non-constant to '%s'", oit->type.getCompleteString().c_str());
oit->infoSink.info.message(EPrefixError, buf, node->getLine());
oit->error = true;
return false;
}
......@@ -115,11 +117,13 @@ bool ParseAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTraverse
sprintf_s(buf, maxSize, "'constructor' : assigning non-constant to '%s'", oit->type.getCompleteString().c_str());
oit->infoSink.info.message(EPrefixError, buf, node->getLine());
oit->error = true;
return false;
}
if (node->getSequence().size() == 0) {
oit->error = true;
return false;
}
......@@ -152,6 +156,7 @@ bool ParseAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTraverse
oit->isMatrix = false;
oit->matrixSize = 0;
}
return false;
}
......@@ -229,6 +234,7 @@ bool ParseLoop(bool /* preVisit */, TIntermLoop* node, TIntermTraverser* it)
TConstTraverser* oit = static_cast<TConstTraverser*>(it);
oit->infoSink.info.message(EPrefixInternalError, "Loop Node found in constant constructor", node->getLine());
oit->error = true;
return false;
}
......@@ -237,6 +243,7 @@ bool ParseBranch(bool /* previsit*/, TIntermBranch* node, TIntermTraverser* it)
TConstTraverser* oit = static_cast<TConstTraverser*>(it);
oit->infoSink.info.message(EPrefixInternalError, "Branch Node found in constant constructor", node->getLine());
oit->error = true;
return false;
}
......
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