Commit 727b374f by John Kessenich

HLSL: Build IO types bottom up, as parsed, and cache the original (IO).

Previously, this was done recursively, per object, and the nonIO version was cached. This reverses both those approaches.
parent 88c4464d
...@@ -412,7 +412,7 @@ public: ...@@ -412,7 +412,7 @@ public:
} }
// Remove IO related data from qualifier. // Remove IO related data from qualifier.
void makeNonIo() void makeNonIo() //?? remove?
{ {
// This preserves the storage type // This preserves the storage type
builtIn = EbvNone; builtIn = EbvNone;
...@@ -429,7 +429,7 @@ public: ...@@ -429,7 +429,7 @@ public:
} }
// Return true if there is data which would be scrubbed by makeNonIo // Return true if there is data which would be scrubbed by makeNonIo
bool hasIoData() const bool hasIoData() const // ?? remove?
{ {
return builtIn != EbvNone || return builtIn != EbvNone ||
hasLayout() || hasLayout() ||
...@@ -626,7 +626,6 @@ public: ...@@ -626,7 +626,6 @@ public:
{ {
return hasUniformLayout() || return hasUniformLayout() ||
hasAnyLocation() || hasAnyLocation() ||
hasBinding() ||
hasStream() || hasStream() ||
hasXfb() || hasXfb() ||
hasFormat() || hasFormat() ||
...@@ -1221,34 +1220,10 @@ public: ...@@ -1221,34 +1220,10 @@ public:
// Make complete copy of the whole type graph rooted at 'copyOf'. // Make complete copy of the whole type graph rooted at 'copyOf'.
void deepCopy(const TType& copyOf) void deepCopy(const TType& copyOf)
{ {
TMap<TTypeList*,TTypeList*> copied; // to enable copying a type graph as a graph, not a tree TMap<TTypeList*,TTypeList*> copied; // to enable copying a type graph as a graph, not a tree //?? turn off again?
deepCopy(copyOf, copied); deepCopy(copyOf, copied);
} }
// Return true if type (recursively) contains IO data.
bool hasIoData() const
{
if (getQualifier().hasIoData())
return true;
if (isStruct())
for (unsigned int i = 0; i < structure->size(); ++i)
if ((*structure)[i].type->hasIoData())
return true;
return false;
}
// Remove IO related data from type
void makeNonIo()
{
getQualifier().makeNonIo();
if (isStruct())
for (unsigned int i = 0; i < structure->size(); ++i)
(*structure)[i].type->makeNonIo();
}
// Recursively make temporary // Recursively make temporary
void makeTemporary() void makeTemporary()
{ {
......
...@@ -2,5 +2,5 @@ ...@@ -2,5 +2,5 @@
// For the version, it uses the latest git tag followed by the number of commits. // For the version, it uses the latest git tag followed by the number of commits.
// For the date, it uses the current date (when then script is run). // For the date, it uses the current date (when then script is run).
#define GLSLANG_REVISION "Overload400-PrecQual.1787" #define GLSLANG_REVISION "Overload400-PrecQual.1791"
#define GLSLANG_DATE "03-Feb-2017" #define GLSLANG_DATE "04-Feb-2017"
...@@ -1708,14 +1708,7 @@ bool HlslGrammar::acceptStruct(TType& type) ...@@ -1708,14 +1708,7 @@ bool HlslGrammar::acceptStruct(TType& type)
new(&type) TType(typeList, structName, postDeclQualifier); // sets EbtBlock new(&type) TType(typeList, structName, postDeclQualifier); // sets EbtBlock
} }
// If it was named, which means the type can be reused later, add parseContext.declareStruct(token.loc, structName, type);
// it to the symbol table. (Unless it's a block, in which
// case the name is not a type.)
if (type.getBasicType() != EbtBlock && structName.size() > 0) {
TVariable* userTypeDef = new TVariable(&structName, type, true);
if (! parseContext.symbolTable.insert(*userTypeDef))
parseContext.error(token.loc, "redefinition", structName.c_str(), "struct");
}
return true; return true;
} }
......
...@@ -161,7 +161,7 @@ bool HlslParseContext::shouldConvertLValue(const TIntermNode* node) const ...@@ -161,7 +161,7 @@ bool HlslParseContext::shouldConvertLValue(const TIntermNode* node) const
void HlslParseContext::growGlobalUniformBlock(TSourceLoc& loc, TType& memberType, TString& memberName) void HlslParseContext::growGlobalUniformBlock(TSourceLoc& loc, TType& memberType, TString& memberName)
{ {
makeTypeNonIo(&memberType); //?? losing offsets is okay? memberType.getQualifier().makeNonIo(); //?? losing offsets is okay?
TParseContextBase::growGlobalUniformBlock(loc, memberType, memberName); TParseContextBase::growGlobalUniformBlock(loc, memberType, memberName);
} }
...@@ -1583,8 +1583,6 @@ TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunct ...@@ -1583,8 +1583,6 @@ TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunct
TVector<TVariable*> inputs; TVector<TVariable*> inputs;
TVector<TVariable*> outputs; TVector<TVariable*> outputs;
remapEntryPointIO(userFunction, entryPointOutput, inputs, outputs); remapEntryPointIO(userFunction, entryPointOutput, inputs, outputs);
// Once the parameters are moved to shader I/O, they should be non-I/O
remapNonEntryPointIO(userFunction);
// Further this return/in/out transform by flattening, splitting, and assigning locations // Further this return/in/out transform by flattening, splitting, and assigning locations
const auto makeVariableInOut = [&](TVariable& variable) { const auto makeVariableInOut = [&](TVariable& variable) {
...@@ -1689,9 +1687,10 @@ void HlslParseContext::handleFunctionBody(const TSourceLoc& loc, TFunction& func ...@@ -1689,9 +1687,10 @@ void HlslParseContext::handleFunctionBody(const TSourceLoc& loc, TFunction& func
// AST I/O is done through shader globals declared in the 'in' or 'out' // AST I/O is done through shader globals declared in the 'in' or 'out'
// storage class. An HLSL entry point has a return value, input parameters // storage class. An HLSL entry point has a return value, input parameters
// and output parameters. These need to get remapped to the AST I/O. // and output parameters. These need to get remapped to the AST I/O.
void HlslParseContext::remapEntryPointIO(const TFunction& function, TVariable*& returnValue, void HlslParseContext::remapEntryPointIO(TFunction& function, TVariable*& returnValue,
TVector<TVariable*>& inputs, TVector<TVariable*>& outputs) TVector<TVariable*>& inputs, TVector<TVariable*>& outputs)
{ {
const auto makeIoVariable = [this](const char* name, TType& type) {
const auto remapType = [&](TType& type) { const auto remapType = [&](TType& type) {
const auto remapBuiltInType = [&](TType& type) { const auto remapBuiltInType = [&](TType& type) {
switch (type.getQualifier().builtIn) { switch (type.getQualifier().builtIn) {
...@@ -1709,34 +1708,46 @@ void HlslParseContext::remapEntryPointIO(const TFunction& function, TVariable*& ...@@ -1709,34 +1708,46 @@ void HlslParseContext::remapEntryPointIO(const TFunction& function, TVariable*&
}; };
remapBuiltInType(type); remapBuiltInType(type);
if (type.isStruct()) { if (type.isStruct()) {
auto members = *type.getStruct(); auto& members = *type.getStruct();
for (auto member = members.begin(); member != members.end(); ++member) for (auto member = members.begin(); member != members.end(); ++member)
remapBuiltInType(*member->type); // TODO: lack-of-recursion structure depth problem remapBuiltInType(*member->type); // TODO: lack-of-recursion structure depth problem
} }
}; };
TVariable* ioVariable = makeInternalVariable(name, type);
// We might have already lost the IO-aspect of the deep parts of this type,
// get them back and also make them if that hadn't been done yet.
// (The shallow part of IO is already safely copied into the return value.)
type.getQualifier().makeNonIo();
if (type.getStruct() != nullptr) {
auto newList = ioTypeMap.find(ioVariable->getType().getStruct());
if (newList != ioTypeMap.end())
ioVariable->getWritableType().setStruct(newList->second);
}
remapType(ioVariable->getWritableType());
return ioVariable;
};
// return value is actually a shader-scoped output (out) // return value is actually a shader-scoped output (out)
if (function.getType().getBasicType() == EbtVoid) if (function.getType().getBasicType() == EbtVoid)
returnValue = nullptr; returnValue = nullptr;
else { else {
returnValue = makeInternalVariable("@entryPointOutput", function.getType()); returnValue = makeIoVariable("@entryPointOutput", function.getWritableType());
returnValue->getWritableType().getQualifier().storage = EvqVaryingOut; returnValue->getWritableType().getQualifier().storage = EvqVaryingOut;
remapType(returnValue->getWritableType());
} }
// parameters are actually shader-scoped inputs and outputs (in or out) // parameters are actually shader-scoped inputs and outputs (in or out)
for (int i = 0; i < function.getParamCount(); i++) { for (int i = 0; i < function.getParamCount(); i++) {
TType& paramType = *function[i].type; TType& paramType = *function[i].type;
if (paramType.getQualifier().isParamInput()) { if (paramType.getQualifier().isParamInput()) {
TVariable* argAsGlobal = makeInternalVariable(*function[i].name, paramType); TVariable* argAsGlobal = makeIoVariable(function[i].name->c_str(), paramType);
argAsGlobal->getWritableType().getQualifier().storage = EvqVaryingIn; argAsGlobal->getWritableType().getQualifier().storage = EvqVaryingIn;
inputs.push_back(argAsGlobal); inputs.push_back(argAsGlobal);
} }
if (paramType.getQualifier().isParamOutput()) { if (paramType.getQualifier().isParamOutput()) {
TVariable* argAsGlobal = makeInternalVariable(*function[i].name, paramType); TVariable* argAsGlobal = makeIoVariable(function[i].name->c_str(), paramType);
argAsGlobal->getWritableType().getQualifier().storage = EvqVaryingOut; argAsGlobal->getWritableType().getQualifier().storage = EvqVaryingOut;
outputs.push_back(argAsGlobal); outputs.push_back(argAsGlobal);
remapType(argAsGlobal->getWritableType());
} }
} }
} }
...@@ -1747,11 +1758,11 @@ void HlslParseContext::remapNonEntryPointIO(TFunction& function) ...@@ -1747,11 +1758,11 @@ void HlslParseContext::remapNonEntryPointIO(TFunction& function)
{ {
// return value // return value
if (function.getType().getBasicType() != EbtVoid) if (function.getType().getBasicType() != EbtVoid)
makeTypeNonIo(&function.getWritableType()); function.getWritableType().getQualifier().makeNonIo();
// parameters // parameters
for (int i = 0; i < function.getParamCount(); i++) for (int i = 0; i < function.getParamCount(); i++)
makeTypeNonIo(function[i].type); function[i].type->getQualifier().makeNonIo();
} }
// Handle function returns, including type conversions to the function return type // Handle function returns, including type conversions to the function return type
...@@ -5349,41 +5360,59 @@ void HlslParseContext::declareTypedef(const TSourceLoc& loc, TString& identifier ...@@ -5349,41 +5360,59 @@ void HlslParseContext::declareTypedef(const TSourceLoc& loc, TString& identifier
error(loc, "name already defined", "typedef", identifier.c_str()); error(loc, "name already defined", "typedef", identifier.c_str());
} }
// Create a non-IO type from an IO type. If there is no IO data, // Do everything necessary to handle a struct declaration, including
// the input type is unmodified. Otherwise, it modifies the type // making IO aliases because HLSL allows mixed IO in a struct that specializes
// in place. // based on the usage (input, output, uniform, none).
void HlslParseContext::makeTypeNonIo(TType* type) void HlslParseContext::declareStruct(const TSourceLoc& loc, TString& structName, TType& type)
{ {
// early out if there's nothing to do: prevents introduction of unneeded types. // If it was named, which means the type can be reused later, add
if (!type->hasIoData()) // it to the symbol table. (Unless it's a block, in which
// case the name is not a type.)
if (type.getBasicType() == EbtBlock || structName.size() == 0)
return; return;
type->getQualifier().makeNonIo(); // Sanitize the qualifier. TVariable* userTypeDef = new TVariable(&structName, type, true);
if (! symbolTable.insert(*userTypeDef)) {
// Nothing more to do if there is no deep structure. error(loc, "redefinition", structName.c_str(), "struct");
if (!type->isStruct())
return; return;
}
const auto typeIter = nonIoTypeMap.find(type->getStruct()); // See if we need IO aliases for the structure typeList
if (typeIter != nonIoTypeMap.end()) { bool hasIo = false;
// reuse deep structure if we have sanitized it before, but we must preserve for (auto member = type.getStruct()->begin(); member != type.getStruct()->end(); ++member) {
// our unique shallow structure, which may not be shared with other users of if (member->type->getQualifier().hasIoData()) {
// the deep copy. Create a new type with the sanitized qualifier, and the hasIo = true;
// shared deep structure break;
type->setStruct(typeIter->second); // share already sanitized deep structure. }
} else { if (member->type->isStruct()) {
// The type contains interstage IO, but we've never encountered it before. if (ioTypeMap.find(member->type->getStruct()) != ioTypeMap.end()) {
// Copy it, scrub data we don't want for an non-IO type, and remember it in the nonIoTypeMap hasIo = true;
break;
}
}
}
if (!hasIo)
return;
TType nonIoType; // We have IO involved.
nonIoType.deepCopy(*type);
nonIoType.makeNonIo();
// remember the new deep structure in a map, so we can share it in the future. // Make a pure typeList for the symbol table, and cache side copies of IO versions.
nonIoTypeMap[type->getStruct()] = nonIoType.getWritableStruct(); TTypeList* newList = new TTypeList;
type->shallowCopy(nonIoType); // we modify the input type in place for (auto member = type.getStruct()->begin(); member != type.getStruct()->end(); ++member) {
TType* memberType = new TType;
memberType->shallowCopy(*member->type);
TTypeLoc newMember = { memberType, member->loc };
if (member->type->isStruct()) {
// swap in an IO child if there is one
auto it = ioTypeMap.find(member->type->getStruct());
if (it != ioTypeMap.end())
newMember.type->setStruct(it->second);
}
newList->push_back(newMember);
member->type->getQualifier().makeNonIo();
} }
ioTypeMap[type.getStruct()] = newList;
} }
// //
...@@ -5416,7 +5445,7 @@ TIntermNode* HlslParseContext::declareVariable(const TSourceLoc& loc, TString& i ...@@ -5416,7 +5445,7 @@ TIntermNode* HlslParseContext::declareVariable(const TSourceLoc& loc, TString& i
switch (type.getQualifier().storage) { switch (type.getQualifier().storage) {
case EvqGlobal: case EvqGlobal:
case EvqTemporary: case EvqTemporary:
makeTypeNonIo(&type); type.getQualifier().makeNonIo();
default: default:
break; break;
} }
......
...@@ -75,7 +75,7 @@ public: ...@@ -75,7 +75,7 @@ public:
TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&, const TAttributeMap&, TIntermNode*& entryPointTree); TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&, const TAttributeMap&, TIntermNode*& entryPointTree);
TIntermNode* transformEntryPoint(const TSourceLoc&, TFunction&, const TAttributeMap&); TIntermNode* transformEntryPoint(const TSourceLoc&, TFunction&, const TAttributeMap&);
void handleFunctionBody(const TSourceLoc&, TFunction&, TIntermNode* functionBody, TIntermNode*& node); void handleFunctionBody(const TSourceLoc&, TFunction&, TIntermNode* functionBody, TIntermNode*& node);
void remapEntryPointIO(const TFunction& function, TVariable*& returnValue, TVector<TVariable*>& inputs, TVector<TVariable*>& outputs); void remapEntryPointIO(TFunction& function, TVariable*& returnValue, TVector<TVariable*>& inputs, TVector<TVariable*>& outputs);
void remapNonEntryPointIO(TFunction& function); void remapNonEntryPointIO(TFunction& function);
TIntermNode* handleReturnValue(const TSourceLoc&, TIntermTyped*); TIntermNode* handleReturnValue(const TSourceLoc&, TIntermTyped*);
void handleFunctionArgument(TFunction*, TIntermTyped*& arguments, TIntermTyped* newArg); void handleFunctionArgument(TFunction*, TIntermTyped*& arguments, TIntermTyped* newArg);
...@@ -131,6 +131,7 @@ public: ...@@ -131,6 +131,7 @@ public:
const TFunction* findFunction(const TSourceLoc& loc, TFunction& call, bool& builtIn, TIntermTyped*& args); const TFunction* findFunction(const TSourceLoc& loc, TFunction& call, bool& builtIn, TIntermTyped*& args);
void declareTypedef(const TSourceLoc&, TString& identifier, const TType&, TArraySizes* typeArray = 0); void declareTypedef(const TSourceLoc&, TString& identifier, const TType&, TArraySizes* typeArray = 0);
void declareStruct(const TSourceLoc&, TString& structName, TType&);
TIntermNode* declareVariable(const TSourceLoc&, TString& identifier, TType&, TIntermTyped* initializer = 0); TIntermNode* declareVariable(const TSourceLoc&, TString& identifier, TType&, TIntermTyped* initializer = 0);
void lengthenList(const TSourceLoc&, TIntermSequence& list, int size); void lengthenList(const TSourceLoc&, TIntermSequence& list, int size);
TIntermTyped* addConstructor(const TSourceLoc&, TIntermNode*, const TType&); TIntermTyped* addConstructor(const TSourceLoc&, TIntermNode*, const TType&);
...@@ -230,10 +231,6 @@ protected: ...@@ -230,10 +231,6 @@ protected:
int flattenStruct(const TSourceLoc& loc, const TVariable& variable, const TType&, TFlattenData&, TString name); int flattenStruct(const TSourceLoc& loc, const TVariable& variable, const TType&, TFlattenData&, TString name);
int flattenArray(const TSourceLoc& loc, const TVariable& variable, const TType&, TFlattenData&, TString name); int flattenArray(const TSourceLoc& loc, const TVariable& variable, const TType&, TFlattenData&, TString name);
// Create a non-IO type from an IO type. If there is no IO data, this returns the input type unmodified.
// Otherwise, it modifies the type in place, and returns a pointer to it.
void makeTypeNonIo(TType*);
void finish() override; // post-processing void finish() override; // post-processing
// Current state of parsing // Current state of parsing
...@@ -299,9 +296,8 @@ protected: ...@@ -299,9 +296,8 @@ protected:
TVector<int> flattenLevel; // nested postfix operator level for flattening TVector<int> flattenLevel; // nested postfix operator level for flattening
TVector<int> flattenOffset; // cumulative offset for flattening TVector<int> flattenOffset; // cumulative offset for flattening
// Sanitized type map. If the same type is sanitized again, we want to reuse it. // IO-type map.
// We cannot index by the TType: the map is typelist to typelist. TMap<const TTypeList*, TTypeList*> ioTypeMap;
TMap<const TTypeList*, TTypeList*> nonIoTypeMap;
// Structure splitting data: // Structure splitting data:
TMap<int, TVariable*> splitIoVars; // variables with the builtin interstage IO removed, indexed by unique ID. TMap<int, TVariable*> splitIoVars; // variables with the builtin interstage IO removed, indexed by unique ID.
......
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