Merge pull request #306 from johnkslang/finish-spec-const-semantics
Vulkan: Finish semantics for what creates spec-const-semantics.
This commit is contained in:
commit
0c968f9d0e
16 changed files with 610 additions and 245 deletions
|
|
@ -922,6 +922,7 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* true
|
|||
TIntermConstantUnion* TIntermediate::addConstantUnion(const TConstUnionArray& unionArray, const TType& t, const TSourceLoc& loc, bool literal) const
|
||||
{
|
||||
TIntermConstantUnion* node = new TIntermConstantUnion(unionArray, t);
|
||||
node->getQualifier().storage = EvqConst;
|
||||
node->setLoc(loc);
|
||||
if (literal)
|
||||
node->setLiteral();
|
||||
|
|
@ -1165,20 +1166,44 @@ void TIntermediate::removeTree()
|
|||
//
|
||||
// "5.x Specialization Constant Operations"
|
||||
//
|
||||
// ...
|
||||
// Only some operations discussed in this section may be applied to a
|
||||
// specialization constant and still yield a result that is as
|
||||
// specialization constant. The operations allowed are listed below.
|
||||
// When a specialization constant is operated on with one of these
|
||||
// operators and with another constant or specialization constant, the
|
||||
// result is implicitly a specialization constant.
|
||||
//
|
||||
// It also needs to allow basic construction, swizzling, and indexing
|
||||
// operations.
|
||||
// - int(), uint(), and bool() constructors for type conversions
|
||||
// from any of the following types to any of the following types:
|
||||
// * int
|
||||
// * uint
|
||||
// * bool
|
||||
// - vector versions of the above conversion constructors
|
||||
// - allowed implicit conversions of the above
|
||||
// - swizzles (e.g., foo.yx)
|
||||
// - The following when applied to integer or unsigned integer types:
|
||||
// * unary negative ( - )
|
||||
// * binary operations ( + , - , * , / , % )
|
||||
// * shift ( <<, >> )
|
||||
// * bitwise operations ( & , | , ^ )
|
||||
// - The following when applied to integer or unsigned integer scalar types:
|
||||
// * comparison ( == , != , > , >= , < , <= )
|
||||
// - The following when applied to the Boolean scalar type:
|
||||
// * not ( ! )
|
||||
// * logical operations ( && , || , ^^ )
|
||||
// * comparison ( == , != )"
|
||||
//
|
||||
// This function just handles binary and unary nodes. Construction
|
||||
// rules are handled in construction paths that are not covered by the unary
|
||||
// and binary paths, while required conversions will still show up here
|
||||
// as unary converters in the from a construction operator.
|
||||
//
|
||||
bool TIntermediate::isSpecializationOperation(const TIntermOperator& node) const
|
||||
{
|
||||
// allow construction
|
||||
if (node.isConstructor())
|
||||
return true;
|
||||
|
||||
// The set for floating point is quite limited
|
||||
if (node.getBasicType() == EbtFloat ||
|
||||
node.getBasicType() == EbtDouble) {
|
||||
// The operations resulting in floating point are quite limited
|
||||
// (However, some floating-point operations result in bool, like ">",
|
||||
// so are handled later.)
|
||||
if (node.getType().isFloatingDomain()) {
|
||||
switch (node.getOp()) {
|
||||
case EOpIndexDirect:
|
||||
case EOpIndexIndirect:
|
||||
|
|
@ -1190,7 +1215,14 @@ bool TIntermediate::isSpecializationOperation(const TIntermOperator& node) const
|
|||
}
|
||||
}
|
||||
|
||||
// Floating-point is out of the way.
|
||||
// Check for floating-point arguments
|
||||
if (const TIntermBinary* bin = node.getAsBinaryNode())
|
||||
if (bin->getLeft() ->getType().isFloatingDomain() ||
|
||||
bin->getRight()->getType().isFloatingDomain())
|
||||
return false;
|
||||
|
||||
// So, for now, we can assume everything left is non-floating-point...
|
||||
|
||||
// Now check for integer/bool-based operations
|
||||
switch (node.getOp()) {
|
||||
|
||||
|
|
|
|||
|
|
@ -2208,6 +2208,18 @@ bool TParseContext::builtInName(const TString& identifier)
|
|||
// constructor to build something of the type of the constructor. Also returns
|
||||
// the type of the constructor.
|
||||
//
|
||||
// Part of establishing type is establishing specialization-constness.
|
||||
// We don't yet know "top down" whether type is a specialization constant,
|
||||
// but a const constructor can becomes a specialization constant if any of
|
||||
// its children are, subject to KHR_vulkan_glsl rules:
|
||||
//
|
||||
// - int(), uint(), and bool() constructors for type conversions
|
||||
// from any of the following types to any of the following types:
|
||||
// * int
|
||||
// * uint
|
||||
// * bool
|
||||
// - vector versions of the above conversion constructors
|
||||
//
|
||||
// Returns true if there was an error in construction.
|
||||
//
|
||||
bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, TFunction& function, TOperator op, TType& type)
|
||||
|
|
@ -2253,6 +2265,7 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
|
|||
bool overFull = false;
|
||||
bool matrixInMatrix = false;
|
||||
bool arrayArg = false;
|
||||
bool floatArgument = false;
|
||||
for (int arg = 0; arg < function.getParamCount(); ++arg) {
|
||||
if (function[arg].type->isArray()) {
|
||||
if (! function[arg].type->isExplicitlySizedArray()) {
|
||||
|
|
@ -2281,11 +2294,52 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
|
|||
constType = false;
|
||||
if (function[arg].type->getQualifier().isSpecConstant())
|
||||
specConstType = true;
|
||||
if (function[arg].type->isFloatingDomain())
|
||||
floatArgument = true;
|
||||
}
|
||||
|
||||
// inherit constness from children
|
||||
if (constType) {
|
||||
if (specConstType)
|
||||
bool makeSpecConst;
|
||||
// Finish pinning down spec-const semantics
|
||||
if (specConstType) {
|
||||
switch (op) {
|
||||
case EOpConstructInt:
|
||||
case EOpConstructUint:
|
||||
case EOpConstructInt64:
|
||||
case EOpConstructUint64:
|
||||
case EOpConstructBool:
|
||||
case EOpConstructBVec2:
|
||||
case EOpConstructBVec3:
|
||||
case EOpConstructBVec4:
|
||||
case EOpConstructIVec2:
|
||||
case EOpConstructIVec3:
|
||||
case EOpConstructIVec4:
|
||||
case EOpConstructUVec2:
|
||||
case EOpConstructUVec3:
|
||||
case EOpConstructUVec4:
|
||||
case EOpConstructI64Vec2:
|
||||
case EOpConstructI64Vec3:
|
||||
case EOpConstructI64Vec4:
|
||||
case EOpConstructU64Vec2:
|
||||
case EOpConstructU64Vec3:
|
||||
case EOpConstructU64Vec4:
|
||||
// This was the list of valid ones, if they aren't converting from float
|
||||
// and aren't making an array.
|
||||
makeSpecConst = ! floatArgument && ! type.isArray();
|
||||
break;
|
||||
default:
|
||||
// anything else wasn't white-listed in the spec as a conversion
|
||||
makeSpecConst = false;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
makeSpecConst = false;
|
||||
|
||||
if (makeSpecConst)
|
||||
type.getQualifier().makeSpecConstant();
|
||||
else if (specConstType)
|
||||
type.getQualifier().makeTemporary();
|
||||
else
|
||||
type.getQualifier().storage = EvqConst;
|
||||
}
|
||||
|
|
@ -4941,7 +4995,14 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||
// constructor-style subtree, allowing the rest of the code to operate
|
||||
// identically for both kinds of initializers.
|
||||
//
|
||||
initializer = convertInitializerList(loc, variable->getType(), initializer);
|
||||
// Type can't be deduced from the initializer list, so a skeletal type to
|
||||
// follow has to be passed in. Constness and specialization-constness
|
||||
// should be deduced bottom up, not dictated by the skeletal type.
|
||||
//
|
||||
TType skeletalType;
|
||||
skeletalType.shallowCopy(variable->getType());
|
||||
skeletalType.getQualifier().makeTemporary();
|
||||
initializer = convertInitializerList(loc, skeletalType, initializer);
|
||||
if (! initializer) {
|
||||
// error recovery; don't leave const without constant values
|
||||
if (qualifier == EvqConst)
|
||||
|
|
@ -5030,7 +5091,7 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||
// normal assigning of a value to a variable...
|
||||
specializationCheck(loc, initializer->getType(), "initializer");
|
||||
TIntermSymbol* intermSymbol = intermediate.addSymbol(*variable, loc);
|
||||
TIntermNode* initNode = intermediate.addAssign(EOpAssign, intermSymbol, initializer, loc);
|
||||
TIntermTyped* initNode = intermediate.addAssign(EOpAssign, intermSymbol, initializer, loc);
|
||||
if (! initNode)
|
||||
assignError(loc, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
|
||||
|
||||
|
|
@ -5041,11 +5102,14 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||
}
|
||||
|
||||
//
|
||||
// Reprocess any initializer-list { ... } parts of the initializer.
|
||||
// Reprocess any initializer-list (the "{ ... }" syntax) parts of the
|
||||
// initializer.
|
||||
//
|
||||
// Need to hierarchically assign correct types and implicit
|
||||
// conversions. Will do this mimicking the same process used for
|
||||
// creating a constructor-style initializer, ensuring we get the
|
||||
// same form.
|
||||
// same form. However, it has to in parallel walk the 'type'
|
||||
// passed in, as type cannot be deduced from an initializer list.
|
||||
//
|
||||
TIntermTyped* TParseContext::convertInitializerList(const TSourceLoc& loc, const TType& type, TIntermTyped* initializer)
|
||||
{
|
||||
|
|
@ -5191,12 +5255,6 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode*
|
|||
// for each parameter to the constructor call, check to see if the right type is passed or convert them
|
||||
// to the right type if possible (and allowed).
|
||||
// for structure constructors, just check if the right type is passed, no conversion is allowed.
|
||||
|
||||
// We don't know "top down" whether type is a specialization constant,
|
||||
// but a const becomes a specialization constant if any of its children are.
|
||||
bool hasSpecConst = false;
|
||||
bool isConstConstrutor = true;
|
||||
|
||||
for (TIntermSequence::iterator p = sequenceVector.begin();
|
||||
p != sequenceVector.end(); p++, paramCount++) {
|
||||
if (type.isArray())
|
||||
|
|
@ -5206,21 +5264,13 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode*
|
|||
else
|
||||
newNode = constructBuiltIn(type, op, (*p)->getAsTyped(), node->getLoc(), true);
|
||||
|
||||
if (newNode) {
|
||||
if (newNode)
|
||||
*p = newNode;
|
||||
if (! newNode->getType().getQualifier().isConstant())
|
||||
isConstConstrutor = false;
|
||||
if (newNode->getType().getQualifier().isSpecConstant())
|
||||
hasSpecConst = true;
|
||||
} else
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, type, loc);
|
||||
if (isConstConstrutor && hasSpecConst)
|
||||
constructor->getWritableType().getQualifier().makeSpecConstant();
|
||||
|
||||
return constructor;
|
||||
return intermediate.setAggregateOperator(aggrNode, op, type, loc);
|
||||
}
|
||||
|
||||
// Function for constructor implementation. Calls addUnaryMath with appropriate EOp value
|
||||
|
|
|
|||
|
|
@ -346,7 +346,6 @@ protected:
|
|||
static int getBaseAlignmentScalar(const TType&, int& size);
|
||||
bool isSpecializationOperation(const TIntermOperator&) const;
|
||||
|
||||
|
||||
const EShLanguage language; // stage, known at construction time
|
||||
EShSource source; // source language, known a bit later
|
||||
std::string entryPoint;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue