Merge branch 'master' of github.com:KhronosGroup/glslang into clang-format
This commit is contained in:
commit
5797975686
@ -128,8 +128,9 @@ protected:
|
|||||||
void addDecoration(spv::Id id, spv::Decoration dec, unsigned value);
|
void addDecoration(spv::Id id, spv::Decoration dec, unsigned value);
|
||||||
void addMemberDecoration(spv::Id id, int member, spv::Decoration dec);
|
void addMemberDecoration(spv::Id id, int member, spv::Decoration dec);
|
||||||
void addMemberDecoration(spv::Id id, int member, spv::Decoration dec, unsigned value);
|
void addMemberDecoration(spv::Id id, int member, spv::Decoration dec, unsigned value);
|
||||||
spv::Id createSpvSpecConstant(const glslang::TIntermTyped&);
|
spv::Id createSpvConstant(const glslang::TIntermTyped&);
|
||||||
spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant);
|
spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant);
|
||||||
|
spv::Id createSpvConstantFromConstSubTree(const glslang::TIntermTyped* subTree);
|
||||||
bool isTrivialLeaf(const glslang::TIntermTyped* node);
|
bool isTrivialLeaf(const glslang::TIntermTyped* node);
|
||||||
bool isTrivial(const glslang::TIntermTyped* node);
|
bool isTrivial(const glslang::TIntermTyped* node);
|
||||||
spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);
|
spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);
|
||||||
@ -719,6 +720,7 @@ void TGlslangToSpvTraverser::dumpSpv(std::vector<unsigned int>& out)
|
|||||||
for (auto it = iOSet.cbegin(); it != iOSet.cend(); ++it)
|
for (auto it = iOSet.cbegin(); it != iOSet.cend(); ++it)
|
||||||
entryPoint->addIdOperand(*it);
|
entryPoint->addIdOperand(*it);
|
||||||
|
|
||||||
|
builder.eliminateDeadDecorations();
|
||||||
builder.dump(out);
|
builder.dump(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1519,7 +1521,7 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T
|
|||||||
void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
|
void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
|
||||||
{
|
{
|
||||||
int nextConst = 0;
|
int nextConst = 0;
|
||||||
spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst, false);
|
spv::Id constant = createSpvConstantFromConstUnionArray(node->getType(), node->getConstArray(), nextConst, false);
|
||||||
|
|
||||||
builder.clearAccessChain();
|
builder.clearAccessChain();
|
||||||
builder.setAccessChainRValue(constant);
|
builder.setAccessChainRValue(constant);
|
||||||
@ -1628,8 +1630,8 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol*
|
|||||||
// First, steer off constants, which are not SPIR-V variables, but
|
// First, steer off constants, which are not SPIR-V variables, but
|
||||||
// can still have a mapping to a SPIR-V Id.
|
// can still have a mapping to a SPIR-V Id.
|
||||||
// This includes specialization constants.
|
// This includes specialization constants.
|
||||||
if (node->getQualifier().storage == glslang::EvqConst) {
|
if (node->getQualifier().isConstant()) {
|
||||||
return createSpvSpecConstant(*node);
|
return createSpvConstant(*node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, handle actual variables
|
// Now, handle actual variables
|
||||||
@ -3434,11 +3436,12 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
|
|||||||
builder.promoteScalar(precision, operands.front(), operands[2]);
|
builder.promoteScalar(precision, operands.front(), operands[2]);
|
||||||
break;
|
break;
|
||||||
case glslang::EOpMix:
|
case glslang::EOpMix:
|
||||||
if (isFloat)
|
if (! builder.isBoolType(builder.getScalarTypeId(builder.getTypeId(operands.back())))) {
|
||||||
|
assert(isFloat);
|
||||||
libCall = spv::GLSLstd450FMix;
|
libCall = spv::GLSLstd450FMix;
|
||||||
else {
|
} else {
|
||||||
opCode = spv::OpSelect;
|
opCode = spv::OpSelect;
|
||||||
spv::MissingFunctionality("translating integer mix to OpSelect");
|
std::swap(operands.front(), operands.back());
|
||||||
}
|
}
|
||||||
builder.promoteScalar(precision, operands.front(), operands.back());
|
builder.promoteScalar(precision, operands.front(), operands.back());
|
||||||
break;
|
break;
|
||||||
@ -3728,15 +3731,15 @@ void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::De
|
|||||||
// recursively walks. So, this function walks the "top" of the tree:
|
// recursively walks. So, this function walks the "top" of the tree:
|
||||||
// - emit specialization constant-building instructions for specConstant
|
// - emit specialization constant-building instructions for specConstant
|
||||||
// - when running into a non-spec-constant, switch to createSpvConstant()
|
// - when running into a non-spec-constant, switch to createSpvConstant()
|
||||||
spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermTyped& node)
|
spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TIntermTyped& node)
|
||||||
{
|
{
|
||||||
assert(node.getQualifier().storage == glslang::EvqConst);
|
assert(node.getQualifier().isConstant());
|
||||||
|
|
||||||
if (! node.getQualifier().specConstant) {
|
if (! node.getQualifier().specConstant) {
|
||||||
// hand off to the non-spec-constant path
|
// hand off to the non-spec-constant path
|
||||||
assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr);
|
assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr);
|
||||||
int nextConst = 0;
|
int nextConst = 0;
|
||||||
return createSpvConstant(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
|
return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
|
||||||
nextConst, false);
|
nextConst, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3745,7 +3748,7 @@ spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermType
|
|||||||
if (node.getAsSymbolNode() && node.getQualifier().hasSpecConstantId()) {
|
if (node.getAsSymbolNode() && node.getQualifier().hasSpecConstantId()) {
|
||||||
// this is a direct literal assigned to a layout(constant_id=) declaration
|
// this is a direct literal assigned to a layout(constant_id=) declaration
|
||||||
int nextConst = 0;
|
int nextConst = 0;
|
||||||
return createSpvConstant(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
|
return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
|
||||||
nextConst, true);
|
nextConst, true);
|
||||||
} else {
|
} else {
|
||||||
// gl_WorkgroupSize is a special case until the front-end handles hierarchical specialization constants,
|
// gl_WorkgroupSize is a special case until the front-end handles hierarchical specialization constants,
|
||||||
@ -3759,8 +3762,11 @@ spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermType
|
|||||||
addDecoration(dimConstId.back(), spv::DecorationSpecId, glslangIntermediate->getLocalSizeSpecId(dim));
|
addDecoration(dimConstId.back(), spv::DecorationSpecId, glslangIntermediate->getLocalSizeSpecId(dim));
|
||||||
}
|
}
|
||||||
return builder.makeCompositeConstant(builder.makeVectorType(builder.makeUintType(32), 3), dimConstId, true);
|
return builder.makeCompositeConstant(builder.makeVectorType(builder.makeUintType(32), 3), dimConstId, true);
|
||||||
|
} else if (auto* sn = node.getAsSymbolNode()){
|
||||||
|
return createSpvConstantFromConstSubTree(sn->getConstSubtree());
|
||||||
} else {
|
} else {
|
||||||
spv::MissingFunctionality("specialization-constant expression trees");
|
spv::MissingFunctionality("Neither a front-end constant nor a spec constant.");
|
||||||
|
exit(1);
|
||||||
return spv::NoResult;
|
return spv::NoResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3772,7 +3778,7 @@ spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermType
|
|||||||
// If there are not enough elements present in 'consts', 0 will be substituted;
|
// If there are not enough elements present in 'consts', 0 will be substituted;
|
||||||
// an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
|
// an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
|
||||||
//
|
//
|
||||||
spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant)
|
spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant)
|
||||||
{
|
{
|
||||||
// vector of constants for SPIR-V
|
// vector of constants for SPIR-V
|
||||||
std::vector<spv::Id> spvConsts;
|
std::vector<spv::Id> spvConsts;
|
||||||
@ -3783,15 +3789,15 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangT
|
|||||||
if (glslangType.isArray()) {
|
if (glslangType.isArray()) {
|
||||||
glslang::TType elementType(glslangType, 0);
|
glslang::TType elementType(glslangType, 0);
|
||||||
for (int i = 0; i < glslangType.getOuterArraySize(); ++i)
|
for (int i = 0; i < glslangType.getOuterArraySize(); ++i)
|
||||||
spvConsts.push_back(createSpvConstant(elementType, consts, nextConst, false));
|
spvConsts.push_back(createSpvConstantFromConstUnionArray(elementType, consts, nextConst, false));
|
||||||
} else if (glslangType.isMatrix()) {
|
} else if (glslangType.isMatrix()) {
|
||||||
glslang::TType vectorType(glslangType, 0);
|
glslang::TType vectorType(glslangType, 0);
|
||||||
for (int col = 0; col < glslangType.getMatrixCols(); ++col)
|
for (int col = 0; col < glslangType.getMatrixCols(); ++col)
|
||||||
spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst, false));
|
spvConsts.push_back(createSpvConstantFromConstUnionArray(vectorType, consts, nextConst, false));
|
||||||
} else if (glslangType.getStruct()) {
|
} else if (glslangType.getStruct()) {
|
||||||
glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
|
glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
|
||||||
for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
|
for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
|
||||||
spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst, false));
|
spvConsts.push_back(createSpvConstantFromConstUnionArray(*iter->type, consts, nextConst, false));
|
||||||
} else if (glslangType.isVector()) {
|
} else if (glslangType.isVector()) {
|
||||||
for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {
|
for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {
|
||||||
bool zero = nextConst >= consts.size();
|
bool zero = nextConst >= consts.size();
|
||||||
@ -3848,6 +3854,66 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangT
|
|||||||
return builder.makeCompositeConstant(typeId, spvConsts);
|
return builder.makeCompositeConstant(typeId, spvConsts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create constant ID from const initializer sub tree.
|
||||||
|
spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstSubTree(
|
||||||
|
const glslang::TIntermTyped* subTree) {
|
||||||
|
const glslang::TType& glslangType = subTree->getType();
|
||||||
|
spv::Id typeId = convertGlslangToSpvType(glslangType);
|
||||||
|
bool is_spec_const = subTree->getType().getQualifier().isSpecConstant();
|
||||||
|
if (const glslang::TIntermAggregate* an = subTree->getAsAggregate()) {
|
||||||
|
// Aggregate node, we should generate OpConstantComposite or
|
||||||
|
// OpSpecConstantComposite instruction.
|
||||||
|
std::vector<spv::Id> const_constituents;
|
||||||
|
for (auto NI = an->getSequence().begin(); NI != an->getSequence().end();
|
||||||
|
NI++) {
|
||||||
|
const_constituents.push_back(
|
||||||
|
createSpvConstantFromConstSubTree((*NI)->getAsTyped()));
|
||||||
|
}
|
||||||
|
// Note that constructors are aggregate nodes, so expressions like:
|
||||||
|
// float x = float(y) will become an aggregate node. If 'x' is declared
|
||||||
|
// as a constant, the aggregate node representing 'float(y)' will be
|
||||||
|
// processed here.
|
||||||
|
if (builder.isVectorType(typeId) || builder.isMatrixType(typeId) ||
|
||||||
|
builder.isAggregateType(typeId)) {
|
||||||
|
return builder.makeCompositeConstant(typeId, const_constituents, is_spec_const);
|
||||||
|
} else {
|
||||||
|
assert(builder.isScalarType(typeId) && const_constituents.size() == 1);
|
||||||
|
return const_constituents.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (const glslang::TIntermBinary* bn = subTree->getAsBinaryNode()) {
|
||||||
|
// Binary operation node, we should generate OpSpecConstantOp <binary op>
|
||||||
|
// This case should only happen when Specialization Constants are involved.
|
||||||
|
spv::MissingFunctionality("OpSpecConstantOp <binary op> not implemented");
|
||||||
|
return spv::NoResult;
|
||||||
|
|
||||||
|
} else if (const glslang::TIntermUnary* un = subTree->getAsUnaryNode()) {
|
||||||
|
// Unary operation node, similar to binary operation node, should only
|
||||||
|
// happen when specialization constants are involved.
|
||||||
|
spv::MissingFunctionality("OpSpecConstantOp <unary op> not implemented");
|
||||||
|
return spv::NoResult;
|
||||||
|
|
||||||
|
} else if (const glslang::TIntermConstantUnion* cn = subTree->getAsConstantUnion()) {
|
||||||
|
// ConstantUnion node, should redirect to
|
||||||
|
// createSpvConstantFromConstUnionArray
|
||||||
|
int nextConst = 0;
|
||||||
|
return createSpvConstantFromConstUnionArray(
|
||||||
|
glslangType, cn->getConstArray(), nextConst, is_spec_const);
|
||||||
|
|
||||||
|
} else if (const glslang::TIntermSymbol* sn = subTree->getAsSymbolNode()) {
|
||||||
|
// Symbol node. Call getSymbolId(). This should cover both cases 1) the
|
||||||
|
// symbol has already been assigned an ID, 2) need a new ID for this
|
||||||
|
// symbol.
|
||||||
|
return getSymbolId(sn);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
spv::MissingFunctionality(
|
||||||
|
"createSpvConstantFromConstSubTree() not covered TIntermTyped* const "
|
||||||
|
"initializer subtree.");
|
||||||
|
return spv::NoResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Return true if the node is a constant or symbol whose reading has no
|
// Return true if the node is a constant or symbol whose reading has no
|
||||||
// non-trivial observable cost or effect.
|
// non-trivial observable cost or effect.
|
||||||
bool TGlslangToSpvTraverser::isTrivialLeaf(const glslang::TIntermTyped* node)
|
bool TGlslangToSpvTraverser::isTrivialLeaf(const glslang::TIntermTyped* node)
|
||||||
|
|||||||
@ -2234,6 +2234,45 @@ Id Builder::accessChainGetInferredType()
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// comment in header
|
||||||
|
void Builder::eliminateDeadDecorations()
|
||||||
|
{
|
||||||
|
std::unordered_set<const Block*> reachable_blocks;
|
||||||
|
std::unordered_set<Id> unreachable_definitions;
|
||||||
|
// Collect IDs defined in unreachable blocks. For each function, label the
|
||||||
|
// reachable blocks first. Then for each unreachable block, collect the
|
||||||
|
// result IDs of the instructions in it.
|
||||||
|
for (std::vector<Function*>::const_iterator fi = module.getFunctions().cbegin();
|
||||||
|
fi != module.getFunctions().cend(); fi++)
|
||||||
|
{
|
||||||
|
Function* f = *fi;
|
||||||
|
Block* entry = f->getEntryBlock();
|
||||||
|
inReadableOrder(entry, [&reachable_blocks](const Block* b) { reachable_blocks.insert(b); });
|
||||||
|
for (std::vector<Block*>::const_iterator bi = f->getBlocks().cbegin();
|
||||||
|
bi != f->getBlocks().cend(); bi++)
|
||||||
|
{
|
||||||
|
Block* b = *bi;
|
||||||
|
if (!reachable_blocks.count(b))
|
||||||
|
{
|
||||||
|
for (std::vector<std::unique_ptr<Instruction> >::const_iterator ii =
|
||||||
|
b->getInstructions().cbegin();
|
||||||
|
ii != b->getInstructions().cend(); ii++)
|
||||||
|
{
|
||||||
|
Instruction* i = ii->get();
|
||||||
|
unreachable_definitions.insert(i->getResultId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
decorations.erase(std::remove_if(decorations.begin(), decorations.end(),
|
||||||
|
[&unreachable_definitions](std::unique_ptr<Instruction>& I) {
|
||||||
|
Instruction* inst = I.get();
|
||||||
|
Id decoration_id = inst->getIdOperand(0);
|
||||||
|
return unreachable_definitions.count(decoration_id) != 0;
|
||||||
|
}),
|
||||||
|
decorations.end());
|
||||||
|
}
|
||||||
|
|
||||||
void Builder::dump(std::vector<unsigned int>& out) const
|
void Builder::dump(std::vector<unsigned int>& out) const
|
||||||
{
|
{
|
||||||
// Header, before first instructions:
|
// Header, before first instructions:
|
||||||
|
|||||||
@ -535,6 +535,9 @@ public:
|
|||||||
// based on the type of the base and the chain of dereferences.
|
// based on the type of the base and the chain of dereferences.
|
||||||
Id accessChainGetInferredType();
|
Id accessChainGetInferredType();
|
||||||
|
|
||||||
|
// Remove OpDecorate instructions whose operands are defined in unreachable
|
||||||
|
// blocks.
|
||||||
|
void eliminateDeadDecorations();
|
||||||
void dump(std::vector<unsigned int>&) const;
|
void dump(std::vector<unsigned int>&) const;
|
||||||
|
|
||||||
void createBranch(Block* block);
|
void createBranch(Block* block);
|
||||||
|
|||||||
@ -182,6 +182,9 @@ public:
|
|||||||
void addLocalVariable(std::unique_ptr<Instruction> inst) { localVariables.push_back(std::move(inst)); }
|
void addLocalVariable(std::unique_ptr<Instruction> inst) { localVariables.push_back(std::move(inst)); }
|
||||||
const std::vector<Block*>& getPredecessors() const { return predecessors; }
|
const std::vector<Block*>& getPredecessors() const { return predecessors; }
|
||||||
const std::vector<Block*>& getSuccessors() const { return successors; }
|
const std::vector<Block*>& getSuccessors() const { return successors; }
|
||||||
|
const std::vector<std::unique_ptr<Instruction> >& getInstructions() const {
|
||||||
|
return instructions;
|
||||||
|
}
|
||||||
void setUnreachable() { unreachable = true; }
|
void setUnreachable() { unreachable = true; }
|
||||||
bool isUnreachable() const { return unreachable; }
|
bool isUnreachable() const { return unreachable; }
|
||||||
// Returns the block's merge instruction, if one exists (otherwise null).
|
// Returns the block's merge instruction, if one exists (otherwise null).
|
||||||
@ -275,6 +278,7 @@ public:
|
|||||||
Module& getParent() const { return parent; }
|
Module& getParent() const { return parent; }
|
||||||
Block* getEntryBlock() const { return blocks.front(); }
|
Block* getEntryBlock() const { return blocks.front(); }
|
||||||
Block* getLastBlock() const { return blocks.back(); }
|
Block* getLastBlock() const { return blocks.back(); }
|
||||||
|
const std::vector<Block*>& getBlocks() const { return blocks; }
|
||||||
void addLocalVariable(std::unique_ptr<Instruction> inst);
|
void addLocalVariable(std::unique_ptr<Instruction> inst);
|
||||||
Id getReturnType() const { return functionInstruction.getTypeId(); }
|
Id getReturnType() const { return functionInstruction.getTypeId(); }
|
||||||
void dump(std::vector<unsigned int>& out) const
|
void dump(std::vector<unsigned int>& out) const
|
||||||
@ -326,6 +330,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Instruction* getInstruction(Id id) const { return idToInstruction[id]; }
|
Instruction* getInstruction(Id id) const { return idToInstruction[id]; }
|
||||||
|
const std::vector<Function*>& getFunctions() const { return functions; }
|
||||||
spv::Id getTypeId(Id resultId) const { return idToInstruction[resultId]->getTypeId(); }
|
spv::Id getTypeId(Id resultId) const { return idToInstruction[resultId]->getTypeId(); }
|
||||||
StorageClass getStorageClass(Id typeId) const
|
StorageClass getStorageClass(Id typeId) const
|
||||||
{
|
{
|
||||||
|
|||||||
@ -699,8 +699,9 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
|
|||||||
|
|
||||||
if (Options & EOptionOutputPreprocessed) {
|
if (Options & EOptionOutputPreprocessed) {
|
||||||
std::string str;
|
std::string str;
|
||||||
|
glslang::TShader::ForbidInclude includer;
|
||||||
if (shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false,
|
if (shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false,
|
||||||
messages, &str, glslang::TShader::ForbidInclude())) {
|
messages, &str, includer)) {
|
||||||
PutsIfNonEmpty(str.c_str());
|
PutsIfNonEmpty(str.c_str());
|
||||||
} else {
|
} else {
|
||||||
CompileFailed = true;
|
CompileFailed = true;
|
||||||
|
|||||||
@ -337,7 +337,7 @@ ERROR: node is still EOpNull!
|
|||||||
0:201 1 (const int)
|
0:201 1 (const int)
|
||||||
0:201 Constant:
|
0:201 Constant:
|
||||||
0:201 2 (const int)
|
0:201 2 (const int)
|
||||||
0:202 Test condition and select (layout(column_major shared ) temp highp float)
|
0:202 Test condition and select (temp highp float)
|
||||||
0:202 Condition
|
0:202 Condition
|
||||||
0:202 'b' (temp bool)
|
0:202 'b' (temp bool)
|
||||||
0:202 true case
|
0:202 true case
|
||||||
@ -764,7 +764,7 @@ ERROR: node is still EOpNull!
|
|||||||
0:201 1 (const int)
|
0:201 1 (const int)
|
||||||
0:201 Constant:
|
0:201 Constant:
|
||||||
0:201 2 (const int)
|
0:201 2 (const int)
|
||||||
0:202 Test condition and select (layout(column_major shared ) temp highp float)
|
0:202 Test condition and select (temp highp float)
|
||||||
0:202 Condition
|
0:202 Condition
|
||||||
0:202 'b' (temp bool)
|
0:202 'b' (temp bool)
|
||||||
0:202 true case
|
0:202 true case
|
||||||
|
|||||||
12
Test/baseResults/preprocessor.many.endif.vert.err
Normal file
12
Test/baseResults/preprocessor.many.endif.vert.err
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
ERROR: 0:1: '#endif' : mismatched statements
|
||||||
|
ERROR: 0:2: '#endif' : mismatched statements
|
||||||
|
ERROR: 0:3: '#endif' : mismatched statements
|
||||||
|
ERROR: 0:4: '#endif' : mismatched statements
|
||||||
|
ERROR: 0:5: '#endif' : mismatched statements
|
||||||
|
ERROR: 0:6: '#endif' : mismatched statements
|
||||||
|
ERROR: 0:7: '#endif' : mismatched statements
|
||||||
|
ERROR: 0:10: 'preprocessor evaluation' : bad expression
|
||||||
|
ERROR: 0:11: '' : missing #endif
|
||||||
|
ERROR: 9 compilation errors. No code generated.
|
||||||
|
|
||||||
|
|
||||||
0
Test/baseResults/preprocessor.many.endif.vert.out
Normal file
0
Test/baseResults/preprocessor.many.endif.vert.out
Normal file
@ -7,7 +7,7 @@ Linked fragment stage:
|
|||||||
|
|
||||||
// Module Version 10000
|
// Module Version 10000
|
||||||
// Generated by (magic number): 80001
|
// Generated by (magic number): 80001
|
||||||
// Id's are bound by 1104
|
// Id's are bound by 1112
|
||||||
|
|
||||||
Capability Shader
|
Capability Shader
|
||||||
Capability Float64
|
Capability Float64
|
||||||
@ -15,7 +15,7 @@ Linked fragment stage:
|
|||||||
Capability SampledRect
|
Capability SampledRect
|
||||||
1: ExtInstImport "GLSL.std.450"
|
1: ExtInstImport "GLSL.std.450"
|
||||||
MemoryModel Logical GLSL450
|
MemoryModel Logical GLSL450
|
||||||
EntryPoint Fragment 4 "main" 13 1025 1031 1036 1048 1074 1095 1097
|
EntryPoint Fragment 4 "main" 13 1025 1031 1036 1048 1074 1095 1097 1103 1105
|
||||||
ExecutionMode 4 OriginUpperLeft
|
ExecutionMode 4 OriginUpperLeft
|
||||||
Source GLSL 400
|
Source GLSL 400
|
||||||
SourceExtension "GL_ARB_separate_shader_objects"
|
SourceExtension "GL_ARB_separate_shader_objects"
|
||||||
@ -52,6 +52,8 @@ Linked fragment stage:
|
|||||||
Name 1078 "isamp2DA"
|
Name 1078 "isamp2DA"
|
||||||
Name 1095 "gl_FragCoord"
|
Name 1095 "gl_FragCoord"
|
||||||
Name 1097 "vl2"
|
Name 1097 "vl2"
|
||||||
|
Name 1103 "uo"
|
||||||
|
Name 1105 "u"
|
||||||
Decorate 17(u2drs) DescriptorSet 0
|
Decorate 17(u2drs) DescriptorSet 0
|
||||||
Decorate 1023(arrayedSampler) DescriptorSet 0
|
Decorate 1023(arrayedSampler) DescriptorSet 0
|
||||||
Decorate 1025(i) Flat
|
Decorate 1025(i) Flat
|
||||||
@ -60,6 +62,7 @@ Linked fragment stage:
|
|||||||
Decorate 1078(isamp2DA) DescriptorSet 0
|
Decorate 1078(isamp2DA) DescriptorSet 0
|
||||||
Decorate 1095(gl_FragCoord) BuiltIn FragCoord
|
Decorate 1095(gl_FragCoord) BuiltIn FragCoord
|
||||||
Decorate 1097(vl2) Location 6
|
Decorate 1097(vl2) Location 6
|
||||||
|
Decorate 1105(u) Flat
|
||||||
2: TypeVoid
|
2: TypeVoid
|
||||||
3: TypeFunction 2
|
3: TypeFunction 2
|
||||||
10: TypeFloat 32
|
10: TypeFloat 32
|
||||||
@ -177,6 +180,10 @@ Linked fragment stage:
|
|||||||
1094: TypePointer Input 11(fvec4)
|
1094: TypePointer Input 11(fvec4)
|
||||||
1095(gl_FragCoord): 1094(ptr) Variable Input
|
1095(gl_FragCoord): 1094(ptr) Variable Input
|
||||||
1097(vl2): 1094(ptr) Variable Input
|
1097(vl2): 1094(ptr) Variable Input
|
||||||
|
1102: TypePointer Output 30(int)
|
||||||
|
1103(uo): 1102(ptr) Variable Output
|
||||||
|
1104: TypePointer Input 30(int)
|
||||||
|
1105(u): 1104(ptr) Variable Input
|
||||||
4(main): 2 Function None 3
|
4(main): 2 Function None 3
|
||||||
5: Label
|
5: Label
|
||||||
1017(v): 1016(ptr) Variable Function
|
1017(v): 1016(ptr) Variable Function
|
||||||
@ -227,8 +234,13 @@ Linked fragment stage:
|
|||||||
1100: 11(fvec4) Load 13(outp)
|
1100: 11(fvec4) Load 13(outp)
|
||||||
1101: 11(fvec4) FAdd 1100 1099
|
1101: 11(fvec4) FAdd 1100 1099
|
||||||
Store 13(outp) 1101
|
Store 13(outp) 1101
|
||||||
1102: 2 FunctionCall 6(foo23()
|
1106: 30(int) Load 1105(u)
|
||||||
1103: 2 FunctionCall 8(doubles()
|
1107: 23(int) Load 1025(i)
|
||||||
|
1108: 30(int) Bitcast 1107
|
||||||
|
1109: 30(int) UMod 1106 1108
|
||||||
|
Store 1103(uo) 1109
|
||||||
|
1110: 2 FunctionCall 6(foo23()
|
||||||
|
1111: 2 FunctionCall 8(doubles()
|
||||||
Return
|
Return
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
6(foo23(): 2 Function None 3
|
6(foo23(): 2 Function None 3
|
||||||
@ -719,28 +731,28 @@ Linked fragment stage:
|
|||||||
424: 37(float) Load 39(doublev)
|
424: 37(float) Load 39(doublev)
|
||||||
425: 37(float) Load 39(doublev)
|
425: 37(float) Load 39(doublev)
|
||||||
429: 426(bool) Load 428(boolv)
|
429: 426(bool) Load 428(boolv)
|
||||||
430: 37(float) ExtInst 1(GLSL.std.450) 46(FMix) 424 425 429
|
430: 37(float) Select 429 425 424
|
||||||
431: 37(float) Load 39(doublev)
|
431: 37(float) Load 39(doublev)
|
||||||
432: 37(float) FAdd 431 430
|
432: 37(float) FAdd 431 430
|
||||||
Store 39(doublev) 432
|
Store 39(doublev) 432
|
||||||
433: 41(fvec2) Load 43(dvec2v)
|
433: 41(fvec2) Load 43(dvec2v)
|
||||||
434: 41(fvec2) Load 43(dvec2v)
|
434: 41(fvec2) Load 43(dvec2v)
|
||||||
438: 435(bvec2) Load 437(bvec2v)
|
438: 435(bvec2) Load 437(bvec2v)
|
||||||
439: 41(fvec2) ExtInst 1(GLSL.std.450) 46(FMix) 433 434 438
|
439: 41(fvec2) Select 438 434 433
|
||||||
440: 41(fvec2) Load 43(dvec2v)
|
440: 41(fvec2) Load 43(dvec2v)
|
||||||
441: 41(fvec2) FAdd 440 439
|
441: 41(fvec2) FAdd 440 439
|
||||||
Store 43(dvec2v) 441
|
Store 43(dvec2v) 441
|
||||||
442: 46(fvec3) Load 48(dvec3v)
|
442: 46(fvec3) Load 48(dvec3v)
|
||||||
443: 46(fvec3) Load 48(dvec3v)
|
443: 46(fvec3) Load 48(dvec3v)
|
||||||
447: 444(bvec3) Load 446(bvec3v)
|
447: 444(bvec3) Load 446(bvec3v)
|
||||||
448: 46(fvec3) ExtInst 1(GLSL.std.450) 46(FMix) 442 443 447
|
448: 46(fvec3) Select 447 443 442
|
||||||
449: 46(fvec3) Load 48(dvec3v)
|
449: 46(fvec3) Load 48(dvec3v)
|
||||||
450: 46(fvec3) FAdd 449 448
|
450: 46(fvec3) FAdd 449 448
|
||||||
Store 48(dvec3v) 450
|
Store 48(dvec3v) 450
|
||||||
451: 51(fvec4) Load 53(dvec4v)
|
451: 51(fvec4) Load 53(dvec4v)
|
||||||
452: 51(fvec4) Load 53(dvec4v)
|
452: 51(fvec4) Load 53(dvec4v)
|
||||||
456: 453(bvec4) Load 455(bvec4v)
|
456: 453(bvec4) Load 455(bvec4v)
|
||||||
457: 51(fvec4) ExtInst 1(GLSL.std.450) 46(FMix) 451 452 456
|
457: 51(fvec4) Select 456 452 451
|
||||||
458: 51(fvec4) Load 53(dvec4v)
|
458: 51(fvec4) Load 53(dvec4v)
|
||||||
459: 51(fvec4) FAdd 458 457
|
459: 51(fvec4) FAdd 458 457
|
||||||
Store 53(dvec4v) 459
|
Store 53(dvec4v) 459
|
||||||
|
|||||||
@ -281,7 +281,7 @@ Linked fragment stage:
|
|||||||
176: 7(fvec4) Load 9(v)
|
176: 7(fvec4) Load 9(v)
|
||||||
177: 7(fvec4) Load 9(v)
|
177: 7(fvec4) Load 9(v)
|
||||||
182: 179(bvec4) Load 181(ub41)
|
182: 179(bvec4) Load 181(ub41)
|
||||||
183: 7(fvec4) ExtInst 1(GLSL.std.450) 46(FMix) 176 177 182
|
183: 7(fvec4) Select 182 177 176
|
||||||
184: 7(fvec4) Load 9(v)
|
184: 7(fvec4) Load 9(v)
|
||||||
185: 7(fvec4) FAdd 184 183
|
185: 7(fvec4) FAdd 184 183
|
||||||
Store 9(v) 185
|
Store 9(v) 185
|
||||||
|
|||||||
64
Test/baseResults/spv.noDeadDecorations.vert.out
Normal file
64
Test/baseResults/spv.noDeadDecorations.vert.out
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
spv.noDeadDecorations.vert
|
||||||
|
Warning, version 310 is not yet complete; most version-specific features are present, but some are missing.
|
||||||
|
|
||||||
|
|
||||||
|
Linked vertex stage:
|
||||||
|
|
||||||
|
|
||||||
|
// Module Version 10000
|
||||||
|
// Generated by (magic number): 80001
|
||||||
|
// Id's are bound by 32
|
||||||
|
|
||||||
|
Capability Shader
|
||||||
|
1: ExtInstImport "GLSL.std.450"
|
||||||
|
MemoryModel Logical GLSL450
|
||||||
|
EntryPoint Vertex 4 "main" 22
|
||||||
|
Source ESSL 310
|
||||||
|
Name 4 "main"
|
||||||
|
Name 10 "func(f1;"
|
||||||
|
Name 9 "a"
|
||||||
|
Name 20 "gl_PerVertex"
|
||||||
|
MemberName 20(gl_PerVertex) 0 "gl_Position"
|
||||||
|
MemberName 20(gl_PerVertex) 1 "gl_PointSize"
|
||||||
|
Name 22 ""
|
||||||
|
Name 26 "param"
|
||||||
|
Decorate 10(func(f1;) RelaxedPrecision
|
||||||
|
Decorate 9(a) RelaxedPrecision
|
||||||
|
Decorate 12 RelaxedPrecision
|
||||||
|
Decorate 13 RelaxedPrecision
|
||||||
|
MemberDecorate 20(gl_PerVertex) 0 BuiltIn Position
|
||||||
|
MemberDecorate 20(gl_PerVertex) 1 BuiltIn PointSize
|
||||||
|
Decorate 20(gl_PerVertex) Block
|
||||||
|
Decorate 27 RelaxedPrecision
|
||||||
|
2: TypeVoid
|
||||||
|
3: TypeFunction 2
|
||||||
|
6: TypeFloat 32
|
||||||
|
7: TypePointer Function 6(float)
|
||||||
|
8: TypeFunction 6(float) 7(ptr)
|
||||||
|
16: 6(float) Constant 3212836864
|
||||||
|
19: TypeVector 6(float) 4
|
||||||
|
20(gl_PerVertex): TypeStruct 19(fvec4) 6(float)
|
||||||
|
21: TypePointer Output 20(gl_PerVertex)
|
||||||
|
22: 21(ptr) Variable Output
|
||||||
|
23: TypeInt 32 1
|
||||||
|
24: 23(int) Constant 0
|
||||||
|
25: 6(float) Constant 0
|
||||||
|
28: TypeInt 32 0
|
||||||
|
29: 28(int) Constant 0
|
||||||
|
30: TypePointer Output 6(float)
|
||||||
|
4(main): 2 Function None 3
|
||||||
|
5: Label
|
||||||
|
26(param): 7(ptr) Variable Function
|
||||||
|
Store 26(param) 25
|
||||||
|
27: 6(float) FunctionCall 10(func(f1;) 26(param)
|
||||||
|
31: 30(ptr) AccessChain 22 24 29
|
||||||
|
Store 31 27
|
||||||
|
Return
|
||||||
|
FunctionEnd
|
||||||
|
10(func(f1;): 6(float) Function None 8
|
||||||
|
9(a): 7(ptr) FunctionParameter
|
||||||
|
11: Label
|
||||||
|
12: 6(float) Load 9(a)
|
||||||
|
13: 6(float) FNegate 12
|
||||||
|
ReturnValue 13
|
||||||
|
FunctionEnd
|
||||||
172
Test/baseResults/spv.specConstantComposite.vert.out
Normal file
172
Test/baseResults/spv.specConstantComposite.vert.out
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
spv.specConstantComposite.vert
|
||||||
|
Warning, version 450 is not yet complete; most version-specific features are present, but some are missing.
|
||||||
|
|
||||||
|
|
||||||
|
Linked vertex stage:
|
||||||
|
|
||||||
|
|
||||||
|
// Module Version 10000
|
||||||
|
// Generated by (magic number): 80001
|
||||||
|
// Id's are bound by 106
|
||||||
|
|
||||||
|
Capability Shader
|
||||||
|
Capability Float64
|
||||||
|
1: ExtInstImport "GLSL.std.450"
|
||||||
|
MemoryModel Logical GLSL450
|
||||||
|
EntryPoint Vertex 4 "main" 27 105
|
||||||
|
Source GLSL 450
|
||||||
|
Name 4 "main"
|
||||||
|
Name 6 "refer_primary_spec_const("
|
||||||
|
Name 8 "refer_composite_spec_const("
|
||||||
|
Name 10 "refer_copmosite_dot_dereference("
|
||||||
|
Name 12 "refer_composite_bracket_dereference("
|
||||||
|
Name 16 "refer_spec_const_array_length("
|
||||||
|
Name 18 "declare_spec_const_in_func("
|
||||||
|
Name 27 "color"
|
||||||
|
Name 41 "flat_struct"
|
||||||
|
MemberName 41(flat_struct) 0 "i"
|
||||||
|
MemberName 41(flat_struct) 1 "f"
|
||||||
|
MemberName 41(flat_struct) 2 "d"
|
||||||
|
MemberName 41(flat_struct) 3 "b"
|
||||||
|
Name 42 "nesting_struct"
|
||||||
|
MemberName 42(nesting_struct) 0 "nested"
|
||||||
|
MemberName 42(nesting_struct) 1 "v"
|
||||||
|
MemberName 42(nesting_struct) 2 "i"
|
||||||
|
Name 72 "indexable"
|
||||||
|
Name 76 "indexable"
|
||||||
|
Name 83 "len"
|
||||||
|
Name 105 "global_vec4_array_with_spec_length"
|
||||||
|
Decorate 21 SpecId 203
|
||||||
|
Decorate 28 SpecId 200
|
||||||
|
Decorate 32 SpecId 201
|
||||||
|
Decorate 43 SpecId 202
|
||||||
|
2: TypeVoid
|
||||||
|
3: TypeFunction 2
|
||||||
|
14: TypeInt 32 1
|
||||||
|
15: TypeFunction 14(int)
|
||||||
|
20: TypeBool
|
||||||
|
21: 20(bool) SpecConstantTrue
|
||||||
|
24: TypeFloat 32
|
||||||
|
25: TypeVector 24(float) 4
|
||||||
|
26: TypePointer Output 25(fvec4)
|
||||||
|
27(color): 26(ptr) Variable Output
|
||||||
|
28: 14(int) SpecConstant 3
|
||||||
|
32: 24(float) SpecConstant 1078523331
|
||||||
|
33: 25(fvec4) SpecConstantComposite 32 32 32 32
|
||||||
|
36: 24(float) Constant 1133908460
|
||||||
|
37: 25(fvec4) SpecConstantComposite 32 32 36 36
|
||||||
|
40: TypeFloat 64
|
||||||
|
41(flat_struct): TypeStruct 14(int) 24(float) 40(float) 20(bool)
|
||||||
|
42(nesting_struct): TypeStruct 41(flat_struct) 25(fvec4) 14(int)
|
||||||
|
43: 40(float) SpecConstant 1413754136 1074340347
|
||||||
|
44:41(flat_struct) SpecConstantComposite 28 32 43 21
|
||||||
|
45:42(nesting_struct) SpecConstantComposite 44 33 28
|
||||||
|
46: 14(int) Constant 2
|
||||||
|
51: TypeInt 32 0
|
||||||
|
52: 51(int) Constant 0
|
||||||
|
57: 51(int) Constant 5
|
||||||
|
58: TypeArray 24(float) 57
|
||||||
|
59: 24(float) Constant 1065353216
|
||||||
|
60: 24(float) Constant 1073741824
|
||||||
|
61: 24(float) Constant 1077936128
|
||||||
|
62: 58 SpecConstantComposite 32 32 59 60 61
|
||||||
|
63: 14(int) Constant 1
|
||||||
|
68: TypeArray 14(int) 57
|
||||||
|
69: 14(int) Constant 30
|
||||||
|
70: 68 SpecConstantComposite 28 28 63 46 69
|
||||||
|
71: TypePointer Function 68
|
||||||
|
73: TypePointer Function 14(int)
|
||||||
|
87: 24(float) Constant 1106321080
|
||||||
|
88:41(flat_struct) SpecConstantComposite 69 87 43 21
|
||||||
|
89: 14(int) Constant 10
|
||||||
|
90:42(nesting_struct) SpecConstantComposite 88 37 89
|
||||||
|
96: 20(bool) ConstantFalse
|
||||||
|
97:41(flat_struct) SpecConstantComposite 28 32 43 96
|
||||||
|
98: 24(float) Constant 1036831949
|
||||||
|
99: 25(fvec4) ConstantComposite 98 98 98 98
|
||||||
|
100:42(nesting_struct) SpecConstantComposite 97 99 28
|
||||||
|
101: 14(int) Constant 3000
|
||||||
|
102:42(nesting_struct) SpecConstantComposite 88 37 101
|
||||||
|
103: TypeArray 25(fvec4) 28
|
||||||
|
104: TypePointer Input 103
|
||||||
|
105(global_vec4_array_with_spec_length): 104(ptr) Variable Input
|
||||||
|
4(main): 2 Function None 3
|
||||||
|
5: Label
|
||||||
|
Return
|
||||||
|
FunctionEnd
|
||||||
|
6(refer_primary_spec_const(): 2 Function None 3
|
||||||
|
7: Label
|
||||||
|
SelectionMerge 23 None
|
||||||
|
BranchConditional 21 22 23
|
||||||
|
22: Label
|
||||||
|
29: 24(float) ConvertSToF 28
|
||||||
|
30: 25(fvec4) Load 27(color)
|
||||||
|
31: 25(fvec4) VectorTimesScalar 30 29
|
||||||
|
Store 27(color) 31
|
||||||
|
Branch 23
|
||||||
|
23: Label
|
||||||
|
Return
|
||||||
|
FunctionEnd
|
||||||
|
8(refer_composite_spec_const(): 2 Function None 3
|
||||||
|
9: Label
|
||||||
|
34: 25(fvec4) Load 27(color)
|
||||||
|
35: 25(fvec4) FAdd 34 33
|
||||||
|
Store 27(color) 35
|
||||||
|
38: 25(fvec4) Load 27(color)
|
||||||
|
39: 25(fvec4) FSub 38 37
|
||||||
|
Store 27(color) 39
|
||||||
|
Return
|
||||||
|
FunctionEnd
|
||||||
|
10(refer_copmosite_dot_dereference(): 2 Function None 3
|
||||||
|
11: Label
|
||||||
|
47: 14(int) CompositeExtract 45 2
|
||||||
|
48: 24(float) ConvertSToF 47
|
||||||
|
49: 25(fvec4) Load 27(color)
|
||||||
|
50: 25(fvec4) VectorTimesScalar 49 48
|
||||||
|
Store 27(color) 50
|
||||||
|
53: 24(float) CompositeExtract 33 0
|
||||||
|
54: 25(fvec4) Load 27(color)
|
||||||
|
55: 25(fvec4) CompositeConstruct 53 53 53 53
|
||||||
|
56: 25(fvec4) FAdd 54 55
|
||||||
|
Store 27(color) 56
|
||||||
|
Return
|
||||||
|
FunctionEnd
|
||||||
|
12(refer_composite_bracket_dereference(): 2 Function None 3
|
||||||
|
13: Label
|
||||||
|
72(indexable): 71(ptr) Variable Function
|
||||||
|
76(indexable): 71(ptr) Variable Function
|
||||||
|
64: 24(float) CompositeExtract 62 1
|
||||||
|
65: 25(fvec4) Load 27(color)
|
||||||
|
66: 25(fvec4) CompositeConstruct 64 64 64 64
|
||||||
|
67: 25(fvec4) FSub 65 66
|
||||||
|
Store 27(color) 67
|
||||||
|
Store 72(indexable) 70
|
||||||
|
74: 73(ptr) AccessChain 72(indexable) 28
|
||||||
|
75: 14(int) Load 74
|
||||||
|
Store 76(indexable) 70
|
||||||
|
77: 73(ptr) AccessChain 76(indexable) 75
|
||||||
|
78: 14(int) Load 77
|
||||||
|
79: 24(float) ConvertSToF 78
|
||||||
|
80: 25(fvec4) Load 27(color)
|
||||||
|
81: 25(fvec4) CompositeConstruct 79 79 79 79
|
||||||
|
82: 25(fvec4) FDiv 80 81
|
||||||
|
Store 27(color) 82
|
||||||
|
Return
|
||||||
|
FunctionEnd
|
||||||
|
16(refer_spec_const_array_length(): 14(int) Function None 15
|
||||||
|
17: Label
|
||||||
|
83(len): 73(ptr) Variable Function
|
||||||
|
Store 83(len) 28
|
||||||
|
84: 14(int) Load 83(len)
|
||||||
|
ReturnValue 84
|
||||||
|
FunctionEnd
|
||||||
|
18(declare_spec_const_in_func(): 2 Function None 3
|
||||||
|
19: Label
|
||||||
|
91: 14(int) CompositeExtract 90 2
|
||||||
|
92: 24(float) ConvertSToF 91
|
||||||
|
93: 25(fvec4) Load 27(color)
|
||||||
|
94: 25(fvec4) CompositeConstruct 92 92 92 92
|
||||||
|
95: 25(fvec4) FDiv 93 94
|
||||||
|
Store 27(color) 95
|
||||||
|
Return
|
||||||
|
FunctionEnd
|
||||||
10
Test/preprocessor.many.endif.vert
Normal file
10
Test/preprocessor.many.endif.vert
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if
|
||||||
|
#else
|
||||||
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
in vec2 c2D;
|
in vec2 c2D;
|
||||||
flat in int i;
|
flat in int i;
|
||||||
|
flat in uint u;
|
||||||
|
out uint uo;
|
||||||
out vec4 outp;
|
out vec4 outp;
|
||||||
out ivec4 ioutp;
|
out ivec4 ioutp;
|
||||||
out uvec4 uoutp;
|
out uvec4 uoutp;
|
||||||
@ -254,6 +256,7 @@ void main()
|
|||||||
ioutp += textureGatherOffset(isamp2DA, vec3(0.1), ivec2(i));
|
ioutp += textureGatherOffset(isamp2DA, vec3(0.1), ivec2(i));
|
||||||
|
|
||||||
outp += gl_FragCoord + vl2;
|
outp += gl_FragCoord + vl2;
|
||||||
|
uo = u % i;
|
||||||
foo23();
|
foo23();
|
||||||
doubles();
|
doubles();
|
||||||
}
|
}
|
||||||
|
|||||||
13
Test/spv.noDeadDecorations.vert
Normal file
13
Test/spv.noDeadDecorations.vert
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#version 310 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
float func(float a)
|
||||||
|
{
|
||||||
|
return -a;
|
||||||
|
a = a * -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position.x = func(0.0);
|
||||||
|
}
|
||||||
93
Test/spv.specConstantComposite.vert
Normal file
93
Test/spv.specConstantComposite.vert
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// constant_id specified scalar spec constants
|
||||||
|
layout(constant_id = 200) const int spec_int = 3;
|
||||||
|
layout(constant_id = 201) const float spec_float = 3.14;
|
||||||
|
layout(constant_id = 202) const
|
||||||
|
double spec_double = 3.1415926535897932384626433832795;
|
||||||
|
layout(constant_id = 203) const bool spec_bool = true;
|
||||||
|
|
||||||
|
const float cast_spec_float = float(spec_float);
|
||||||
|
|
||||||
|
// Flat struct
|
||||||
|
struct flat_struct {
|
||||||
|
int i;
|
||||||
|
float f;
|
||||||
|
double d;
|
||||||
|
bool b;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Nesting struct
|
||||||
|
struct nesting_struct {
|
||||||
|
flat_struct nested;
|
||||||
|
vec4 v;
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Expect OpSpecConstantComposite
|
||||||
|
// Flat struct initializer
|
||||||
|
const flat_struct spec_flat_struct_all_spec = {spec_int, spec_float,
|
||||||
|
spec_double, spec_bool};
|
||||||
|
const flat_struct spec_flat_struct_partial_spec = {30, 30.14, spec_double,
|
||||||
|
spec_bool};
|
||||||
|
|
||||||
|
// Nesting struct initializer
|
||||||
|
const nesting_struct nesting_struct_ctor = {
|
||||||
|
{spec_int, spec_float, spec_double, false},
|
||||||
|
vec4(0.1, 0.1, 0.1, 0.1),
|
||||||
|
spec_int};
|
||||||
|
|
||||||
|
// Vector constructor
|
||||||
|
const vec4 spec_vec4_all_spec =
|
||||||
|
vec4(spec_float, spec_float, spec_float, spec_float);
|
||||||
|
const vec4 spec_vec4_partial_spec =
|
||||||
|
vec4(spec_float, spec_float, 300.14, 300.14);
|
||||||
|
|
||||||
|
// Struct nesting constructor
|
||||||
|
const nesting_struct spec_nesting_struct_all_spec = {
|
||||||
|
spec_flat_struct_all_spec, spec_vec4_all_spec, spec_int};
|
||||||
|
const nesting_struct spec_nesting_struct_partial_spec = {
|
||||||
|
spec_flat_struct_partial_spec, spec_vec4_partial_spec, 3000};
|
||||||
|
|
||||||
|
const float spec_float_array[5] = {spec_float, spec_float, 1.0, 2.0, 3.0};
|
||||||
|
const int spec_int_array[5] = {spec_int, spec_int, 1, 2, 30};
|
||||||
|
|
||||||
|
// global_vec4_array_with_spec_length is not a spec constant, but its array
|
||||||
|
// size is. When calling global_vec4_array_with_spec_length.length(), A
|
||||||
|
// TIntermSymbol Node shoule be returned, instead of a TIntermConstantUnion
|
||||||
|
// node which represents a known constant value.
|
||||||
|
in vec4 global_vec4_array_with_spec_length[spec_int];
|
||||||
|
|
||||||
|
out vec4 color;
|
||||||
|
|
||||||
|
void refer_primary_spec_const() {
|
||||||
|
if (spec_bool) color *= spec_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
void refer_composite_spec_const() {
|
||||||
|
color += spec_vec4_all_spec;
|
||||||
|
color -= spec_vec4_partial_spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void refer_copmosite_dot_dereference() {
|
||||||
|
color *= spec_nesting_struct_all_spec.i;
|
||||||
|
color += spec_vec4_all_spec.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void refer_composite_bracket_dereference() {
|
||||||
|
color -= spec_float_array[1];
|
||||||
|
color /= spec_int_array[spec_int_array[spec_int]];
|
||||||
|
}
|
||||||
|
|
||||||
|
int refer_spec_const_array_length() {
|
||||||
|
int len = global_vec4_array_with_spec_length.length();
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void declare_spec_const_in_func() {
|
||||||
|
const nesting_struct spec_const_declared_in_func = {
|
||||||
|
spec_flat_struct_partial_spec, spec_vec4_partial_spec, 10};
|
||||||
|
color /= spec_const_declared_in_func.i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {}
|
||||||
@ -12,3 +12,4 @@ preprocessor.pragma.vert
|
|||||||
preprocessor.simple.vert
|
preprocessor.simple.vert
|
||||||
preprocessor.success_if_parse_would_fail.vert
|
preprocessor.success_if_parse_would_fail.vert
|
||||||
preprocessor.defined.vert
|
preprocessor.defined.vert
|
||||||
|
preprocessor.many.endif.vert
|
||||||
|
|||||||
@ -64,6 +64,7 @@ spv.matrix2.frag
|
|||||||
spv.memoryQualifier.frag
|
spv.memoryQualifier.frag
|
||||||
spv.merge-unreachable.frag
|
spv.merge-unreachable.frag
|
||||||
spv.newTexture.frag
|
spv.newTexture.frag
|
||||||
|
spv.noDeadDecorations.vert
|
||||||
spv.nonSquare.vert
|
spv.nonSquare.vert
|
||||||
spv.Operations.frag
|
spv.Operations.frag
|
||||||
spv.intOps.vert
|
spv.intOps.vert
|
||||||
@ -101,6 +102,7 @@ spv.pushConstant.vert
|
|||||||
spv.subpass.frag
|
spv.subpass.frag
|
||||||
spv.specConstant.vert
|
spv.specConstant.vert
|
||||||
spv.specConstant.comp
|
spv.specConstant.comp
|
||||||
|
spv.specConstantComposite.vert
|
||||||
# GLSL-level semantics
|
# GLSL-level semantics
|
||||||
vulkan.frag
|
vulkan.frag
|
||||||
vulkan.vert
|
vulkan.vert
|
||||||
|
|||||||
@ -411,6 +411,19 @@ public:
|
|||||||
clearLayout();
|
clearLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drop just the storage qualification, which perhaps should
|
||||||
|
// never be done, as it is fundamentally inconsistent, but need to
|
||||||
|
// explore what downstream consumers need.
|
||||||
|
// E.g., in a deference, it is an inconsistency between:
|
||||||
|
// A) partially dereferenced resource is still in the storage class it started in
|
||||||
|
// B) partially dereferenced resource is a new temporary object
|
||||||
|
// If A, then nothing should change, if B, then everything should change, but this is half way.
|
||||||
|
void makePartialTemporary()
|
||||||
|
{
|
||||||
|
storage = EvqTemporary;
|
||||||
|
specConstant = false;
|
||||||
|
}
|
||||||
|
|
||||||
TStorageQualifier storage : 6;
|
TStorageQualifier storage : 6;
|
||||||
TBuiltInVariable builtIn : 8;
|
TBuiltInVariable builtIn : 8;
|
||||||
TPrecisionQualifier precision : 3;
|
TPrecisionQualifier precision : 3;
|
||||||
@ -727,6 +740,7 @@ public:
|
|||||||
}
|
}
|
||||||
void makeSpecConstant()
|
void makeSpecConstant()
|
||||||
{
|
{
|
||||||
|
storage = EvqConst;
|
||||||
specConstant = true;
|
specConstant = true;
|
||||||
}
|
}
|
||||||
static const char* getLayoutPackingString(TLayoutPacking packing)
|
static const char* getLayoutPackingString(TLayoutPacking packing)
|
||||||
@ -1209,6 +1223,7 @@ public:
|
|||||||
virtual int getMatrixCols() const { return matrixCols; }
|
virtual int getMatrixCols() const { return matrixCols; }
|
||||||
virtual int getMatrixRows() const { return matrixRows; }
|
virtual int getMatrixRows() const { return matrixRows; }
|
||||||
virtual int getOuterArraySize() const { return arraySizes->getOuterSize(); }
|
virtual int getOuterArraySize() const { return arraySizes->getOuterSize(); }
|
||||||
|
virtual TIntermTyped* getOuterArrayNode() const { return arraySizes->getOuterNode(); }
|
||||||
virtual int getCumulativeArraySize() const { return arraySizes->getCumulativeSize(); }
|
virtual int getCumulativeArraySize() const { return arraySizes->getCumulativeSize(); }
|
||||||
virtual bool isArrayOfArrays() const { return arraySizes != nullptr && arraySizes->getNumDims() > 1; }
|
virtual bool isArrayOfArrays() const { return arraySizes != nullptr && arraySizes->getNumDims() > 1; }
|
||||||
virtual int getImplicitArraySize() const { return arraySizes->getImplicitSize(); }
|
virtual int getImplicitArraySize() const { return arraySizes->getImplicitSize(); }
|
||||||
|
|||||||
@ -612,25 +612,29 @@ public:
|
|||||||
// if symbol is initialized as symbol(sym), the memory comes from the pool allocator of sym. If sym comes from
|
// if symbol is initialized as symbol(sym), the memory comes from the pool allocator of sym. If sym comes from
|
||||||
// per process threadPoolAllocator, then it causes increased memory usage per compile
|
// per process threadPoolAllocator, then it causes increased memory usage per compile
|
||||||
// it is essential to use "symbol = sym" to assign to symbol
|
// it is essential to use "symbol = sym" to assign to symbol
|
||||||
TIntermSymbol(int i, const TString& n, const TType& t) :
|
TIntermSymbol(int i, const TString& n, const TType& t)
|
||||||
TIntermTyped(t), id(i) { name = n;}
|
: TIntermTyped(t), id(i), constSubtree(nullptr)
|
||||||
|
{ name = n; }
|
||||||
virtual int getId() const { return id; }
|
virtual int getId() const { return id; }
|
||||||
virtual const TString& getName() const { return name; }
|
virtual const TString& getName() const { return name; }
|
||||||
virtual void traverse(TIntermTraverser*);
|
virtual void traverse(TIntermTraverser*);
|
||||||
virtual TIntermSymbol* getAsSymbolNode() { return this; }
|
virtual TIntermSymbol* getAsSymbolNode() { return this; }
|
||||||
virtual const TIntermSymbol* getAsSymbolNode() const { return this; }
|
virtual const TIntermSymbol* getAsSymbolNode() const { return this; }
|
||||||
void setConstArray(const TConstUnionArray& c) { unionArray = c; }
|
void setConstArray(const TConstUnionArray& c) { constArray = c; }
|
||||||
const TConstUnionArray& getConstArray() const { return unionArray; }
|
const TConstUnionArray& getConstArray() const { return constArray; }
|
||||||
|
void setConstSubtree(TIntermTyped* subtree) { constSubtree = subtree; }
|
||||||
|
TIntermTyped* getConstSubtree() const { return constSubtree; }
|
||||||
protected:
|
protected:
|
||||||
int id; // the unique id of the symbol this node represents
|
int id; // the unique id of the symbol this node represents
|
||||||
TString name; // the name of the symbol this node represents
|
TString name; // the name of the symbol this node represents
|
||||||
TConstUnionArray unionArray; // if the symbol is a front-end compile-time constant, this is its value
|
TConstUnionArray constArray; // if the symbol is a front-end compile-time constant, this is its value
|
||||||
|
TIntermTyped* constSubtree;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TIntermConstantUnion : public TIntermTyped {
|
class TIntermConstantUnion : public TIntermTyped {
|
||||||
public:
|
public:
|
||||||
TIntermConstantUnion(const TConstUnionArray& ua, const TType& t) : TIntermTyped(t), unionArray(ua), literal(false) { }
|
TIntermConstantUnion(const TConstUnionArray& ua, const TType& t) : TIntermTyped(t), constArray(ua), literal(false) { }
|
||||||
const TConstUnionArray& getConstArray() const { return unionArray; }
|
const TConstUnionArray& getConstArray() const { return constArray; }
|
||||||
virtual TIntermConstantUnion* getAsConstantUnion() { return this; }
|
virtual TIntermConstantUnion* getAsConstantUnion() { return this; }
|
||||||
virtual const TIntermConstantUnion* getAsConstantUnion() const { return this; }
|
virtual const TIntermConstantUnion* getAsConstantUnion() const { return this; }
|
||||||
virtual void traverse(TIntermTraverser*);
|
virtual void traverse(TIntermTraverser*);
|
||||||
@ -640,7 +644,7 @@ public:
|
|||||||
void setExpression() { literal = false; }
|
void setExpression() { literal = false; }
|
||||||
bool isLiteral() const { return literal; }
|
bool isLiteral() const { return literal; }
|
||||||
protected:
|
protected:
|
||||||
const TConstUnionArray unionArray;
|
const TConstUnionArray constArray;
|
||||||
bool literal; // true if node represents a literal in the source code
|
bool literal; // true if node represents a literal in the source code
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -61,25 +61,35 @@ namespace glslang {
|
|||||||
// Returns the added node.
|
// Returns the added node.
|
||||||
//
|
//
|
||||||
|
|
||||||
TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TSourceLoc& loc)
|
TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TConstUnionArray& constArray,
|
||||||
|
TIntermTyped* constSubtree, const TSourceLoc& loc)
|
||||||
{
|
{
|
||||||
TIntermSymbol* node = new TIntermSymbol(id, name, type);
|
TIntermSymbol* node = new TIntermSymbol(id, name, type);
|
||||||
node->setLoc(loc);
|
node->setLoc(loc);
|
||||||
|
node->setConstArray(constArray);
|
||||||
|
node->setConstSubtree(constSubtree);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TConstUnionArray& constArray, const TSourceLoc& loc)
|
TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable)
|
||||||
{
|
{
|
||||||
TIntermSymbol* node = addSymbol(id, name, type, loc);
|
glslang::TSourceLoc loc; // just a null location
|
||||||
node->setConstArray(constArray);
|
loc.init();
|
||||||
|
|
||||||
return node;
|
return addSymbol(variable, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable, const TSourceLoc& loc)
|
TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable, const TSourceLoc& loc)
|
||||||
{
|
{
|
||||||
return addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), variable.getConstArray(), loc);
|
return addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), variable.getConstArray(), variable.getConstSubtree(), loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
TIntermSymbol* TIntermediate::addSymbol(const TType& type, const TSourceLoc& loc)
|
||||||
|
{
|
||||||
|
TConstUnionArray unionArray; // just a null constant
|
||||||
|
|
||||||
|
return addSymbol(0, "", type, unionArray, nullptr, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -252,6 +262,7 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, TSo
|
|||||||
|
|
||||||
//
|
//
|
||||||
// For constructors, we are now done, it was all in the conversion.
|
// For constructors, we are now done, it was all in the conversion.
|
||||||
|
// TODO: but, did this bypass constant folding?
|
||||||
//
|
//
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case EOpConstructInt:
|
case EOpConstructInt:
|
||||||
@ -281,7 +292,7 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, TSo
|
|||||||
if (child->getAsConstantUnion())
|
if (child->getAsConstantUnion())
|
||||||
return child->getAsConstantUnion()->fold(op, node->getType());
|
return child->getAsConstantUnion()->fold(op, node->getType());
|
||||||
|
|
||||||
// If it's a specialiation constant, the result is too.
|
// If it's a specialization constant, the result is too.
|
||||||
if (child->getType().getQualifier().isSpecConstant())
|
if (child->getType().getQualifier().isSpecConstant())
|
||||||
node->getWritableType().getQualifier().makeSpecConstant();
|
node->getWritableType().getQualifier().makeSpecConstant();
|
||||||
|
|
||||||
@ -474,6 +485,7 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt
|
|||||||
case EOpSub:
|
case EOpSub:
|
||||||
case EOpMul:
|
case EOpMul:
|
||||||
case EOpDiv:
|
case EOpDiv:
|
||||||
|
case EOpMod:
|
||||||
|
|
||||||
case EOpVectorTimesScalar:
|
case EOpVectorTimesScalar:
|
||||||
case EOpVectorTimesMatrix:
|
case EOpVectorTimesMatrix:
|
||||||
@ -605,6 +617,12 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt
|
|||||||
newNode->setLoc(node->getLoc());
|
newNode->setLoc(node->getLoc());
|
||||||
newNode->setOperand(node);
|
newNode->setOperand(node);
|
||||||
|
|
||||||
|
// TODO: it seems that some unary folding operations should occur here, but are not
|
||||||
|
|
||||||
|
// Propagate specialization-constant-ness.
|
||||||
|
if (node->getType().getQualifier().isSpecConstant())
|
||||||
|
newNode->getWritableType().getQualifier().makeSpecConstant();
|
||||||
|
|
||||||
return newNode;
|
return newNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -813,7 +831,7 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* true
|
|||||||
// Make a selection node.
|
// Make a selection node.
|
||||||
//
|
//
|
||||||
TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
|
TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
|
||||||
node->getQualifier().storage = EvqTemporary;
|
node->getQualifier().makeTemporary();
|
||||||
node->setLoc(loc);
|
node->setLoc(loc);
|
||||||
node->getQualifier().precision = std::max(trueBlock->getQualifier().precision, falseBlock->getQualifier().precision);
|
node->getQualifier().precision = std::max(trueBlock->getQualifier().precision, falseBlock->getQualifier().precision);
|
||||||
|
|
||||||
@ -872,7 +890,6 @@ TIntermConstantUnion* TIntermediate::addConstantUnion(double d, TBasicType baseT
|
|||||||
|
|
||||||
TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc& loc)
|
TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc& loc)
|
||||||
{
|
{
|
||||||
|
|
||||||
TIntermAggregate* node = new TIntermAggregate(EOpSequence);
|
TIntermAggregate* node = new TIntermAggregate(EOpSequence);
|
||||||
|
|
||||||
node->setLoc(loc);
|
node->setLoc(loc);
|
||||||
@ -1017,8 +1034,7 @@ void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymb
|
|||||||
const TAnonMember* anon = symbol.getAsAnonMember();
|
const TAnonMember* anon = symbol.getAsAnonMember();
|
||||||
variable = &anon->getAnonContainer();
|
variable = &anon->getAnonContainer();
|
||||||
}
|
}
|
||||||
TIntermSymbol* node = new TIntermSymbol(variable->getUniqueId(), variable->getName(), variable->getType());
|
TIntermSymbol* node = addSymbol(*variable);
|
||||||
node->setConstArray(variable->getConstArray());
|
|
||||||
linkage = growAggregate(linkage, node);
|
linkage = growAggregate(linkage, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -484,7 +484,7 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
|
|||||||
TIntermTyped* result = nullptr;
|
TIntermTyped* result = nullptr;
|
||||||
|
|
||||||
int indexValue = 0;
|
int indexValue = 0;
|
||||||
if (index->getQualifier().storage == EvqConst) {
|
if (index->getQualifier().isFrontEndConstant()) {
|
||||||
indexValue = index->getAsConstantUnion()->getConstArray()[0].getIConst();
|
indexValue = index->getAsConstantUnion()->getConstArray()[0].getIConst();
|
||||||
checkIndex(loc, base->getType(), indexValue);
|
checkIndex(loc, base->getType(), indexValue);
|
||||||
}
|
}
|
||||||
@ -495,7 +495,7 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
|
|||||||
error(loc, " left of '[' is not of type array, matrix, or vector ", base->getAsSymbolNode()->getName().c_str(), "");
|
error(loc, " left of '[' is not of type array, matrix, or vector ", base->getAsSymbolNode()->getName().c_str(), "");
|
||||||
else
|
else
|
||||||
error(loc, " left of '[' is not of type array, matrix, or vector ", "expression", "");
|
error(loc, " left of '[' is not of type array, matrix, or vector ", "expression", "");
|
||||||
} else if (base->getType().getQualifier().storage == EvqConst && index->getQualifier().storage == EvqConst)
|
} else if (base->getType().getQualifier().isFrontEndConstant() && index->getQualifier().isFrontEndConstant())
|
||||||
return intermediate.foldDereference(base, indexValue, loc);
|
return intermediate.foldDereference(base, indexValue, loc);
|
||||||
else {
|
else {
|
||||||
// at least one of base and index is variable...
|
// at least one of base and index is variable...
|
||||||
@ -503,7 +503,7 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
|
|||||||
if (base->getAsSymbolNode() && isIoResizeArray(base->getType()))
|
if (base->getAsSymbolNode() && isIoResizeArray(base->getType()))
|
||||||
handleIoResizeArrayAccess(loc, base);
|
handleIoResizeArrayAccess(loc, base);
|
||||||
|
|
||||||
if (index->getQualifier().storage == EvqConst) {
|
if (index->getQualifier().isFrontEndConstant()) {
|
||||||
if (base->getType().isImplicitlySizedArray())
|
if (base->getType().isImplicitlySizedArray())
|
||||||
updateImplicitArraySize(loc, base, indexValue);
|
updateImplicitArraySize(loc, base, indexValue);
|
||||||
result = intermediate.addIndex(EOpIndexDirect, base, index, loc);
|
result = intermediate.addIndex(EOpIndexDirect, base, index, loc);
|
||||||
@ -541,10 +541,15 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
|
|||||||
} else {
|
} else {
|
||||||
// Insert valid dereferenced result
|
// Insert valid dereferenced result
|
||||||
TType newType(base->getType(), 0); // dereferenced type
|
TType newType(base->getType(), 0); // dereferenced type
|
||||||
if (base->getType().getQualifier().storage == EvqConst && index->getQualifier().storage == EvqConst)
|
if (base->getType().getQualifier().isConstant() && index->getQualifier().isConstant()) {
|
||||||
newType.getQualifier().storage = EvqConst;
|
newType.getQualifier().storage = EvqConst;
|
||||||
else
|
// If base or index is a specialization constant, the result should also be a specialization constant.
|
||||||
newType.getQualifier().storage = EvqTemporary;
|
if (base->getType().getQualifier().isSpecConstant() || index->getQualifier().isSpecConstant()) {
|
||||||
|
newType.getQualifier().makeSpecConstant();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newType.getQualifier().makePartialTemporary();
|
||||||
|
}
|
||||||
result->setType(newType);
|
result->setType(newType);
|
||||||
|
|
||||||
if (anyIndexLimits)
|
if (anyIndexLimits)
|
||||||
@ -587,7 +592,7 @@ void TParseContext::handleIndexLimits(const TSourceLoc& /*loc*/, TIntermTyped* b
|
|||||||
(! limits.generalVariableIndexing && ! base->getType().getQualifier().isUniformOrBuffer() &&
|
(! limits.generalVariableIndexing && ! base->getType().getQualifier().isUniformOrBuffer() &&
|
||||||
! base->getType().getQualifier().isPipeInput() &&
|
! base->getType().getQualifier().isPipeInput() &&
|
||||||
! base->getType().getQualifier().isPipeOutput() &&
|
! base->getType().getQualifier().isPipeOutput() &&
|
||||||
base->getType().getQualifier().storage != EvqConst) ||
|
! base->getType().getQualifier().isConstant()) ||
|
||||||
(! limits.generalVaryingIndexing && (base->getType().getQualifier().isPipeInput() ||
|
(! limits.generalVaryingIndexing && (base->getType().getQualifier().isPipeInput() ||
|
||||||
base->getType().getQualifier().isPipeOutput()))) {
|
base->getType().getQualifier().isPipeOutput()))) {
|
||||||
// it's too early to know what the inductive variables are, save it for post processing
|
// it's too early to know what the inductive variables are, save it for post processing
|
||||||
@ -820,6 +825,9 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm
|
|||||||
return result;
|
return result;
|
||||||
else {
|
else {
|
||||||
TType type(base->getBasicType(), EvqTemporary, fields.num);
|
TType type(base->getBasicType(), EvqTemporary, fields.num);
|
||||||
|
// Swizzle operations propagate specialization-constantness
|
||||||
|
if (base->getQualifier().isSpecConstant())
|
||||||
|
type.getQualifier().makeSpecConstant();
|
||||||
return addConstructor(loc, base, type, mapTypeToConstructorOp(type));
|
return addConstructor(loc, base, type, mapTypeToConstructorOp(type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -837,6 +845,9 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm
|
|||||||
result = intermediate.addIndex(EOpVectorSwizzle, base, index, loc);
|
result = intermediate.addIndex(EOpVectorSwizzle, base, index, loc);
|
||||||
result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, (int) vectorString.size()));
|
result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, (int) vectorString.size()));
|
||||||
}
|
}
|
||||||
|
// Swizzle operations propagate specialization-constantness
|
||||||
|
if (base->getType().getQualifier().isSpecConstant())
|
||||||
|
result->getWritableType().getQualifier().makeSpecConstant();
|
||||||
}
|
}
|
||||||
} else if (base->getBasicType() == EbtStruct || base->getBasicType() == EbtBlock) {
|
} else if (base->getBasicType() == EbtStruct || base->getBasicType() == EbtBlock) {
|
||||||
const TTypeList* fields = base->getType().getStruct();
|
const TTypeList* fields = base->getType().getStruct();
|
||||||
@ -849,7 +860,7 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fieldFound) {
|
if (fieldFound) {
|
||||||
if (base->getType().getQualifier().storage == EvqConst)
|
if (base->getType().getQualifier().isFrontEndConstant())
|
||||||
result = intermediate.foldDereference(base, member, loc);
|
result = intermediate.foldDereference(base, member, loc);
|
||||||
else {
|
else {
|
||||||
blockMemberExtensionCheck(loc, base, field);
|
blockMemberExtensionCheck(loc, base, field);
|
||||||
@ -1017,7 +1028,7 @@ TIntermAggregate* TParseContext::handleFunctionDefinition(const TSourceLoc& loc,
|
|||||||
loc);
|
loc);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
paramNodes = intermediate.growAggregate(paramNodes, intermediate.addSymbol(0, "", *param.type, loc), loc);
|
paramNodes = intermediate.growAggregate(paramNodes, intermediate.addSymbol(*param.type, loc), loc);
|
||||||
}
|
}
|
||||||
intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), loc);
|
intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), loc);
|
||||||
loopNestingLevel = 0;
|
loopNestingLevel = 0;
|
||||||
@ -1220,6 +1231,11 @@ TIntermTyped* TParseContext::handleLengthMethod(const TSourceLoc& loc, TFunction
|
|||||||
else
|
else
|
||||||
error(loc, "", function->getName().c_str(), "array must be declared with a size before using this method");
|
error(loc, "", function->getName().c_str(), "array must be declared with a size before using this method");
|
||||||
}
|
}
|
||||||
|
} else if (type.getOuterArrayNode()) {
|
||||||
|
// If the array's outer size is specified by an intermediate node, it means the array's length
|
||||||
|
// was specified by a specialization constant. In such a case, we should return the node of the
|
||||||
|
// specialization constants to represent the length.
|
||||||
|
return type.getOuterArrayNode();
|
||||||
} else
|
} else
|
||||||
length = type.getOuterArraySize();
|
length = type.getOuterArraySize();
|
||||||
} else if (type.isMatrix())
|
} else if (type.isMatrix())
|
||||||
@ -2039,7 +2055,7 @@ void TParseContext::rValueErrorCheck(const TSourceLoc& loc, const char* op, TInt
|
|||||||
//
|
//
|
||||||
void TParseContext::constantValueCheck(TIntermTyped* node, const char* token)
|
void TParseContext::constantValueCheck(TIntermTyped* node, const char* token)
|
||||||
{
|
{
|
||||||
if (node->getQualifier().storage != EvqConst)
|
if (! node->getQualifier().isConstant())
|
||||||
error(node->getLoc(), "constant expression required", token, "");
|
error(node->getLoc(), "constant expression required", token, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2204,6 +2220,7 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
|
|||||||
|
|
||||||
int size = 0;
|
int size = 0;
|
||||||
bool constType = true;
|
bool constType = true;
|
||||||
|
bool specConstType = false; // value is only valid if constType is true
|
||||||
bool full = false;
|
bool full = false;
|
||||||
bool overFull = false;
|
bool overFull = false;
|
||||||
bool matrixInMatrix = false;
|
bool matrixInMatrix = false;
|
||||||
@ -2232,12 +2249,18 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
|
|||||||
if (op != EOpConstructStruct && ! type.isArray() && size >= type.computeNumComponents())
|
if (op != EOpConstructStruct && ! type.isArray() && size >= type.computeNumComponents())
|
||||||
full = true;
|
full = true;
|
||||||
|
|
||||||
if (function[arg].type->getQualifier().storage != EvqConst)
|
if (! function[arg].type->getQualifier().isConstant())
|
||||||
constType = false;
|
constType = false;
|
||||||
|
if (function[arg].type->getQualifier().isSpecConstant())
|
||||||
|
specConstType = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (constType)
|
if (constType) {
|
||||||
type.getQualifier().storage = EvqConst;
|
if (specConstType)
|
||||||
|
type.getQualifier().makeSpecConstant();
|
||||||
|
else
|
||||||
|
type.getQualifier().storage = EvqConst;
|
||||||
|
}
|
||||||
|
|
||||||
if (type.isArray()) {
|
if (type.isArray()) {
|
||||||
if (function.getParamCount() == 0) {
|
if (function.getParamCount() == 0) {
|
||||||
@ -3147,7 +3170,7 @@ void TParseContext::nonInitConstCheck(const TSourceLoc& loc, TString& identifier
|
|||||||
//
|
//
|
||||||
if (type.getQualifier().storage == EvqConst ||
|
if (type.getQualifier().storage == EvqConst ||
|
||||||
type.getQualifier().storage == EvqConstReadOnly) {
|
type.getQualifier().storage == EvqConstReadOnly) {
|
||||||
type.getQualifier().storage = EvqTemporary;
|
type.getQualifier().makeTemporary();
|
||||||
error(loc, "variables with qualifier 'const' must be initialized", identifier.c_str(), "");
|
error(loc, "variables with qualifier 'const' must be initialized", identifier.c_str(), "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4848,7 +4871,7 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||||||
if (! initializer) {
|
if (! initializer) {
|
||||||
// error recovery; don't leave const without constant values
|
// error recovery; don't leave const without constant values
|
||||||
if (qualifier == EvqConst)
|
if (qualifier == EvqConst)
|
||||||
variable->getWritableType().getQualifier().storage = EvqTemporary;
|
variable->getWritableType().getQualifier().makeTemporary();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4868,21 +4891,22 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uniform and global consts require a constant initializer
|
// Uniforms require a compile-time constant initializer
|
||||||
if (qualifier == EvqUniform && initializer->getType().getQualifier().storage != EvqConst) {
|
if (qualifier == EvqUniform && ! initializer->getType().getQualifier().isFrontEndConstant()) {
|
||||||
error(loc, "uniform initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str());
|
error(loc, "uniform initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str());
|
||||||
variable->getWritableType().getQualifier().storage = EvqTemporary;
|
variable->getWritableType().getQualifier().makeTemporary();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (qualifier == EvqConst && symbolTable.atGlobalLevel() && initializer->getType().getQualifier().storage != EvqConst) {
|
// Global consts require a constant initializer (specialization constant is okay)
|
||||||
|
if (qualifier == EvqConst && symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) {
|
||||||
error(loc, "global const initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str());
|
error(loc, "global const initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str());
|
||||||
variable->getWritableType().getQualifier().storage = EvqTemporary;
|
variable->getWritableType().getQualifier().makeTemporary();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Const variables require a constant initializer, depending on version
|
// Const variables require a constant initializer, depending on version
|
||||||
if (qualifier == EvqConst) {
|
if (qualifier == EvqConst) {
|
||||||
if (initializer->getType().getQualifier().storage != EvqConst) {
|
if (! initializer->getType().getQualifier().isConstant()) {
|
||||||
const char* initFeature = "non-constant initializer";
|
const char* initFeature = "non-constant initializer";
|
||||||
requireProfile(loc, ~EEsProfile, initFeature);
|
requireProfile(loc, ~EEsProfile, initFeature);
|
||||||
profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature);
|
profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature);
|
||||||
@ -4894,7 +4918,7 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||||||
//
|
//
|
||||||
// "In declarations of global variables with no storage qualifier or with a const
|
// "In declarations of global variables with no storage qualifier or with a const
|
||||||
// qualifier any initializer must be a constant expression."
|
// qualifier any initializer must be a constant expression."
|
||||||
if (symbolTable.atGlobalLevel() && initializer->getType().getQualifier().storage != EvqConst) {
|
if (symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) {
|
||||||
const char* initFeature = "non-constant global initializer";
|
const char* initFeature = "non-constant global initializer";
|
||||||
if (relaxedErrors())
|
if (relaxedErrors())
|
||||||
warn(loc, "not allowed in this version", initFeature, "");
|
warn(loc, "not allowed in this version", initFeature, "");
|
||||||
@ -4907,14 +4931,27 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||||||
// Compile-time tagging of the variable with its constant value...
|
// Compile-time tagging of the variable with its constant value...
|
||||||
|
|
||||||
initializer = intermediate.addConversion(EOpAssign, variable->getType(), initializer);
|
initializer = intermediate.addConversion(EOpAssign, variable->getType(), initializer);
|
||||||
if (! initializer || ! initializer->getAsConstantUnion() || variable->getType() != initializer->getType()) {
|
if (! initializer || ! initializer->getType().getQualifier().isConstant() || variable->getType() != initializer->getType()) {
|
||||||
error(loc, "non-matching or non-convertible constant type for const initializer",
|
error(loc, "non-matching or non-convertible constant type for const initializer",
|
||||||
variable->getType().getStorageQualifierString(), "");
|
variable->getType().getStorageQualifierString(), "");
|
||||||
variable->getWritableType().getQualifier().storage = EvqTemporary;
|
variable->getWritableType().getQualifier().makeTemporary();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
variable->setConstArray(initializer->getAsConstantUnion()->getConstArray());
|
// We either have a folded constant in getAsConstantUnion, or we have to use
|
||||||
|
// the initializer's subtree in the AST to represent the computation of a
|
||||||
|
// specialization constant.
|
||||||
|
assert(initializer->getAsConstantUnion() || initializer->getType().getQualifier().isSpecConstant());
|
||||||
|
if (initializer->getAsConstantUnion())
|
||||||
|
variable->setConstArray(initializer->getAsConstantUnion()->getConstArray());
|
||||||
|
else {
|
||||||
|
// It's a specialization constant.
|
||||||
|
variable->getWritableType().getQualifier().makeSpecConstant();
|
||||||
|
|
||||||
|
// Keep the subtree that computes the specialization constant with the variable.
|
||||||
|
// Later, a symbol node will adopt the subtree from the variable.
|
||||||
|
variable->setConstSubtree(initializer);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// normal assigning of a value to a variable...
|
// normal assigning of a value to a variable...
|
||||||
specializationCheck(loc, initializer->getType(), "initializer");
|
specializationCheck(loc, initializer->getType(), "initializer");
|
||||||
@ -5075,12 +5112,17 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode*
|
|||||||
// if the structure constructor contains more than one parameter, then construct
|
// if the structure constructor contains more than one parameter, then construct
|
||||||
// each parameter
|
// each parameter
|
||||||
|
|
||||||
int paramCount = 0; // keeps a track of the constructor parameter number being checked
|
int paramCount = 0; // keeps track of the constructor parameter number being checked
|
||||||
|
|
||||||
// for each parameter to the constructor call, check to see if the right type is passed or convert them
|
// 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).
|
// to the right type if possible (and allowed).
|
||||||
// for structure constructors, just check if the right type is passed, no conversion is 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();
|
for (TIntermSequence::iterator p = sequenceVector.begin();
|
||||||
p != sequenceVector.end(); p++, paramCount++) {
|
p != sequenceVector.end(); p++, paramCount++) {
|
||||||
if (type.isArray())
|
if (type.isArray())
|
||||||
@ -5090,13 +5132,19 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode*
|
|||||||
else
|
else
|
||||||
newNode = constructBuiltIn(type, op, (*p)->getAsTyped(), node->getLoc(), true);
|
newNode = constructBuiltIn(type, op, (*p)->getAsTyped(), node->getLoc(), true);
|
||||||
|
|
||||||
if (newNode)
|
if (newNode) {
|
||||||
*p = newNode;
|
*p = newNode;
|
||||||
else
|
if (! newNode->getType().getQualifier().isConstant())
|
||||||
|
isConstConstrutor = false;
|
||||||
|
if (newNode->getType().getQualifier().isSpecConstant())
|
||||||
|
hasSpecConst = true;
|
||||||
|
} else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, type, loc);
|
TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, type, loc);
|
||||||
|
if (isConstConstrutor && hasSpecConst)
|
||||||
|
constructor->getWritableType().getQualifier().makeSpecConstant();
|
||||||
|
|
||||||
return constructor;
|
return constructor;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,8 +32,8 @@
|
|||||||
//POSSIBILITY OF SUCH DAMAGE.
|
//POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "../Include/PoolAlloc.h"
|
|
||||||
#include "../Include/Common.h"
|
#include "../Include/Common.h"
|
||||||
|
#include "../Include/PoolAlloc.h"
|
||||||
|
|
||||||
#include "../Include/InitializeGlobals.h"
|
#include "../Include/InitializeGlobals.h"
|
||||||
#include "../OSDependent/osinclude.h"
|
#include "../OSDependent/osinclude.h"
|
||||||
|
|||||||
@ -51,10 +51,10 @@ const int EndOfInput = -1;
|
|||||||
//
|
//
|
||||||
class TInputScanner {
|
class TInputScanner {
|
||||||
public:
|
public:
|
||||||
TInputScanner(int n, const char* const s[], size_t L[], const char* const* names = nullptr, int b = 0, int f = 0) :
|
TInputScanner(int n, const char* const s[], size_t L[], const char* const* names = nullptr, int b = 0, int f = 0, bool single = false) :
|
||||||
numSources(n),
|
numSources(n),
|
||||||
sources(reinterpret_cast<const unsigned char* const *>(s)), // up to this point, common usage is "char*", but now we need positive 8-bit characters
|
sources(reinterpret_cast<const unsigned char* const *>(s)), // up to this point, common usage is "char*", but now we need positive 8-bit characters
|
||||||
lengths(L), currentSource(0), currentChar(0), stringBias(b), finale(f)
|
lengths(L), currentSource(0), currentChar(0), stringBias(b), finale(f), singleLogical(single)
|
||||||
{
|
{
|
||||||
loc = new TSourceLoc[numSources];
|
loc = new TSourceLoc[numSources];
|
||||||
for (int i = 0; i < numSources; ++i) {
|
for (int i = 0; i < numSources; ++i) {
|
||||||
@ -67,6 +67,10 @@ public:
|
|||||||
loc[currentSource].string = -stringBias;
|
loc[currentSource].string = -stringBias;
|
||||||
loc[currentSource].line = 1;
|
loc[currentSource].line = 1;
|
||||||
loc[currentSource].column = 0;
|
loc[currentSource].column = 0;
|
||||||
|
logicalSourceLoc.string = 0;
|
||||||
|
logicalSourceLoc.line = 1;
|
||||||
|
logicalSourceLoc.column = 0;
|
||||||
|
logicalSourceLoc.name = loc[0].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~TInputScanner()
|
virtual ~TInputScanner()
|
||||||
@ -82,8 +86,11 @@ public:
|
|||||||
|
|
||||||
int ret = peek();
|
int ret = peek();
|
||||||
++loc[currentSource].column;
|
++loc[currentSource].column;
|
||||||
|
++logicalSourceLoc.column;
|
||||||
if (ret == '\n') {
|
if (ret == '\n') {
|
||||||
++loc[currentSource].line;
|
++loc[currentSource].line;
|
||||||
|
++logicalSourceLoc.line;
|
||||||
|
logicalSourceLoc.column = 0;
|
||||||
loc[currentSource].column = 0;
|
loc[currentSource].column = 0;
|
||||||
}
|
}
|
||||||
advance();
|
advance();
|
||||||
@ -118,6 +125,7 @@ public:
|
|||||||
if (currentChar > 0) {
|
if (currentChar > 0) {
|
||||||
--currentChar;
|
--currentChar;
|
||||||
--loc[currentSource].column;
|
--loc[currentSource].column;
|
||||||
|
--logicalSourceLoc.column;
|
||||||
if (loc[currentSource].column < 0) {
|
if (loc[currentSource].column < 0) {
|
||||||
// We've moved back past a new line. Find the
|
// We've moved back past a new line. Find the
|
||||||
// previous newline (or start of the file) to compute
|
// previous newline (or start of the file) to compute
|
||||||
@ -129,6 +137,7 @@ public:
|
|||||||
}
|
}
|
||||||
--chIndex;
|
--chIndex;
|
||||||
}
|
}
|
||||||
|
logicalSourceLoc.column = (int)(currentChar - chIndex);
|
||||||
loc[currentSource].column = (int)(currentChar - chIndex);
|
loc[currentSource].column = (int)(currentChar - chIndex);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -141,23 +150,57 @@ public:
|
|||||||
} else
|
} else
|
||||||
currentChar = lengths[currentSource] - 1;
|
currentChar = lengths[currentSource] - 1;
|
||||||
}
|
}
|
||||||
if (peek() == '\n')
|
if (peek() == '\n') {
|
||||||
--loc[currentSource].line;
|
--loc[currentSource].line;
|
||||||
|
--logicalSourceLoc.line;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for #line override
|
// for #line override
|
||||||
void setLine(int newLine) { loc[getLastValidSourceIndex()].line = newLine; }
|
void setLine(int newLine)
|
||||||
void setFile(const char* filename) { loc[getLastValidSourceIndex()].name = filename; }
|
{
|
||||||
|
logicalSourceLoc.line = newLine;
|
||||||
|
loc[getLastValidSourceIndex()].line = newLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for #line override in filename based parsing
|
||||||
|
void setFile(const char* filename)
|
||||||
|
{
|
||||||
|
logicalSourceLoc.name = filename;
|
||||||
|
loc[getLastValidSourceIndex()].name = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFile(const char* filename, size_t i)
|
||||||
|
{
|
||||||
|
if (i == getLastValidSourceIndex()) {
|
||||||
|
logicalSourceLoc.name = filename;
|
||||||
|
}
|
||||||
|
loc[i].name = filename;
|
||||||
|
}
|
||||||
|
|
||||||
void setString(int newString)
|
void setString(int newString)
|
||||||
{
|
{
|
||||||
|
logicalSourceLoc.string = newString;
|
||||||
loc[getLastValidSourceIndex()].string = newString;
|
loc[getLastValidSourceIndex()].string = newString;
|
||||||
|
logicalSourceLoc.name = nullptr;
|
||||||
loc[getLastValidSourceIndex()].name = nullptr;
|
loc[getLastValidSourceIndex()].name = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for #include content indentation
|
// for #include content indentation
|
||||||
void setColumn(int col) { loc[getLastValidSourceIndex()].column = col; }
|
void setColumn(int col)
|
||||||
|
{
|
||||||
|
logicalSourceLoc.column = col;
|
||||||
|
loc[getLastValidSourceIndex()].column = col;
|
||||||
|
}
|
||||||
|
|
||||||
const TSourceLoc& getSourceLoc() const { return loc[std::max(0, std::min(currentSource, numSources - finale - 1))]; }
|
const TSourceLoc& getSourceLoc() const
|
||||||
|
{
|
||||||
|
if (singleLogical) {
|
||||||
|
return logicalSourceLoc;
|
||||||
|
} else {
|
||||||
|
return loc[std::max(0, std::min(currentSource, numSources - finale - 1))];
|
||||||
|
}
|
||||||
|
}
|
||||||
// Returns the index (starting from 0) of the most recent valid source string we are reading from.
|
// Returns the index (starting from 0) of the most recent valid source string we are reading from.
|
||||||
int getLastValidSourceIndex() const { return std::min(currentSource, numSources - 1); }
|
int getLastValidSourceIndex() const { return std::min(currentSource, numSources - 1); }
|
||||||
|
|
||||||
@ -204,6 +247,10 @@ protected:
|
|||||||
|
|
||||||
int stringBias; // the first string that is the user's string number 0
|
int stringBias; // the first string that is the user's string number 0
|
||||||
int finale; // number of internal strings after user's last string
|
int finale; // number of internal strings after user's last string
|
||||||
|
|
||||||
|
TSourceLoc logicalSourceLoc;
|
||||||
|
bool singleLogical; // treats the strings as a single logical string.
|
||||||
|
// locations will be reported from the first string.
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace glslang
|
} // end namespace glslang
|
||||||
|
|||||||
@ -131,7 +131,8 @@ bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profil
|
|||||||
TIntermediate intermediate(language, version, profile);
|
TIntermediate intermediate(language, version, profile);
|
||||||
|
|
||||||
TParseContext parseContext(symbolTable, intermediate, true, version, profile, spv, vulkan, language, infoSink);
|
TParseContext parseContext(symbolTable, intermediate, true, version, profile, spv, vulkan, language, infoSink);
|
||||||
TPpContext ppContext(parseContext, TShader::ForbidInclude());
|
TShader::ForbidInclude includer;
|
||||||
|
TPpContext ppContext(parseContext, "", includer);
|
||||||
TScanContext scanContext(parseContext);
|
TScanContext scanContext(parseContext);
|
||||||
parseContext.setScanContext(&scanContext);
|
parseContext.setScanContext(&scanContext);
|
||||||
parseContext.setPpContext(&ppContext);
|
parseContext.setPpContext(&ppContext);
|
||||||
@ -482,7 +483,7 @@ bool ProcessDeferred(
|
|||||||
TIntermediate& intermediate, // returned tree, etc.
|
TIntermediate& intermediate, // returned tree, etc.
|
||||||
ProcessingContext& processingContext,
|
ProcessingContext& processingContext,
|
||||||
bool requireNonempty,
|
bool requireNonempty,
|
||||||
const TShader::Includer& includer
|
TShader::Includer& includer
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (! InitThread())
|
if (! InitThread())
|
||||||
@ -550,7 +551,6 @@ bool ProcessDeferred(
|
|||||||
version = defaultVersion;
|
version = defaultVersion;
|
||||||
profile = defaultProfile;
|
profile = defaultProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
int spv = (messages & EShMsgSpvRules) ? 100 : 0; // TODO find path to get real version number here, for now non-0 is what matters
|
int spv = (messages & EShMsgSpvRules) ? 100 : 0; // TODO find path to get real version number here, for now non-0 is what matters
|
||||||
bool goodVersion = DeduceVersionProfile(compiler->infoSink, compiler->getLanguage(), versionNotFirst, defaultVersion, version, profile, spv);
|
bool goodVersion = DeduceVersionProfile(compiler->infoSink, compiler->getLanguage(), versionNotFirst, defaultVersion, version, profile, spv);
|
||||||
bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst));
|
bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst));
|
||||||
@ -590,7 +590,7 @@ bool ProcessDeferred(
|
|||||||
|
|
||||||
TParseContext parseContext(symbolTable, intermediate, false, version, profile, spv, vulkan, compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages);
|
TParseContext parseContext(symbolTable, intermediate, false, version, profile, spv, vulkan, compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages);
|
||||||
glslang::TScanContext scanContext(parseContext);
|
glslang::TScanContext scanContext(parseContext);
|
||||||
TPpContext ppContext(parseContext, includer);
|
TPpContext ppContext(parseContext, names[numPre]? names[numPre]: "", includer);
|
||||||
parseContext.setScanContext(&scanContext);
|
parseContext.setScanContext(&scanContext);
|
||||||
parseContext.setPpContext(&ppContext);
|
parseContext.setPpContext(&ppContext);
|
||||||
parseContext.setLimits(*resources);
|
parseContext.setLimits(*resources);
|
||||||
@ -863,7 +863,7 @@ bool PreprocessDeferred(
|
|||||||
bool forceDefaultVersionAndProfile,
|
bool forceDefaultVersionAndProfile,
|
||||||
bool forwardCompatible, // give errors for use of deprecated features
|
bool forwardCompatible, // give errors for use of deprecated features
|
||||||
EShMessages messages, // warnings/errors/AST; things to print out
|
EShMessages messages, // warnings/errors/AST; things to print out
|
||||||
const TShader::Includer& includer,
|
TShader::Includer& includer,
|
||||||
TIntermediate& intermediate, // returned tree, etc.
|
TIntermediate& intermediate, // returned tree, etc.
|
||||||
std::string* outputString)
|
std::string* outputString)
|
||||||
{
|
{
|
||||||
@ -902,7 +902,7 @@ bool CompileDeferred(
|
|||||||
bool forwardCompatible, // give errors for use of deprecated features
|
bool forwardCompatible, // give errors for use of deprecated features
|
||||||
EShMessages messages, // warnings/errors/AST; things to print out
|
EShMessages messages, // warnings/errors/AST; things to print out
|
||||||
TIntermediate& intermediate,// returned tree, etc.
|
TIntermediate& intermediate,// returned tree, etc.
|
||||||
const TShader::Includer& includer)
|
TShader::Includer& includer)
|
||||||
{
|
{
|
||||||
DoFullParse parser;
|
DoFullParse parser;
|
||||||
return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
|
return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
|
||||||
@ -1051,9 +1051,10 @@ int ShCompile(
|
|||||||
compiler->infoSink.debug.erase();
|
compiler->infoSink.debug.erase();
|
||||||
|
|
||||||
TIntermediate intermediate(compiler->getLanguage());
|
TIntermediate intermediate(compiler->getLanguage());
|
||||||
|
TShader::ForbidInclude includer;
|
||||||
bool success = CompileDeferred(compiler, shaderStrings, numStrings, inputLengths, nullptr,
|
bool success = CompileDeferred(compiler, shaderStrings, numStrings, inputLengths, nullptr,
|
||||||
"", optLevel, resources, defaultVersion, ENoProfile, false,
|
"", optLevel, resources, defaultVersion, ENoProfile, false,
|
||||||
forwardCompatible, messages, intermediate, TShader::ForbidInclude());
|
forwardCompatible, messages, intermediate, includer);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Call the machine dependent compiler
|
// Call the machine dependent compiler
|
||||||
@ -1361,7 +1362,7 @@ void TShader::setStringsWithLengthsAndNames(
|
|||||||
// Returns true for success.
|
// Returns true for success.
|
||||||
//
|
//
|
||||||
bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
||||||
bool forwardCompatible, EShMessages messages, const Includer& includer)
|
bool forwardCompatible, EShMessages messages, Includer& includer)
|
||||||
{
|
{
|
||||||
if (! InitThread())
|
if (! InitThread())
|
||||||
return false;
|
return false;
|
||||||
@ -1389,7 +1390,7 @@ bool TShader::preprocess(const TBuiltInResource* builtInResources,
|
|||||||
bool forceDefaultVersionAndProfile,
|
bool forceDefaultVersionAndProfile,
|
||||||
bool forwardCompatible, EShMessages message,
|
bool forwardCompatible, EShMessages message,
|
||||||
std::string* output_string,
|
std::string* output_string,
|
||||||
const TShader::Includer& includer)
|
Includer& includer)
|
||||||
{
|
{
|
||||||
if (! InitThread())
|
if (! InitThread())
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -252,11 +252,14 @@ TVariable::TVariable(const TVariable& copyOf) : TSymbol(copyOf)
|
|||||||
if (copyOf.numExtensions != 0)
|
if (copyOf.numExtensions != 0)
|
||||||
setExtensions(copyOf.numExtensions, copyOf.extensions);
|
setExtensions(copyOf.numExtensions, copyOf.extensions);
|
||||||
|
|
||||||
if (! copyOf.unionArray.empty()) {
|
if (! copyOf.constArray.empty()) {
|
||||||
assert(! copyOf.type.isStruct());
|
assert(! copyOf.type.isStruct());
|
||||||
TConstUnionArray newArray(copyOf.unionArray, 0, copyOf.unionArray.size());
|
TConstUnionArray newArray(copyOf.constArray, 0, copyOf.constArray.size());
|
||||||
unionArray = newArray;
|
constArray = newArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// don't support specialization-constant subtrees in cloned tables
|
||||||
|
constSubtree = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
TVariable* TVariable::clone() const
|
TVariable* TVariable::clone() const
|
||||||
|
|||||||
@ -135,7 +135,7 @@ protected:
|
|||||||
//
|
//
|
||||||
// Variable class, meaning a symbol that's not a function.
|
// Variable class, meaning a symbol that's not a function.
|
||||||
//
|
//
|
||||||
// There could be a separate class heirarchy for Constant variables;
|
// There could be a separate class hierarchy for Constant variables;
|
||||||
// Only one of int, bool, or float, (or none) is correct for
|
// 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
|
// 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
|
// seem worth having separate classes, and "getConst" can't simply return
|
||||||
@ -144,7 +144,10 @@ protected:
|
|||||||
//
|
//
|
||||||
class TVariable : public TSymbol {
|
class TVariable : public TSymbol {
|
||||||
public:
|
public:
|
||||||
TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), userType(uT) { type.shallowCopy(t); }
|
TVariable(const TString *name, const TType& t, bool uT = false )
|
||||||
|
: TSymbol(name),
|
||||||
|
userType(uT),
|
||||||
|
constSubtree(nullptr) { type.shallowCopy(t); }
|
||||||
virtual TVariable* clone() const;
|
virtual TVariable* clone() const;
|
||||||
virtual ~TVariable() { }
|
virtual ~TVariable() { }
|
||||||
|
|
||||||
@ -153,9 +156,11 @@ public:
|
|||||||
virtual const TType& getType() const { return type; }
|
virtual const TType& getType() const { return type; }
|
||||||
virtual TType& getWritableType() { assert(writable); return type; }
|
virtual TType& getWritableType() { assert(writable); return type; }
|
||||||
virtual bool isUserType() const { return userType; }
|
virtual bool isUserType() const { return userType; }
|
||||||
virtual const TConstUnionArray& getConstArray() const { return unionArray; }
|
virtual const TConstUnionArray& getConstArray() const { return constArray; }
|
||||||
virtual TConstUnionArray& getWritableConstArray() { assert(writable); return unionArray; }
|
virtual TConstUnionArray& getWritableConstArray() { assert(writable); return constArray; }
|
||||||
virtual void setConstArray(const TConstUnionArray& constArray) { unionArray = constArray; }
|
virtual void setConstArray(const TConstUnionArray& array) { constArray = array; }
|
||||||
|
virtual void setConstSubtree(TIntermTyped* subtree) { constSubtree = subtree; }
|
||||||
|
virtual TIntermTyped* getConstSubtree() const { return constSubtree; }
|
||||||
|
|
||||||
virtual void dump(TInfoSink &infoSink) const;
|
virtual void dump(TInfoSink &infoSink) const;
|
||||||
|
|
||||||
@ -167,7 +172,12 @@ protected:
|
|||||||
bool userType;
|
bool userType;
|
||||||
// we are assuming that Pool Allocator will free the memory allocated to unionArray
|
// we are assuming that Pool Allocator will free the memory allocated to unionArray
|
||||||
// when this object is destroyed
|
// when this object is destroyed
|
||||||
TConstUnionArray unionArray;
|
|
||||||
|
// TODO: these two should be a union
|
||||||
|
// A variable could be a compile-time constant, or a specialization
|
||||||
|
// constant, or neither, but never both.
|
||||||
|
TConstUnionArray constArray; // for compile-time constant value
|
||||||
|
TIntermTyped* constSubtree; // for specialization constant computation
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@ -48,7 +48,7 @@ namespace {
|
|||||||
bool is_positive_infinity(double x) {
|
bool is_positive_infinity(double x) {
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
return _fpclass(x) == _FPCLASS_PINF;
|
return _fpclass(x) == _FPCLASS_PINF;
|
||||||
#elif defined __ANDROID__ || defined __linux__
|
#elif defined __ANDROID__ || defined __linux__ || __MINGW32__ || __MINGW64__
|
||||||
return std::isinf(x) && (x >= 0);
|
return std::isinf(x) && (x >= 0);
|
||||||
#else
|
#else
|
||||||
return isinf(x) && (x >= 0);
|
return isinf(x) && (x >= 0);
|
||||||
@ -605,6 +605,11 @@ void TOutputTraverser::visitSymbol(TIntermSymbol* node)
|
|||||||
|
|
||||||
if (! node->getConstArray().empty())
|
if (! node->getConstArray().empty())
|
||||||
OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1);
|
OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1);
|
||||||
|
else if (node->getConstSubtree()) {
|
||||||
|
incrementDepth(node);
|
||||||
|
node->getConstSubtree()->traverse(this);
|
||||||
|
decrementDepth();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TOutputTraverser::visitLoop(TVisit /* visit */, TIntermLoop* node)
|
bool TOutputTraverser::visitLoop(TVisit /* visit */, TIntermLoop* node)
|
||||||
|
|||||||
@ -163,9 +163,9 @@ public:
|
|||||||
void addPushConstantCount() { ++numPushConstants; }
|
void addPushConstantCount() { ++numPushConstants; }
|
||||||
bool isRecursive() const { return recursive; }
|
bool isRecursive() const { return recursive; }
|
||||||
|
|
||||||
TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, const TSourceLoc&);
|
TIntermSymbol* addSymbol(const TVariable&);
|
||||||
TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TSourceLoc&);
|
|
||||||
TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&);
|
TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&);
|
||||||
|
TIntermSymbol* addSymbol(const TType&, const TSourceLoc&);
|
||||||
TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*) const;
|
TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*) const;
|
||||||
TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
|
TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
|
||||||
TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
|
TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
|
||||||
@ -326,6 +326,7 @@ public:
|
|||||||
static int getBaseAlignment(const TType&, int& size, int& stride, bool std140, bool rowMajor);
|
static int getBaseAlignment(const TType&, int& size, int& stride, bool std140, bool rowMajor);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&);
|
||||||
void error(TInfoSink& infoSink, const char*);
|
void error(TInfoSink& infoSink, const char*);
|
||||||
void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
|
void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
|
||||||
void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects);
|
void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects);
|
||||||
|
|||||||
@ -611,24 +611,28 @@ int TPpContext::CPPinclude(TPpToken* ppToken)
|
|||||||
if (token != '\n' && token != EndOfInput) {
|
if (token != '\n' && token != EndOfInput) {
|
||||||
parseContext.ppError(ppToken->loc, "extra content after file designation", "#include", "");
|
parseContext.ppError(ppToken->loc, "extra content after file designation", "#include", "");
|
||||||
} else {
|
} else {
|
||||||
auto include = includer.include(filename.c_str());
|
TShader::Includer::IncludeResult* res = includer.include(filename.c_str(), TShader::Includer::EIncludeRelative, currentSourceFile.c_str(), includeStack.size() + 1);
|
||||||
std::string sourceName = include.first;
|
if (res && !res->file_name.empty()) {
|
||||||
std::string replacement = include.second;
|
if (res->file_data && res->file_length) {
|
||||||
if (!sourceName.empty()) {
|
|
||||||
if (!replacement.empty()) {
|
|
||||||
const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine();
|
const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine();
|
||||||
std::ostringstream content;
|
std::ostringstream prologue;
|
||||||
content << "#line " << forNextLine << " " << "\"" << sourceName << "\"\n";
|
std::ostringstream epilogue;
|
||||||
content << replacement << (replacement.back() == '\n' ? "" : "\n");
|
prologue << "#line " << forNextLine << " " << "\"" << res->file_name << "\"\n";
|
||||||
content << "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n";
|
epilogue << (res->file_data[res->file_length - 1] == '\n'? "" : "\n") << "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n";
|
||||||
pushInput(new TokenizableString(directiveLoc, content.str(), this));
|
pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this));
|
||||||
}
|
}
|
||||||
// At EOF, there's no "current" location anymore.
|
// At EOF, there's no "current" location anymore.
|
||||||
if (token != EndOfInput) parseContext.setCurrentColumn(0);
|
if (token != EndOfInput) parseContext.setCurrentColumn(0);
|
||||||
// Don't accidentally return EndOfInput, which will end all preprocessing.
|
// Don't accidentally return EndOfInput, which will end all preprocessing.
|
||||||
return '\n';
|
return '\n';
|
||||||
} else {
|
} else {
|
||||||
parseContext.ppError(directiveLoc, replacement.c_str(), "#include", "");
|
std::string message =
|
||||||
|
res ? std::string(res->file_data, res->file_length)
|
||||||
|
: std::string("Could not process include directive");
|
||||||
|
parseContext.ppError(directiveLoc, message.c_str(), "#include", "");
|
||||||
|
if (res) {
|
||||||
|
includer.releaseInclude(res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -867,12 +871,13 @@ int TPpContext::readCPPline(TPpToken* ppToken)
|
|||||||
token = CPPelse(0, ppToken);
|
token = CPPelse(0, ppToken);
|
||||||
break;
|
break;
|
||||||
case PpAtomEndif:
|
case PpAtomEndif:
|
||||||
elseSeen[elsetracker] = false;
|
|
||||||
--elsetracker;
|
|
||||||
if (! ifdepth)
|
if (! ifdepth)
|
||||||
parseContext.ppError(ppToken->loc, "mismatched statements", "#endif", "");
|
parseContext.ppError(ppToken->loc, "mismatched statements", "#endif", "");
|
||||||
else
|
else {
|
||||||
|
elseSeen[elsetracker] = false;
|
||||||
|
--elsetracker;
|
||||||
--ifdepth;
|
--ifdepth;
|
||||||
|
}
|
||||||
token = extraTokenCheck(PpAtomEndif, ppToken, scanToken(ppToken));
|
token = extraTokenCheck(PpAtomEndif, ppToken, scanToken(ppToken));
|
||||||
break;
|
break;
|
||||||
case PpAtomIf:
|
case PpAtomIf:
|
||||||
|
|||||||
@ -83,8 +83,10 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
namespace glslang {
|
namespace glslang {
|
||||||
|
|
||||||
TPpContext::TPpContext(TParseContext& pc, const TShader::Includer& inclr) :
|
TPpContext::TPpContext(TParseContext& pc, const std::string& rootFileName, TShader::Includer& inclr) :
|
||||||
preamble(0), strings(0), parseContext(pc), includer(inclr), inComment(false)
|
preamble(0), strings(0), parseContext(pc), includer(inclr), inComment(false),
|
||||||
|
rootFileName(rootFileName),
|
||||||
|
currentSourceFile(rootFileName)
|
||||||
{
|
{
|
||||||
InitAtomTable();
|
InitAtomTable();
|
||||||
InitScanner();
|
InitScanner();
|
||||||
|
|||||||
@ -78,6 +78,7 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#ifndef PPCONTEXT_H
|
#ifndef PPCONTEXT_H
|
||||||
#define PPCONTEXT_H
|
#define PPCONTEXT_H
|
||||||
|
|
||||||
|
#include <stack>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "../ParseHelper.h"
|
#include "../ParseHelper.h"
|
||||||
@ -121,7 +122,7 @@ class TInputScanner;
|
|||||||
// Don't expect too much in terms of OO design.
|
// Don't expect too much in terms of OO design.
|
||||||
class TPpContext {
|
class TPpContext {
|
||||||
public:
|
public:
|
||||||
TPpContext(TParseContext&, const TShader::Includer&);
|
TPpContext(TParseContext&, const std::string& rootFileName, TShader::Includer&);
|
||||||
virtual ~TPpContext();
|
virtual ~TPpContext();
|
||||||
|
|
||||||
void setPreamble(const char* preamble, size_t length);
|
void setPreamble(const char* preamble, size_t length);
|
||||||
@ -290,7 +291,7 @@ protected:
|
|||||||
//
|
//
|
||||||
|
|
||||||
// Used to obtain #include content.
|
// Used to obtain #include content.
|
||||||
const TShader::Includer& includer;
|
TShader::Includer& includer;
|
||||||
|
|
||||||
int InitCPP();
|
int InitCPP();
|
||||||
int CPPdefine(TPpToken * ppToken);
|
int CPPdefine(TPpToken * ppToken);
|
||||||
@ -430,21 +431,40 @@ protected:
|
|||||||
TInputScanner* input;
|
TInputScanner* input;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Holds a string that can be tokenized via the tInput interface.
|
// Holds a reference to included file data, as well as a
|
||||||
class TokenizableString : public tInput {
|
// prologue and an epilogue string. This can be scanned using the tInput
|
||||||
|
// interface and acts as a single source string.
|
||||||
|
class TokenizableIncludeFile : public tInput {
|
||||||
public:
|
public:
|
||||||
// Copies str, which must be non-empty.
|
// Copies prologue and epilogue. The includedFile must remain valid
|
||||||
TokenizableString(const TSourceLoc& startLoc, const std::string& str, TPpContext* pp)
|
// until this TokenizableIncludeFile is no longer used.
|
||||||
|
TokenizableIncludeFile(const TSourceLoc& startLoc,
|
||||||
|
const std::string& prologue,
|
||||||
|
TShader::Includer::IncludeResult* includedFile,
|
||||||
|
const std::string& epilogue,
|
||||||
|
TPpContext* pp)
|
||||||
: tInput(pp),
|
: tInput(pp),
|
||||||
str_(str),
|
prologue_(prologue),
|
||||||
strings(str_.data()),
|
includedFile_(includedFile),
|
||||||
length(str_.size()),
|
epilogue_(epilogue),
|
||||||
scanner(1, &strings, &length),
|
scanner(3, strings, lengths, names, 0, 0, true),
|
||||||
prevScanner(nullptr),
|
prevScanner(nullptr),
|
||||||
stringInput(pp, scanner) {
|
stringInput(pp, scanner)
|
||||||
scanner.setLine(startLoc.line);
|
{
|
||||||
scanner.setString(startLoc.string);
|
strings[0] = prologue_.data();
|
||||||
scanner.setFile(startLoc.name);
|
strings[1] = includedFile_->file_data;
|
||||||
|
strings[2] = epilogue_.data();
|
||||||
|
|
||||||
|
lengths[0] = prologue_.size();
|
||||||
|
lengths[1] = includedFile_->file_length;
|
||||||
|
lengths[2] = epilogue_.size();
|
||||||
|
|
||||||
|
scanner.setLine(startLoc.line);
|
||||||
|
scanner.setString(startLoc.string);
|
||||||
|
|
||||||
|
scanner.setFile(startLoc.name, 0);
|
||||||
|
scanner.setFile(startLoc.name, 1);
|
||||||
|
scanner.setFile(startLoc.name, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// tInput methods:
|
// tInput methods:
|
||||||
@ -456,16 +476,34 @@ protected:
|
|||||||
{
|
{
|
||||||
prevScanner = pp->parseContext.getScanner();
|
prevScanner = pp->parseContext.getScanner();
|
||||||
pp->parseContext.setScanner(&scanner);
|
pp->parseContext.setScanner(&scanner);
|
||||||
|
pp->push_include(includedFile_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void notifyDeleted() override
|
||||||
|
{
|
||||||
|
pp->parseContext.setScanner(prevScanner);
|
||||||
|
pp->pop_include();
|
||||||
}
|
}
|
||||||
void notifyDeleted() override { pp->parseContext.setScanner(prevScanner); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Stores the titular string.
|
// Stores the prologue for this string.
|
||||||
const std::string str_;
|
const std::string prologue_;
|
||||||
// Will point to str_[0] and be passed to scanner constructor.
|
|
||||||
const char* const strings;
|
// Stores the epilogue for this string.
|
||||||
|
const std::string epilogue_;
|
||||||
|
|
||||||
|
// Points to the IncludeResult that this TokenizableIncludeFile represents.
|
||||||
|
TShader::Includer::IncludeResult* includedFile_;
|
||||||
|
|
||||||
|
// Will point to prologue_, includedFile_->file_data and epilogue_
|
||||||
|
// This is passed to scanner constructor.
|
||||||
|
// These do not own the storage and it must remain valid until this
|
||||||
|
// object has been destroyed.
|
||||||
|
const char* strings[3];
|
||||||
// Length of str_, passed to scanner constructor.
|
// Length of str_, passed to scanner constructor.
|
||||||
size_t length;
|
size_t lengths[3];
|
||||||
|
// String names
|
||||||
|
const char* names[3];
|
||||||
// Scans over str_.
|
// Scans over str_.
|
||||||
TInputScanner scanner;
|
TInputScanner scanner;
|
||||||
// The previous effective scanner before the scanner in this instance
|
// The previous effective scanner before the scanner in this instance
|
||||||
@ -480,6 +518,24 @@ protected:
|
|||||||
void missingEndifCheck();
|
void missingEndifCheck();
|
||||||
int lFloatConst(int len, int ch, TPpToken* ppToken);
|
int lFloatConst(int len, int ch, TPpToken* ppToken);
|
||||||
|
|
||||||
|
void push_include(TShader::Includer::IncludeResult* result)
|
||||||
|
{
|
||||||
|
currentSourceFile = result->file_name;
|
||||||
|
includeStack.push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_include()
|
||||||
|
{
|
||||||
|
TShader::Includer::IncludeResult* include = includeStack.top();
|
||||||
|
includeStack.pop();
|
||||||
|
includer.releaseInclude(include);
|
||||||
|
if (includeStack.empty()) {
|
||||||
|
currentSourceFile = rootFileName;
|
||||||
|
} else {
|
||||||
|
currentSourceFile = includeStack.top()->file_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool inComment;
|
bool inComment;
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -487,8 +543,12 @@ protected:
|
|||||||
//
|
//
|
||||||
typedef TUnorderedMap<TString, int> TAtomMap;
|
typedef TUnorderedMap<TString, int> TAtomMap;
|
||||||
typedef TVector<const TString*> TStringMap;
|
typedef TVector<const TString*> TStringMap;
|
||||||
|
|
||||||
TAtomMap atomMap;
|
TAtomMap atomMap;
|
||||||
TStringMap stringMap;
|
TStringMap stringMap;
|
||||||
|
std::stack<TShader::Includer::IncludeResult*> includeStack;
|
||||||
|
std::string currentSourceFile;
|
||||||
|
std::string rootFileName;
|
||||||
int nextAtom;
|
int nextAtom;
|
||||||
void InitAtomTable();
|
void InitAtomTable();
|
||||||
void AddAtomFixed(const char* s, int atom);
|
void AddAtomFixed(const char* s, int atom);
|
||||||
|
|||||||
@ -4,6 +4,12 @@ set(SOURCES ossource.cpp ../osinclude.h)
|
|||||||
|
|
||||||
add_library(OSDependent STATIC ${SOURCES})
|
add_library(OSDependent STATIC ${SOURCES})
|
||||||
|
|
||||||
|
# MinGW GCC complains about function pointer casts to void*.
|
||||||
|
# Turn that off with -fpermissive.
|
||||||
|
if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
|
||||||
|
target_compile_options(OSDependent PRIVATE -fpermissive)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
source_group("Source" FILES ${SOURCES})
|
source_group("Source" FILES ${SOURCES})
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
|||||||
@ -292,25 +292,90 @@ public:
|
|||||||
void setPreamble(const char* s) { preamble = s; }
|
void setPreamble(const char* s) { preamble = s; }
|
||||||
|
|
||||||
// Interface to #include handlers.
|
// Interface to #include handlers.
|
||||||
|
//
|
||||||
|
// To support #include, a client of Glslang does the following:
|
||||||
|
// 1. Call setStringsWithNames to set the source strings and associated
|
||||||
|
// names. For example, the names could be the names of the files
|
||||||
|
// containing the shader sources.
|
||||||
|
// 2. Call parse with an Includer.
|
||||||
|
//
|
||||||
|
// When the Glslang parser encounters an #include directive, it calls
|
||||||
|
// the Includer's include method with the the requested include name
|
||||||
|
// together with the current string name. The returned IncludeResult
|
||||||
|
// contains the fully resolved name of the included source, together
|
||||||
|
// with the source text that should replace the #include directive
|
||||||
|
// in the source stream. After parsing that source, Glslang will
|
||||||
|
// release the IncludeResult object.
|
||||||
class Includer {
|
class Includer {
|
||||||
public:
|
public:
|
||||||
// On success, returns the full path and content of the file with the given
|
typedef enum {
|
||||||
// filename that replaces "#include filename". On failure, returns an empty
|
EIncludeRelative, // For #include "something"
|
||||||
// string and an error message.
|
EIncludeStandard // Reserved. For #include <something>
|
||||||
virtual std::pair<std::string, std::string> include(const char* filename) const = 0;
|
} IncludeType;
|
||||||
|
|
||||||
|
// An IncludeResult contains the resolved name and content of a source
|
||||||
|
// inclusion.
|
||||||
|
struct IncludeResult {
|
||||||
|
// For a successful inclusion, the fully resolved name of the requested
|
||||||
|
// include. For example, in a filesystem-based includer, full resolution
|
||||||
|
// should convert a relative path name into an absolute path name.
|
||||||
|
// For a failed inclusion, this is an empty string.
|
||||||
|
std::string file_name;
|
||||||
|
// The content and byte length of the requested inclusion. The
|
||||||
|
// Includer producing this IncludeResult retains ownership of the
|
||||||
|
// storage.
|
||||||
|
// For a failed inclusion, the file_data
|
||||||
|
// field points to a string containing error details.
|
||||||
|
const char* file_data;
|
||||||
|
const size_t file_length;
|
||||||
|
// Include resolver's context.
|
||||||
|
void* user_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Resolves an inclusion request by name, type, current source name,
|
||||||
|
// and include depth.
|
||||||
|
// On success, returns an IncludeResult containing the resolved name
|
||||||
|
// and content of the include. On failure, returns an IncludeResult
|
||||||
|
// with an empty string for the file_name and error details in the
|
||||||
|
// file_data field. The Includer retains ownership of the contents
|
||||||
|
// of the returned IncludeResult value, and those contents must
|
||||||
|
// remain valid until the releaseInclude method is called on that
|
||||||
|
// IncludeResult object.
|
||||||
|
virtual IncludeResult* include(const char* requested_source,
|
||||||
|
IncludeType type,
|
||||||
|
const char* requesting_source,
|
||||||
|
size_t inclusion_depth) = 0;
|
||||||
|
// Signals that the parser will no longer use the contents of the
|
||||||
|
// specified IncludeResult.
|
||||||
|
virtual void releaseInclude(IncludeResult* result) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns an error message for any #include directive.
|
// Returns an error message for any #include directive.
|
||||||
class ForbidInclude : public Includer {
|
class ForbidInclude : public Includer {
|
||||||
public:
|
public:
|
||||||
std::pair<std::string, std::string> include(const char* /*filename*/) const override
|
IncludeResult* include(const char*, IncludeType, const char*, size_t) override
|
||||||
{
|
{
|
||||||
return std::make_pair<std::string, std::string>("", "unexpected include directive");
|
static const char unexpected_include[] =
|
||||||
|
"unexpected include directive";
|
||||||
|
static const IncludeResult unexpectedIncludeResult =
|
||||||
|
{"", unexpected_include, sizeof(unexpected_include) - 1, nullptr};
|
||||||
|
return new IncludeResult(unexpectedIncludeResult);
|
||||||
|
}
|
||||||
|
virtual void releaseInclude(IncludeResult* result) override
|
||||||
|
{
|
||||||
|
delete result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool parse(const TBuiltInResource* res, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
||||||
|
bool forwardCompatible, EShMessages messages)
|
||||||
|
{
|
||||||
|
TShader::ForbidInclude includer;
|
||||||
|
return parse(res, defaultVersion, defaultProfile, forceDefaultVersionAndProfile, forwardCompatible, messages, includer);
|
||||||
|
}
|
||||||
|
|
||||||
bool parse(const TBuiltInResource*, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
bool parse(const TBuiltInResource*, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
||||||
bool forwardCompatible, EShMessages, const Includer& = ForbidInclude());
|
bool forwardCompatible, EShMessages, Includer&);
|
||||||
|
|
||||||
// Equivalent to parse() without a default profile and without forcing defaults.
|
// Equivalent to parse() without a default profile and without forcing defaults.
|
||||||
// Provided for backwards compatibility.
|
// Provided for backwards compatibility.
|
||||||
@ -318,7 +383,7 @@ public:
|
|||||||
bool preprocess(const TBuiltInResource* builtInResources,
|
bool preprocess(const TBuiltInResource* builtInResources,
|
||||||
int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
||||||
bool forwardCompatible, EShMessages message, std::string* outputString,
|
bool forwardCompatible, EShMessages message, std::string* outputString,
|
||||||
const TShader::Includer& includer);
|
Includer& includer);
|
||||||
|
|
||||||
const char* getInfoLog();
|
const char* getInfoLog();
|
||||||
const char* getInfoDebugLog();
|
const char* getInfoDebugLog();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user