Merge pull request #222 from Qining/support-precise

Full stack: Support *precise* qualifier
This commit is contained in:
John Kessenich 2016-05-09 20:18:33 -06:00
commit 3357d870e4
15 changed files with 3372 additions and 39 deletions

View File

@ -33,8 +33,6 @@
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//POSSIBILITY OF SUCH DAMAGE. //POSSIBILITY OF SUCH DAMAGE.
//
// Author: John Kessenich, LunarG
// //
// Visit the nodes in the glslang intermediate tree representation to // Visit the nodes in the glslang intermediate tree representation to
// translate them to SPIR-V. // translate them to SPIR-V.
@ -135,10 +133,10 @@ protected:
spv::Id createImageTextureFunctionCall(glslang::TIntermOperator* node); spv::Id createImageTextureFunctionCall(glslang::TIntermOperator* node);
spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*); spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);
spv::Id createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison = true); spv::Id createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison = true);
spv::Id createBinaryMatrixOperation(spv::Op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right); spv::Id createBinaryMatrixOperation(spv::Op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id left, spv::Id right);
spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand,glslang::TBasicType typeProxy); spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand,glslang::TBasicType typeProxy);
spv::Id createUnaryMatrixOperation(spv::Op, spv::Decoration precision, spv::Id typeId, spv::Id operand,glslang::TBasicType typeProxy); spv::Id createUnaryMatrixOperation(spv::Op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand,glslang::TBasicType typeProxy);
spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destTypeId, spv::Id operand); spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destTypeId, spv::Id operand);
spv::Id makeSmearedConstant(spv::Id constant, int vectorSize); spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);
spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy); spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy);
@ -244,7 +242,7 @@ spv::StorageClass TranslateStorageClass(const glslang::TType& type)
case glslang::EvqGlobal: return spv::StorageClassPrivate; case glslang::EvqGlobal: return spv::StorageClassPrivate;
case glslang::EvqConstReadOnly: return spv::StorageClassFunction; case glslang::EvqConstReadOnly: return spv::StorageClassFunction;
case glslang::EvqTemporary: return spv::StorageClassFunction; case glslang::EvqTemporary: return spv::StorageClassFunction;
default: default:
assert(0); assert(0);
return spv::StorageClassFunction; return spv::StorageClassFunction;
} }
@ -385,6 +383,15 @@ spv::Decoration TranslateInvariantDecoration(const glslang::TQualifier& qualifie
return (spv::Decoration)spv::BadValue; return (spv::Decoration)spv::BadValue;
} }
// If glslang type is noContraction, return SPIR-V NoContraction decoration.
spv::Decoration TranslateNoContractionDecoration(const glslang::TQualifier& qualifier)
{
if (qualifier.noContraction)
return spv::DecorationNoContraction;
else
return (spv::Decoration)spv::BadValue;
}
// Translate glslang built-in variable to SPIR-V built in decoration. // Translate glslang built-in variable to SPIR-V built in decoration.
spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn) spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn)
{ {
@ -558,7 +565,7 @@ spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TTy
} }
} }
// Return whether or not the given type is something that should be tied to a // Return whether or not the given type is something that should be tied to a
// descriptor set. // descriptor set.
bool IsDescriptorResource(const glslang::TType& type) bool IsDescriptorResource(const glslang::TType& type)
{ {
@ -782,7 +789,7 @@ TGlslangToSpvTraverser::~TGlslangToSpvTraverser()
// //
// //
// Symbols can turn into // Symbols can turn into
// - uniform/input reads // - uniform/input reads
// - output writes // - output writes
// - complex lvalue base setups: foo.bar[3].... , where we see foo and start up an access chain // - complex lvalue base setups: foo.bar[3].... , where we see foo and start up an access chain
@ -873,7 +880,8 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
spv::Id leftRValue = accessChainLoad(node->getLeft()->getType()); spv::Id leftRValue = accessChainLoad(node->getLeft()->getType());
// do the operation // do the operation
rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()), rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()),
TranslateNoContractionDecoration(node->getType().getQualifier()),
convertGlslangToSpvType(node->getType()), leftRValue, rValue, convertGlslangToSpvType(node->getType()), leftRValue, rValue,
node->getType().getBasicType()); node->getType().getBasicType());
@ -992,6 +1000,7 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
// get result // get result
spv::Id result = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()), spv::Id result = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()),
TranslateNoContractionDecoration(node->getType().getQualifier()),
convertGlslangToSpvType(node->getType()), left, right, convertGlslangToSpvType(node->getType()), left, right,
node->getLeft()->getType().getBasicType()); node->getLeft()->getType().getBasicType());
@ -1058,6 +1067,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
operand = accessChainLoad(node->getOperand()->getType()); operand = accessChainLoad(node->getOperand()->getType());
spv::Decoration precision = TranslatePrecisionDecoration(node->getType()); spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
spv::Decoration noContraction = TranslateNoContractionDecoration(node->getType().getQualifier());
// it could be a conversion // it could be a conversion
if (! result) if (! result)
@ -1065,7 +1075,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
// if not, then possibly an operation // if not, then possibly an operation
if (! result) if (! result)
result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType()); result = createUnaryOperation(node->getOp(), precision, noContraction, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType());
if (result) { if (result) {
builder.clearAccessChain(); builder.clearAccessChain();
@ -1096,7 +1106,8 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
else else
op = glslang::EOpSub; op = glslang::EOpSub;
spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()), spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()),
TranslateNoContractionDecoration(node->getType().getQualifier()),
convertGlslangToSpvType(node->getType()), operand, one, convertGlslangToSpvType(node->getType()), operand, one,
node->getType().getBasicType()); node->getType().getBasicType());
assert(result != spv::NoResult); assert(result != spv::NoResult);
@ -1331,7 +1342,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
break; break;
} }
case glslang::EOpMul: case glslang::EOpMul:
// compontent-wise matrix multiply // compontent-wise matrix multiply
binOp = glslang::EOpMul; binOp = glslang::EOpMul;
break; break;
case glslang::EOpOuterProduct: case glslang::EOpOuterProduct:
@ -1340,7 +1351,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
break; break;
case glslang::EOpDot: case glslang::EOpDot:
{ {
// for scalar dot product, use multiply // for scalar dot product, use multiply
glslang::TIntermSequence& glslangOperands = node->getSequence(); glslang::TIntermSequence& glslangOperands = node->getSequence();
if (! glslangOperands[0]->getAsTyped()->isVector()) if (! glslangOperands[0]->getAsTyped()->isVector())
binOp = glslang::EOpMul; binOp = glslang::EOpMul;
@ -1395,8 +1406,8 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
right->traverse(this); right->traverse(this);
spv::Id rightId = accessChainLoad(right->getType()); spv::Id rightId = accessChainLoad(right->getType());
result = createBinaryOperation(binOp, precision, result = createBinaryOperation(binOp, precision, TranslateNoContractionDecoration(node->getType().getQualifier()),
convertGlslangToSpvType(node->getType()), leftId, rightId, convertGlslangToSpvType(node->getType()), leftId, rightId,
left->getType().getBasicType(), reduceComparison); left->getType().getBasicType(), reduceComparison);
// code above should only make binOp that exists in createBinaryOperation // code above should only make binOp that exists in createBinaryOperation
@ -1469,7 +1480,11 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
result = createNoArgOperation(node->getOp()); result = createNoArgOperation(node->getOp());
break; break;
case 1: case 1:
result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), glslangOperands[0]->getAsTyped()->getBasicType()); result = createUnaryOperation(
node->getOp(), precision,
TranslateNoContractionDecoration(node->getType().getQualifier()),
convertGlslangToSpvType(node->getType()), operands.front(),
glslangOperands[0]->getAsTyped()->getBasicType());
break; break;
default: default:
result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType()); result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType());
@ -1560,7 +1575,7 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T
codeSegments.push_back(child); codeSegments.push_back(child);
} }
// handle the case where the last code segment is missing, due to no code // handle the case where the last code segment is missing, due to no code
// statements between the last case and the end of the switch statement // statements between the last case and the end of the switch statement
if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) || if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) ||
(int)codeSegments.size() == defaultSegment) (int)codeSegments.size() == defaultSegment)
@ -1695,7 +1710,7 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T
spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node) spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node)
{ {
// 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().isConstant()) { if (node->getQualifier().isConstant()) {
@ -1999,7 +2014,7 @@ spv::Id TGlslangToSpvTraverser::makeArraySizeId(const glslang::TArraySizes& arra
specNode->traverse(this); specNode->traverse(this);
return accessChainLoad(specNode->getAsTyped()->getType()); return accessChainLoad(specNode->getAsTyped()->getType());
} }
// Otherwise, need a compile-time (front end) size, get it: // Otherwise, need a compile-time (front end) size, get it:
int size = arraySizes.getDimSize(dim); int size = arraySizes.getDimSize(dim);
assert(size > 0); assert(size > 0);
@ -2146,7 +2161,7 @@ void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& /*structTy
// Getting this far means we need explicit offsets // Getting this far means we need explicit offsets
if (currentOffset < 0) if (currentOffset < 0)
currentOffset = 0; currentOffset = 0;
// Now, currentOffset is valid (either 0, or from a previous nextOffset), // Now, currentOffset is valid (either 0, or from a previous nextOffset),
// but possibly not yet correctly aligned. // but possibly not yet correctly aligned.
@ -2176,7 +2191,7 @@ void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslF
// so that it's available to call. // so that it's available to call.
// Translating the body will happen later. // Translating the body will happen later.
// //
// Typically (except for a "const in" parameter), an address will be passed to the // Typically (except for a "const in" parameter), an address will be passed to the
// function. What it is an address of varies: // function. What it is an address of varies:
// //
// - "in" parameters not marked as "const" can be written to without modifying the argument, // - "in" parameters not marked as "const" can be written to without modifying the argument,
@ -2246,7 +2261,7 @@ void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glsl
void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node) void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node)
{ {
// SPIR-V functions should already be in the functionMap from the prepass // SPIR-V functions should already be in the functionMap from the prepass
// that called makeFunctions(). // that called makeFunctions().
spv::Function* function = functionMap[node->getName().c_str()]; spv::Function* function = functionMap[node->getName().c_str()];
spv::Block* functionBlock = function->getEntryBlock(); spv::Block* functionBlock = function->getEntryBlock();
@ -2660,7 +2675,8 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg
} }
// Translate AST operation to SPV operation, already having SPV-based operands/types. // Translate AST operation to SPV operation, already having SPV-based operands/types.
spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv::Decoration precision,
spv::Decoration noContraction,
spv::Id typeId, spv::Id left, spv::Id right, spv::Id typeId, spv::Id left, spv::Id right,
glslang::TBasicType typeProxy, bool reduceComparison) glslang::TBasicType typeProxy, bool reduceComparison)
{ {
@ -2797,13 +2813,15 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv
if (binOp != spv::OpNop) { if (binOp != spv::OpNop) {
assert(comparison == false); assert(comparison == false);
if (builder.isMatrix(left) || builder.isMatrix(right)) if (builder.isMatrix(left) || builder.isMatrix(right))
return createBinaryMatrixOperation(binOp, precision, typeId, left, right); return createBinaryMatrixOperation(binOp, precision, noContraction, typeId, left, right);
// No matrix involved; make both operands be the same number of components, if needed // No matrix involved; make both operands be the same number of components, if needed
if (needMatchingVectors) if (needMatchingVectors)
builder.promoteScalar(precision, left, right); builder.promoteScalar(precision, left, right);
return builder.setPrecision(builder.createBinOp(binOp, typeId, left, right), precision); spv::Id result = builder.createBinOp(binOp, typeId, left, right);
addDecoration(result, noContraction);
return builder.setPrecision(result, precision);
} }
if (! comparison) if (! comparison)
@ -2872,8 +2890,11 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv
break; break;
} }
if (binOp != spv::OpNop) if (binOp != spv::OpNop) {
return builder.setPrecision(builder.createBinOp(binOp, typeId, left, right), precision); spv::Id result = builder.createBinOp(binOp, typeId, left, right);
addDecoration(result, noContraction);
return builder.setPrecision(result, precision);
}
return 0; return 0;
} }
@ -2892,7 +2913,7 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv
// matrix op scalar op in {+, -, /} // matrix op scalar op in {+, -, /}
// scalar op matrix op in {+, -, /} // scalar op matrix op in {+, -, /}
// //
spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right) spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id left, spv::Id right)
{ {
bool firstClass = true; bool firstClass = true;
@ -2928,8 +2949,11 @@ spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Dec
break; break;
} }
if (firstClass) if (firstClass) {
return builder.setPrecision(builder.createBinOp(op, typeId, left, right), precision); spv::Id result = builder.createBinOp(op, typeId, left, right);
addDecoration(result, noContraction);
return builder.setPrecision(result, precision);
}
// Handle component-wise +, -, *, and / for all combinations of type. // Handle component-wise +, -, *, and / for all combinations of type.
// The result type of all of them is the same type as the (a) matrix operand. // The result type of all of them is the same type as the (a) matrix operand.
@ -2964,8 +2988,9 @@ spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Dec
indexes.push_back(c); indexes.push_back(c);
spv::Id leftVec = leftMat ? builder.createCompositeExtract( left, vecType, indexes) : smearVec; spv::Id leftVec = leftMat ? builder.createCompositeExtract( left, vecType, indexes) : smearVec;
spv::Id rightVec = rightMat ? builder.createCompositeExtract(right, vecType, indexes) : smearVec; spv::Id rightVec = rightMat ? builder.createCompositeExtract(right, vecType, indexes) : smearVec;
results.push_back(builder.createBinOp(op, vecType, leftVec, rightVec)); spv::Id result = builder.createBinOp(op, vecType, leftVec, rightVec);
builder.setPrecision(results.back(), precision); addDecoration(result, noContraction);
results.push_back(builder.setPrecision(result, precision));
} }
// put the pieces together // put the pieces together
@ -2977,7 +3002,7 @@ spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Dec
} }
} }
spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, glslang::TBasicType typeProxy) spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand, glslang::TBasicType typeProxy)
{ {
spv::Op unaryOp = spv::OpNop; spv::Op unaryOp = spv::OpNop;
int libCall = -1; int libCall = -1;
@ -2989,7 +3014,7 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv:
if (isFloat) { if (isFloat) {
unaryOp = spv::OpFNegate; unaryOp = spv::OpFNegate;
if (builder.isMatrixType(typeId)) if (builder.isMatrixType(typeId))
return createUnaryMatrixOperation(unaryOp, precision, typeId, operand, typeProxy); return createUnaryMatrixOperation(unaryOp, precision, noContraction, typeId, operand, typeProxy);
} else } else
unaryOp = spv::OpSNegate; unaryOp = spv::OpSNegate;
break; break;
@ -3271,11 +3296,12 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv:
id = builder.createUnaryOp(unaryOp, typeId, operand); id = builder.createUnaryOp(unaryOp, typeId, operand);
} }
addDecoration(id, noContraction);
return builder.setPrecision(id, precision); return builder.setPrecision(id, precision);
} }
// Create a unary operation on a matrix // Create a unary operation on a matrix
spv::Id TGlslangToSpvTraverser::createUnaryMatrixOperation(spv::Op op, spv::Decoration precision, spv::Id typeId, spv::Id operand, glslang::TBasicType /* typeProxy */) spv::Id TGlslangToSpvTraverser::createUnaryMatrixOperation(spv::Op op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand, glslang::TBasicType /* typeProxy */)
{ {
// Handle unary operations vector by vector. // Handle unary operations vector by vector.
// The result type is the same type as the original type. // The result type is the same type as the original type.
@ -3296,8 +3322,9 @@ spv::Id TGlslangToSpvTraverser::createUnaryMatrixOperation(spv::Op op, spv::Deco
std::vector<unsigned int> indexes; std::vector<unsigned int> indexes;
indexes.push_back(c); indexes.push_back(c);
spv::Id vec = builder.createCompositeExtract(operand, vecType, indexes); spv::Id vec = builder.createCompositeExtract(operand, vecType, indexes);
results.push_back(builder.createUnaryOp(op, vecType, vec)); spv::Id vec_result = builder.createUnaryOp(op, vecType, vec);
builder.setPrecision(results.back(), precision); addDecoration(vec_result, noContraction);
results.push_back(builder.setPrecision(vec_result, precision));
} }
// put the pieces together // put the pieces together
@ -4125,7 +4152,7 @@ bool TGlslangToSpvTraverser::isTrivialLeaf(const glslang::TIntermTyped* node)
default: default:
return false; return false;
} }
} }
// A node is trivial if it is a single operation with no side effects. // A node is trivial if it is a single operation with no side effects.
// Error on the side of saying non-trivial. // Error on the side of saying non-trivial.

View File

@ -0,0 +1,768 @@
precise.tesc
Warning, version 450 is not yet complete; most version-specific features are present, but some are missing.
Shader version: 450
Requested GL_EXT_gpu_shader5
Requested GL_EXT_shader_io_blocks
Requested GL_EXT_tessellation_shader
vertices = -1
0:? Sequence
0:5 Function Definition: minimal( (global float)
0:5 Function Parameters:
0:6 Sequence
0:6 Sequence
0:6 move second child to first child (temp float)
0:6 'result' (noContraction temp float)
0:6 Constant:
0:6 5.000000
0:7 Sequence
0:7 move second child to first child (temp float)
0:7 'a' (noContraction temp float)
0:7 Constant:
0:7 10.000000
0:8 Sequence
0:8 move second child to first child (temp float)
0:8 'b' (noContraction temp float)
0:8 Constant:
0:8 20.000000
0:9 Sequence
0:9 move second child to first child (temp float)
0:9 'c' (noContraction temp float)
0:9 Constant:
0:9 30.000000
0:10 Sequence
0:10 move second child to first child (temp float)
0:10 'd' (noContraction temp float)
0:10 Constant:
0:10 40.000000
0:11 move second child to first child (temp float)
0:11 'result' (noContraction temp float)
0:11 add (noContraction temp float)
0:11 component-wise multiply (noContraction temp float)
0:11 'a' (noContraction temp float)
0:11 'b' (noContraction temp float)
0:11 component-wise multiply (noContraction temp float)
0:11 'c' (noContraction temp float)
0:11 'd' (noContraction temp float)
0:12 Branch: Return with expression
0:12 'result' (noContraction temp float)
0:15 Function Definition: continuous_assignment( (global void)
0:15 Function Parameters:
0:16 Sequence
0:16 Sequence
0:16 move second child to first child (temp float)
0:16 'result' (noContraction temp float)
0:16 Constant:
0:16 5.000000
0:17 Sequence
0:17 move second child to first child (temp float)
0:17 'a' (noContraction temp float)
0:17 Constant:
0:17 10.000000
0:18 Sequence
0:18 move second child to first child (temp float)
0:18 'b' (noContraction temp float)
0:18 Constant:
0:18 20.000000
0:19 move second child to first child (temp float)
0:19 'result' (noContraction temp float)
0:19 move second child to first child (temp float)
0:19 'a' (noContraction temp float)
0:19 add (noContraction temp float)
0:19 'b' (noContraction temp float)
0:19 Constant:
0:19 4.000000
0:22 Function Definition: convert( (global void)
0:22 Function Parameters:
0:? Sequence
0:24 Sequence
0:24 move second child to first child (temp float)
0:24 'a' (noContraction temp float)
0:24 Constant:
0:24 10.000000
0:25 Sequence
0:25 move second child to first child (temp float)
0:25 'b' (noContraction temp float)
0:25 Constant:
0:25 20.000000
0:26 move second child to first child (temp float)
0:26 'b' (noContraction temp float)
0:26 add (noContraction temp float)
0:26 'a' (noContraction temp float)
0:26 'b' (noContraction temp float)
0:27 move second child to first child (temp double)
0:27 'result' (noContraction temp double)
0:27 Convert float to double (temp double)
0:27 'b' (noContraction temp float)
0:30 Function Definition: loop_for( (global float)
0:30 Function Parameters:
0:31 Sequence
0:31 Sequence
0:31 move second child to first child (temp float)
0:31 'r1' (noContraction temp float)
0:31 Constant:
0:31 5.000000
0:32 Sequence
0:32 move second child to first child (temp float)
0:32 'r2' (noContraction temp float)
0:32 Constant:
0:32 10.000000
0:33 Sequence
0:33 move second child to first child (temp int)
0:33 'a' (temp int)
0:33 Constant:
0:33 10 (const int)
0:34 Sequence
0:34 move second child to first child (temp int)
0:34 'b' (noContraction temp int)
0:34 Constant:
0:34 20 (const int)
0:35 Sequence
0:35 move second child to first child (temp int)
0:35 'c' (noContraction temp int)
0:35 Constant:
0:35 30 (const int)
0:36 Sequence
0:36 Sequence
0:36 move second child to first child (temp int)
0:36 'i' (noContraction temp int)
0:36 Constant:
0:36 0 (const int)
0:36 Loop with condition tested first
0:36 Loop Condition
0:36 Compare Less Than (temp bool)
0:36 'i' (temp int)
0:36 'a' (temp int)
0:36 Loop Body
0:37 Sequence
0:37 add second child into first child (noContraction temp float)
0:37 'r1' (noContraction temp float)
0:37 add (noContraction temp float)
0:37 add (noContraction temp float)
0:37 Constant:
0:37 3.120000
0:37 Convert int to float (temp float)
0:37 'b' (noContraction temp int)
0:37 Convert int to float (temp float)
0:37 'i' (noContraction temp int)
0:38 add second child into first child (noContraction temp int)
0:38 'c' (noContraction temp int)
0:38 Constant:
0:38 1 (const int)
0:36 Loop Terminal Expression
0:36 Post-Increment (noContraction temp int)
0:36 'i' (noContraction temp int)
0:40 add second child into first child (temp int)
0:40 'a' (temp int)
0:40 Constant:
0:40 1 (const int)
0:41 move second child to first child (temp float)
0:41 'r2' (noContraction temp float)
0:41 Convert int to float (temp float)
0:41 'c' (noContraction temp int)
0:42 Branch: Return with expression
0:42 Construct float (temp float)
0:42 add (temp float)
0:42 'r1' (noContraction temp float)
0:42 'r2' (noContraction temp float)
0:45 Function Definition: loop_array( (global void)
0:45 Function Parameters:
0:? Sequence
0:48 Sequence
0:48 move second child to first child (temp int)
0:48 'x' (noContraction temp int)
0:48 Constant:
0:48 22 (const int)
0:49 Sequence
0:49 move second child to first child (temp int)
0:49 'y' (noContraction temp int)
0:49 Constant:
0:49 33 (const int)
0:52 add second child into first child (noContraction temp float)
0:52 'result' (noContraction temp float)
0:52 add (noContraction temp float)
0:52 Convert int to float (temp float)
0:52 'x' (noContraction temp int)
0:52 Convert int to float (temp float)
0:52 'y' (noContraction temp int)
0:54 Sequence
0:54 Sequence
0:54 move second child to first child (temp int)
0:54 'i' (temp int)
0:54 Constant:
0:54 0 (const int)
0:54 Loop with condition tested first
0:54 Loop Condition
0:54 Compare Less Than (temp bool)
0:54 'i' (temp int)
0:54 Constant:
0:54 3 (const int)
0:54 Loop Body
0:56 Sequence
0:56 add second child into first child (noContraction temp float)
0:56 'result' (noContraction temp float)
0:56 add (noContraction temp float)
0:56 indirect index (noContraction temp float)
0:56 'a0' (temp 3-element array of float)
0:56 'i' (temp int)
0:56 Constant:
0:56 2.000000
0:58 move second child to first child (temp float)
0:58 indirect index (noContraction temp float)
0:58 'a0' (noContraction temp 3-element array of float)
0:58 'i' (temp int)
0:58 subtract (noContraction temp float)
0:58 Constant:
0:58 3.000000
0:58 Post-Increment (noContraction temp float)
0:58 'result' (noContraction temp float)
0:54 Loop Terminal Expression
0:54 Pre-Increment (temp int)
0:54 'i' (temp int)
0:62 Function Definition: loop_while( (global void)
0:62 Function Parameters:
0:63 Sequence
0:63 Sequence
0:63 move second child to first child (temp float)
0:63 'result' (noContraction temp float)
0:63 Constant:
0:63 5.000000
0:64 Sequence
0:64 move second child to first child (temp int)
0:64 'a' (noContraction temp int)
0:64 Constant:
0:64 10 (const int)
0:65 Sequence
0:65 move second child to first child (temp int)
0:65 'b' (noContraction temp int)
0:65 Constant:
0:65 20 (const int)
0:66 Loop with condition tested first
0:66 Loop Condition
0:66 Compare Less Than (temp bool)
0:66 'result' (noContraction temp float)
0:66 Constant:
0:66 10.000000
0:66 Loop Body
0:67 Sequence
0:67 add second child into first child (noContraction temp float)
0:67 'result' (noContraction temp float)
0:67 add (noContraction temp float)
0:67 Constant:
0:67 3.120000
0:67 Convert int to float (temp float)
0:67 'b' (noContraction temp int)
0:69 move second child to first child (temp float)
0:69 'result' (noContraction temp float)
0:69 Convert int to float (temp float)
0:69 add (temp int)
0:69 add (temp int)
0:69 'a' (noContraction temp int)
0:69 'b' (noContraction temp int)
0:69 Constant:
0:69 5 (const int)
0:70 move second child to first child (temp float)
0:70 'result' (noContraction temp float)
0:70 Constant:
0:70 11.100000
0:73 Function Definition: fma_not_decorated( (global float)
0:73 Function Parameters:
0:? Sequence
0:75 Sequence
0:75 move second child to first child (temp float)
0:75 'a' (noContraction temp float)
0:75 Constant:
0:75 1.000000
0:76 Sequence
0:76 move second child to first child (temp float)
0:76 'b' (noContraction temp float)
0:76 Constant:
0:76 2.000000
0:77 Sequence
0:77 move second child to first child (temp float)
0:77 'c' (noContraction temp float)
0:77 Constant:
0:77 3.000000
0:78 move second child to first child (temp float)
0:78 'b' (noContraction temp float)
0:78 add (noContraction temp float)
0:78 'b' (noContraction temp float)
0:78 'c' (noContraction temp float)
0:79 move second child to first child (temp float)
0:79 'result' (noContraction temp float)
0:79 fma (global float)
0:79 'a' (noContraction temp float)
0:79 'b' (noContraction temp float)
0:79 'c' (noContraction temp float)
0:80 Branch: Return with expression
0:80 'result' (noContraction temp float)
0:83 Function Definition: precise_return_exp_func( (noContraction temp float)
0:83 Function Parameters:
0:84 Sequence
0:84 Sequence
0:84 move second child to first child (temp float)
0:84 'a' (noContraction temp float)
0:84 Constant:
0:84 1.000000
0:85 Sequence
0:85 move second child to first child (temp float)
0:85 'b' (noContraction temp float)
0:85 Constant:
0:85 2.000000
0:86 Branch: Return with expression
0:86 add (noContraction temp float)
0:86 'a' (noContraction temp float)
0:86 'b' (noContraction temp float)
0:89 Function Definition: precise_return_val_func( (noContraction temp float)
0:89 Function Parameters:
0:90 Sequence
0:90 Sequence
0:90 move second child to first child (temp float)
0:90 'a' (noContraction temp float)
0:90 Constant:
0:90 1.000000
0:91 Sequence
0:91 move second child to first child (temp float)
0:91 'b' (noContraction temp float)
0:91 Constant:
0:91 2.000000
0:92 Sequence
0:92 move second child to first child (temp float)
0:92 'result' (noContraction temp float)
0:92 add (noContraction temp float)
0:92 'a' (noContraction temp float)
0:92 'b' (noContraction temp float)
0:93 Branch: Return with expression
0:93 'result' (noContraction temp float)
0:96 Function Definition: precise_func_parameter(f1;f1; (global float)
0:96 Function Parameters:
0:96 'b' (in float)
0:96 'c' (noContraction out float)
0:97 Sequence
0:97 Sequence
0:97 move second child to first child (temp float)
0:97 'a' (noContraction temp float)
0:97 Constant:
0:97 0.500000
0:98 move second child to first child (temp float)
0:98 'c' (noContraction out float)
0:98 add (noContraction temp float)
0:98 'a' (noContraction temp float)
0:98 'b' (noContraction in float)
0:99 Branch: Return with expression
0:99 subtract (temp float)
0:99 'a' (temp float)
0:99 'b' (in float)
0:102 Function Definition: matrix(mf23;mf32; (global 3X3 matrix of float)
0:102 Function Parameters:
0:102 'a' (in 2X3 matrix of float)
0:102 'b' (in 3X2 matrix of float)
0:103 Sequence
0:103 Sequence
0:103 move second child to first child (temp 2X3 matrix of float)
0:103 'c' (noContraction temp 2X3 matrix of float)
0:103 Constant:
0:103 1.000000
0:103 2.000000
0:103 3.000000
0:103 4.000000
0:103 5.000000
0:103 6.000000
0:105 move second child to first child (temp 3X3 matrix of float)
0:105 'result' (noContraction temp 3X3 matrix of float)
0:105 matrix-multiply (noContraction temp 3X3 matrix of float)
0:105 add (noContraction temp 2X3 matrix of float)
0:105 'a' (noContraction in 2X3 matrix of float)
0:105 'c' (noContraction temp 2X3 matrix of float)
0:105 'b' (noContraction in 3X2 matrix of float)
0:106 Branch: Return with expression
0:106 'result' (noContraction temp 3X3 matrix of float)
0:109 Function Definition: main( (global void)
0:109 Function Parameters:
0:? Linker Objects
Linked tessellation control stage:
ERROR: Linking tessellation control stage: At least one shader must specify an output layout(vertices=...)
Shader version: 450
Requested GL_EXT_gpu_shader5
Requested GL_EXT_shader_io_blocks
Requested GL_EXT_tessellation_shader
vertices = -1
0:? Sequence
0:5 Function Definition: minimal( (global float)
0:5 Function Parameters:
0:6 Sequence
0:6 Sequence
0:6 move second child to first child (temp float)
0:6 'result' (noContraction temp float)
0:6 Constant:
0:6 5.000000
0:7 Sequence
0:7 move second child to first child (temp float)
0:7 'a' (noContraction temp float)
0:7 Constant:
0:7 10.000000
0:8 Sequence
0:8 move second child to first child (temp float)
0:8 'b' (noContraction temp float)
0:8 Constant:
0:8 20.000000
0:9 Sequence
0:9 move second child to first child (temp float)
0:9 'c' (noContraction temp float)
0:9 Constant:
0:9 30.000000
0:10 Sequence
0:10 move second child to first child (temp float)
0:10 'd' (noContraction temp float)
0:10 Constant:
0:10 40.000000
0:11 move second child to first child (temp float)
0:11 'result' (noContraction temp float)
0:11 add (noContraction temp float)
0:11 component-wise multiply (noContraction temp float)
0:11 'a' (noContraction temp float)
0:11 'b' (noContraction temp float)
0:11 component-wise multiply (noContraction temp float)
0:11 'c' (noContraction temp float)
0:11 'd' (noContraction temp float)
0:12 Branch: Return with expression
0:12 'result' (noContraction temp float)
0:15 Function Definition: continuous_assignment( (global void)
0:15 Function Parameters:
0:16 Sequence
0:16 Sequence
0:16 move second child to first child (temp float)
0:16 'result' (noContraction temp float)
0:16 Constant:
0:16 5.000000
0:17 Sequence
0:17 move second child to first child (temp float)
0:17 'a' (noContraction temp float)
0:17 Constant:
0:17 10.000000
0:18 Sequence
0:18 move second child to first child (temp float)
0:18 'b' (noContraction temp float)
0:18 Constant:
0:18 20.000000
0:19 move second child to first child (temp float)
0:19 'result' (noContraction temp float)
0:19 move second child to first child (temp float)
0:19 'a' (noContraction temp float)
0:19 add (noContraction temp float)
0:19 'b' (noContraction temp float)
0:19 Constant:
0:19 4.000000
0:22 Function Definition: convert( (global void)
0:22 Function Parameters:
0:? Sequence
0:24 Sequence
0:24 move second child to first child (temp float)
0:24 'a' (noContraction temp float)
0:24 Constant:
0:24 10.000000
0:25 Sequence
0:25 move second child to first child (temp float)
0:25 'b' (noContraction temp float)
0:25 Constant:
0:25 20.000000
0:26 move second child to first child (temp float)
0:26 'b' (noContraction temp float)
0:26 add (noContraction temp float)
0:26 'a' (noContraction temp float)
0:26 'b' (noContraction temp float)
0:27 move second child to first child (temp double)
0:27 'result' (noContraction temp double)
0:27 Convert float to double (temp double)
0:27 'b' (noContraction temp float)
0:30 Function Definition: loop_for( (global float)
0:30 Function Parameters:
0:31 Sequence
0:31 Sequence
0:31 move second child to first child (temp float)
0:31 'r1' (noContraction temp float)
0:31 Constant:
0:31 5.000000
0:32 Sequence
0:32 move second child to first child (temp float)
0:32 'r2' (noContraction temp float)
0:32 Constant:
0:32 10.000000
0:33 Sequence
0:33 move second child to first child (temp int)
0:33 'a' (temp int)
0:33 Constant:
0:33 10 (const int)
0:34 Sequence
0:34 move second child to first child (temp int)
0:34 'b' (noContraction temp int)
0:34 Constant:
0:34 20 (const int)
0:35 Sequence
0:35 move second child to first child (temp int)
0:35 'c' (noContraction temp int)
0:35 Constant:
0:35 30 (const int)
0:36 Sequence
0:36 Sequence
0:36 move second child to first child (temp int)
0:36 'i' (noContraction temp int)
0:36 Constant:
0:36 0 (const int)
0:36 Loop with condition tested first
0:36 Loop Condition
0:36 Compare Less Than (temp bool)
0:36 'i' (temp int)
0:36 'a' (temp int)
0:36 Loop Body
0:37 Sequence
0:37 add second child into first child (noContraction temp float)
0:37 'r1' (noContraction temp float)
0:37 add (noContraction temp float)
0:37 add (noContraction temp float)
0:37 Constant:
0:37 3.120000
0:37 Convert int to float (temp float)
0:37 'b' (noContraction temp int)
0:37 Convert int to float (temp float)
0:37 'i' (noContraction temp int)
0:38 add second child into first child (noContraction temp int)
0:38 'c' (noContraction temp int)
0:38 Constant:
0:38 1 (const int)
0:36 Loop Terminal Expression
0:36 Post-Increment (noContraction temp int)
0:36 'i' (noContraction temp int)
0:40 add second child into first child (temp int)
0:40 'a' (temp int)
0:40 Constant:
0:40 1 (const int)
0:41 move second child to first child (temp float)
0:41 'r2' (noContraction temp float)
0:41 Convert int to float (temp float)
0:41 'c' (noContraction temp int)
0:42 Branch: Return with expression
0:42 Construct float (temp float)
0:42 add (temp float)
0:42 'r1' (noContraction temp float)
0:42 'r2' (noContraction temp float)
0:45 Function Definition: loop_array( (global void)
0:45 Function Parameters:
0:? Sequence
0:48 Sequence
0:48 move second child to first child (temp int)
0:48 'x' (noContraction temp int)
0:48 Constant:
0:48 22 (const int)
0:49 Sequence
0:49 move second child to first child (temp int)
0:49 'y' (noContraction temp int)
0:49 Constant:
0:49 33 (const int)
0:52 add second child into first child (noContraction temp float)
0:52 'result' (noContraction temp float)
0:52 add (noContraction temp float)
0:52 Convert int to float (temp float)
0:52 'x' (noContraction temp int)
0:52 Convert int to float (temp float)
0:52 'y' (noContraction temp int)
0:54 Sequence
0:54 Sequence
0:54 move second child to first child (temp int)
0:54 'i' (temp int)
0:54 Constant:
0:54 0 (const int)
0:54 Loop with condition tested first
0:54 Loop Condition
0:54 Compare Less Than (temp bool)
0:54 'i' (temp int)
0:54 Constant:
0:54 3 (const int)
0:54 Loop Body
0:56 Sequence
0:56 add second child into first child (noContraction temp float)
0:56 'result' (noContraction temp float)
0:56 add (noContraction temp float)
0:56 indirect index (noContraction temp float)
0:56 'a0' (temp 3-element array of float)
0:56 'i' (temp int)
0:56 Constant:
0:56 2.000000
0:58 move second child to first child (temp float)
0:58 indirect index (noContraction temp float)
0:58 'a0' (noContraction temp 3-element array of float)
0:58 'i' (temp int)
0:58 subtract (noContraction temp float)
0:58 Constant:
0:58 3.000000
0:58 Post-Increment (noContraction temp float)
0:58 'result' (noContraction temp float)
0:54 Loop Terminal Expression
0:54 Pre-Increment (temp int)
0:54 'i' (temp int)
0:62 Function Definition: loop_while( (global void)
0:62 Function Parameters:
0:63 Sequence
0:63 Sequence
0:63 move second child to first child (temp float)
0:63 'result' (noContraction temp float)
0:63 Constant:
0:63 5.000000
0:64 Sequence
0:64 move second child to first child (temp int)
0:64 'a' (noContraction temp int)
0:64 Constant:
0:64 10 (const int)
0:65 Sequence
0:65 move second child to first child (temp int)
0:65 'b' (noContraction temp int)
0:65 Constant:
0:65 20 (const int)
0:66 Loop with condition tested first
0:66 Loop Condition
0:66 Compare Less Than (temp bool)
0:66 'result' (noContraction temp float)
0:66 Constant:
0:66 10.000000
0:66 Loop Body
0:67 Sequence
0:67 add second child into first child (noContraction temp float)
0:67 'result' (noContraction temp float)
0:67 add (noContraction temp float)
0:67 Constant:
0:67 3.120000
0:67 Convert int to float (temp float)
0:67 'b' (noContraction temp int)
0:69 move second child to first child (temp float)
0:69 'result' (noContraction temp float)
0:69 Convert int to float (temp float)
0:69 add (temp int)
0:69 add (temp int)
0:69 'a' (noContraction temp int)
0:69 'b' (noContraction temp int)
0:69 Constant:
0:69 5 (const int)
0:70 move second child to first child (temp float)
0:70 'result' (noContraction temp float)
0:70 Constant:
0:70 11.100000
0:73 Function Definition: fma_not_decorated( (global float)
0:73 Function Parameters:
0:? Sequence
0:75 Sequence
0:75 move second child to first child (temp float)
0:75 'a' (noContraction temp float)
0:75 Constant:
0:75 1.000000
0:76 Sequence
0:76 move second child to first child (temp float)
0:76 'b' (noContraction temp float)
0:76 Constant:
0:76 2.000000
0:77 Sequence
0:77 move second child to first child (temp float)
0:77 'c' (noContraction temp float)
0:77 Constant:
0:77 3.000000
0:78 move second child to first child (temp float)
0:78 'b' (noContraction temp float)
0:78 add (noContraction temp float)
0:78 'b' (noContraction temp float)
0:78 'c' (noContraction temp float)
0:79 move second child to first child (temp float)
0:79 'result' (noContraction temp float)
0:79 fma (global float)
0:79 'a' (noContraction temp float)
0:79 'b' (noContraction temp float)
0:79 'c' (noContraction temp float)
0:80 Branch: Return with expression
0:80 'result' (noContraction temp float)
0:83 Function Definition: precise_return_exp_func( (noContraction temp float)
0:83 Function Parameters:
0:84 Sequence
0:84 Sequence
0:84 move second child to first child (temp float)
0:84 'a' (noContraction temp float)
0:84 Constant:
0:84 1.000000
0:85 Sequence
0:85 move second child to first child (temp float)
0:85 'b' (noContraction temp float)
0:85 Constant:
0:85 2.000000
0:86 Branch: Return with expression
0:86 add (noContraction temp float)
0:86 'a' (noContraction temp float)
0:86 'b' (noContraction temp float)
0:89 Function Definition: precise_return_val_func( (noContraction temp float)
0:89 Function Parameters:
0:90 Sequence
0:90 Sequence
0:90 move second child to first child (temp float)
0:90 'a' (noContraction temp float)
0:90 Constant:
0:90 1.000000
0:91 Sequence
0:91 move second child to first child (temp float)
0:91 'b' (noContraction temp float)
0:91 Constant:
0:91 2.000000
0:92 Sequence
0:92 move second child to first child (temp float)
0:92 'result' (noContraction temp float)
0:92 add (noContraction temp float)
0:92 'a' (noContraction temp float)
0:92 'b' (noContraction temp float)
0:93 Branch: Return with expression
0:93 'result' (noContraction temp float)
0:96 Function Definition: precise_func_parameter(f1;f1; (global float)
0:96 Function Parameters:
0:96 'b' (in float)
0:96 'c' (noContraction out float)
0:97 Sequence
0:97 Sequence
0:97 move second child to first child (temp float)
0:97 'a' (noContraction temp float)
0:97 Constant:
0:97 0.500000
0:98 move second child to first child (temp float)
0:98 'c' (noContraction out float)
0:98 add (noContraction temp float)
0:98 'a' (noContraction temp float)
0:98 'b' (noContraction in float)
0:99 Branch: Return with expression
0:99 subtract (temp float)
0:99 'a' (temp float)
0:99 'b' (in float)
0:102 Function Definition: matrix(mf23;mf32; (global 3X3 matrix of float)
0:102 Function Parameters:
0:102 'a' (in 2X3 matrix of float)
0:102 'b' (in 3X2 matrix of float)
0:103 Sequence
0:103 Sequence
0:103 move second child to first child (temp 2X3 matrix of float)
0:103 'c' (noContraction temp 2X3 matrix of float)
0:103 Constant:
0:103 1.000000
0:103 2.000000
0:103 3.000000
0:103 4.000000
0:103 5.000000
0:103 6.000000
0:105 move second child to first child (temp 3X3 matrix of float)
0:105 'result' (noContraction temp 3X3 matrix of float)
0:105 matrix-multiply (noContraction temp 3X3 matrix of float)
0:105 add (noContraction temp 2X3 matrix of float)
0:105 'a' (noContraction in 2X3 matrix of float)
0:105 'c' (noContraction temp 2X3 matrix of float)
0:105 'b' (noContraction in 3X2 matrix of float)
0:106 Branch: Return with expression
0:106 'result' (noContraction temp 3X3 matrix of float)
0:109 Function Definition: main( (global void)
0:109 Function Parameters:
0:? Linker Objects

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,122 @@
spv.precise.tesc
Warning, version 310 is not yet complete; most version-specific features are present, but some are missing.
Linked tessellation control stage:
// Module Version 10000
// Generated by (magic number): 80001
// Id's are bound by 72
Capability Tessellation
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint TessellationControl 4 "main" 12 15 20 30 40 45
ExecutionMode 4 OutputVertices 3
Source ESSL 310
SourceExtension "GL_EXT_gpu_shader5"
SourceExtension "GL_EXT_shader_io_blocks"
SourceExtension "GL_EXT_tessellation_shader"
Name 4 "main"
Name 12 "in_te_position"
Name 15 "gl_InvocationID"
Name 20 "in_tc_position"
Name 30 "gl_TessLevelInner"
Name 40 "gl_TessLevelOuter"
Name 45 "in_tc_tessParam"
Decorate 12(in_te_position) Location 0
Decorate 15(gl_InvocationID) BuiltIn InvocationId
Decorate 20(in_tc_position) Location 0
Decorate 30(gl_TessLevelInner) Patch
Decorate 30(gl_TessLevelInner) BuiltIn TessLevelInner
Decorate 40(gl_TessLevelOuter) Patch
Decorate 40(gl_TessLevelOuter) BuiltIn TessLevelOuter
Decorate 45(in_tc_tessParam) Location 1
Decorate 52 NoContraction
Decorate 53 NoContraction
Decorate 54 NoContraction
Decorate 60 NoContraction
Decorate 61 NoContraction
Decorate 62 NoContraction
Decorate 68 NoContraction
Decorate 69 NoContraction
Decorate 70 NoContraction
2: TypeVoid
3: TypeFunction 2
6: TypeFloat 32
7: TypeVector 6(float) 2
8: TypeInt 32 0
9: 8(int) Constant 3
10: TypeArray 7(fvec2) 9
11: TypePointer Output 10
12(in_te_position): 11(ptr) Variable Output
13: TypeInt 32 1
14: TypePointer Input 13(int)
15(gl_InvocationID): 14(ptr) Variable Input
17: 8(int) Constant 32
18: TypeArray 7(fvec2) 17
19: TypePointer Input 18
20(in_tc_position): 19(ptr) Variable Input
22: TypePointer Input 7(fvec2)
25: TypePointer Output 7(fvec2)
27: 8(int) Constant 2
28: TypeArray 6(float) 27
29: TypePointer Output 28
30(gl_TessLevelInner): 29(ptr) Variable Output
31: 13(int) Constant 0
32: 6(float) Constant 1084227584
33: TypePointer Output 6(float)
35: 13(int) Constant 1
37: 8(int) Constant 4
38: TypeArray 6(float) 37
39: TypePointer Output 38
40(gl_TessLevelOuter): 39(ptr) Variable Output
41: 6(float) Constant 1065353216
42: 6(float) Constant 1105985536
43: TypeArray 6(float) 17
44: TypePointer Input 43
45(in_tc_tessParam): 44(ptr) Variable Input
46: TypePointer Input 6(float)
49: 13(int) Constant 2
4(main): 2 Function None 3
5: Label
16: 13(int) Load 15(gl_InvocationID)
21: 13(int) Load 15(gl_InvocationID)
23: 22(ptr) AccessChain 20(in_tc_position) 21
24: 7(fvec2) Load 23
26: 25(ptr) AccessChain 12(in_te_position) 16
Store 26 24
34: 33(ptr) AccessChain 30(gl_TessLevelInner) 31
Store 34 32
36: 33(ptr) AccessChain 30(gl_TessLevelInner) 35
Store 36 32
47: 46(ptr) AccessChain 45(in_tc_tessParam) 35
48: 6(float) Load 47
50: 46(ptr) AccessChain 45(in_tc_tessParam) 49
51: 6(float) Load 50
52: 6(float) FAdd 48 51
53: 6(float) FMul 42 52
54: 6(float) FAdd 41 53
55: 33(ptr) AccessChain 40(gl_TessLevelOuter) 31
Store 55 54
56: 46(ptr) AccessChain 45(in_tc_tessParam) 49
57: 6(float) Load 56
58: 46(ptr) AccessChain 45(in_tc_tessParam) 31
59: 6(float) Load 58
60: 6(float) FAdd 57 59
61: 6(float) FMul 42 60
62: 6(float) FAdd 41 61
63: 33(ptr) AccessChain 40(gl_TessLevelOuter) 35
Store 63 62
64: 46(ptr) AccessChain 45(in_tc_tessParam) 31
65: 6(float) Load 64
66: 46(ptr) AccessChain 45(in_tc_tessParam) 35
67: 6(float) Load 66
68: 6(float) FAdd 65 67
69: 6(float) FMul 42 68
70: 6(float) FAdd 41 69
71: 33(ptr) AccessChain 40(gl_TessLevelOuter) 49
Store 71 70
Return
FunctionEnd

View File

@ -0,0 +1,192 @@
spv.precise.tese
Warning, version 310 is not yet complete; most version-specific features are present, but some are missing.
Linked tessellation evaluation stage:
// Module Version 10000
// Generated by (magic number): 80001
// Id's are bound by 119
Capability Tessellation
Capability TessellationPointSize
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint TessellationEvaluation 4 "main" 12 21 62 112
ExecutionMode 4 Triangles
ExecutionMode 4 SpacingEqual
ExecutionMode 4 VertexOrderCcw
Source ESSL 310
SourceExtension "GL_EXT_gpu_shader5"
SourceExtension "GL_EXT_shader_io_blocks"
SourceExtension "GL_EXT_tessellation_shader"
Name 4 "main"
Name 9 "pos"
Name 12 "gl_TessCoord"
Name 21 "in_te_position"
Name 45 "f"
Name 62 "in_f_color"
Name 73 "bits"
Name 77 "numBits"
Name 78 "i"
Name 110 "gl_PerVertex"
MemberName 110(gl_PerVertex) 0 "gl_Position"
MemberName 110(gl_PerVertex) 1 "gl_PointSize"
Name 112 ""
Decorate 12(gl_TessCoord) BuiltIn TessCoord
Decorate 21(in_te_position) Location 0
Decorate 27 NoContraction
Decorate 34 NoContraction
Decorate 35 NoContraction
Decorate 42 NoContraction
Decorate 43 NoContraction
Decorate 62(in_f_color) RelaxedPrecision
Decorate 62(in_f_color) Location 0
Decorate 67 RelaxedPrecision
Decorate 68 RelaxedPrecision
Decorate 69 RelaxedPrecision
Decorate 70 RelaxedPrecision
Decorate 97 NoContraction
Decorate 99 NoContraction
Decorate 101 NoContraction
Decorate 106 NoContraction
Decorate 109 NoContraction
MemberDecorate 110(gl_PerVertex) 0 BuiltIn Position
MemberDecorate 110(gl_PerVertex) 1 BuiltIn PointSize
Decorate 110(gl_PerVertex) Block
2: TypeVoid
3: TypeFunction 2
6: TypeFloat 32
7: TypeVector 6(float) 2
8: TypePointer Function 7(fvec2)
10: TypeVector 6(float) 3
11: TypePointer Input 10(fvec3)
12(gl_TessCoord): 11(ptr) Variable Input
13: TypeInt 32 0
14: 13(int) Constant 0
15: TypePointer Input 6(float)
18: 13(int) Constant 32
19: TypeArray 7(fvec2) 18
20: TypePointer Input 19
21(in_te_position): 20(ptr) Variable Input
22: TypeInt 32 1
23: 22(int) Constant 0
24: TypePointer Input 7(fvec2)
28: 13(int) Constant 1
31: 22(int) Constant 1
36: 13(int) Constant 2
39: 22(int) Constant 2
44: TypePointer Function 6(float)
46: 6(float) Constant 1077936128
57: 6(float) Constant 1056964608
60: TypeVector 6(float) 4
61: TypePointer Output 60(fvec4)
62(in_f_color): 61(ptr) Variable Output
66: 6(float) Constant 1065353216
71: TypeVector 13(int) 2
72: TypePointer Function 71(ivec2)
76: TypePointer Function 13(int)
85: TypeBool
105: 6(float) Constant 1025758986
110(gl_PerVertex): TypeStruct 60(fvec4) 6(float)
111: TypePointer Output 110(gl_PerVertex)
112: 111(ptr) Variable Output
114: 6(float) Constant 0
4(main): 2 Function None 3
5: Label
9(pos): 8(ptr) Variable Function
45(f): 44(ptr) Variable Function
73(bits): 72(ptr) Variable Function
77(numBits): 76(ptr) Variable Function
78(i): 76(ptr) Variable Function
16: 15(ptr) AccessChain 12(gl_TessCoord) 14
17: 6(float) Load 16
25: 24(ptr) AccessChain 21(in_te_position) 23
26: 7(fvec2) Load 25
27: 7(fvec2) VectorTimesScalar 26 17
29: 15(ptr) AccessChain 12(gl_TessCoord) 28
30: 6(float) Load 29
32: 24(ptr) AccessChain 21(in_te_position) 31
33: 7(fvec2) Load 32
34: 7(fvec2) VectorTimesScalar 33 30
35: 7(fvec2) FAdd 27 34
37: 15(ptr) AccessChain 12(gl_TessCoord) 36
38: 6(float) Load 37
40: 24(ptr) AccessChain 21(in_te_position) 39
41: 7(fvec2) Load 40
42: 7(fvec2) VectorTimesScalar 41 38
43: 7(fvec2) FAdd 35 42
Store 9(pos) 43
47: 15(ptr) AccessChain 12(gl_TessCoord) 14
48: 6(float) Load 47
49: 15(ptr) AccessChain 12(gl_TessCoord) 28
50: 6(float) Load 49
51: 15(ptr) AccessChain 12(gl_TessCoord) 36
52: 6(float) Load 51
53: 6(float) ExtInst 1(GLSL.std.450) 37(FMin) 50 52
54: 6(float) ExtInst 1(GLSL.std.450) 37(FMin) 48 53
55: 6(float) FMul 46 54
56: 6(float) ExtInst 1(GLSL.std.450) 31(Sqrt) 55
58: 6(float) FMul 56 57
59: 6(float) FAdd 58 57
Store 45(f) 59
63: 10(fvec3) Load 12(gl_TessCoord)
64: 6(float) Load 45(f)
65: 10(fvec3) VectorTimesScalar 63 64
67: 6(float) CompositeExtract 65 0
68: 6(float) CompositeExtract 65 1
69: 6(float) CompositeExtract 65 2
70: 60(fvec4) CompositeConstruct 67 68 69 66
Store 62(in_f_color) 70
74: 7(fvec2) Load 9(pos)
75: 71(ivec2) Bitcast 74
Store 73(bits) 75
Store 77(numBits) 14
Store 78(i) 14
Branch 79
79: Label
LoopMerge 81 82 None
Branch 83
83: Label
84: 13(int) Load 78(i)
86: 85(bool) ULessThan 84 18
BranchConditional 86 80 81
80: Label
87: 76(ptr) AccessChain 73(bits) 14
88: 13(int) Load 87
89: 13(int) Load 78(i)
90: 13(int) ShiftLeftLogical 88 89
91: 13(int) BitwiseAnd 90 28
92: 76(ptr) AccessChain 73(bits) 28
93: 13(int) Load 92
94: 13(int) Load 78(i)
95: 13(int) ShiftLeftLogical 93 94
96: 13(int) BitwiseAnd 95 28
97: 13(int) IAdd 91 96
98: 13(int) Load 77(numBits)
99: 13(int) IAdd 98 97
Store 77(numBits) 99
Branch 82
82: Label
100: 13(int) Load 78(i)
101: 13(int) IAdd 100 31
Store 78(i) 101
Branch 79
81: Label
102: 13(int) Load 77(numBits)
103: 13(int) BitwiseAnd 102 28
104: 6(float) ConvertUToF 103
106: 6(float) FMul 104 105
107: 7(fvec2) Load 9(pos)
108: 7(fvec2) CompositeConstruct 106 106
109: 7(fvec2) FAdd 107 108
Store 9(pos) 109
113: 7(fvec2) Load 9(pos)
115: 6(float) CompositeExtract 113 0
116: 6(float) CompositeExtract 113 1
117: 60(fvec4) CompositeConstruct 115 116 114 66
118: 61(ptr) AccessChain 112 23
Store 118 117
Return
FunctionEnd

109
Test/precise.tesc Normal file
View File

@ -0,0 +1,109 @@
#version 450
#extension GL_EXT_tessellation_shader : require
#extension GL_EXT_gpu_shader5 : require
float minimal() {
precise float result = 5.0;
float a = 10.0;
float b = 20.0;
float c = 30.0;
float d = 40.0;
result = a * b + c * d; // c * d, a * b and rvalue1 + rvalue2 should be 'noContraction'.
return result;
}
void continuous_assignment() {
precise float result = 5.0;
float a = 10.0;
float b = 20.0;
result = a = b + 4; // b + 4 should be 'noContraction'.
}
void convert() {
precise double result;
float a = 10.0;
float b = 20.0;
b = a + b; // a + b should be 'noContraction'.
result = double(b); // convert operation should not be 'noContraction'.
}
float loop_for() {
precise float r1 = 5.0;
precise float r2 = 10.0;
int a = 10;
int b = 20;
int c = 30;
for (int i = 0; i < a; i++) {
r1 += 3.12 + b + i; // 'noContration', this make i++ also 'noContraction'
c += 1; // 'noContration'
}
a += 1; // a + 1 should not be 'noContraction'.
r2 = c; // The calculation of c should be 'noContration'.
return float(r1 + r2); // conversion should not be 'noContration'.
}
void loop_array(void) {
precise float result;
int x = 22;
int y = 33;
float a0[3];
result += float(x) + float(y); // x + y should be 'noContraction' also result + rvalue.
for (int i = 0; i < 3; ++i) {
// a's dereference + 2 should be 'noContraction'.
result += a0[i] + 2;
// result + 1 and 3 - rvalue should be 'noContraction'.
a0[i] = 3 - result++;
}
}
void loop_while() {
precise float result = 5.0;
int a = 10;
int b = 20;
while (result < 10) {
result += 3.12 + b; // result + 3.12 should be 'noContraction'.
}
result = a + b + 5; // b + 5 should not be 'noCtraction' because all operands are integers.
result = 11.1;
}
float fma_not_decorated() {
precise float result;
float a = 1.0;
float b = 2.0;
float c = 3.0;
b = b + c; // b + c should be decorated with 'noContraction'
result = fma(a, b, c); // fma() should not be decorated with 'noContradtion'
return result;
}
precise float precise_return_exp_func() {
float a = 1.0;
float b = 2.0;
return a + b; // the ADD operation should be 'noContraction'
}
precise float precise_return_val_func() {
float a = 1.0;
float b = 2.0;
float result = a + b; // the ADD operation should be 'noContraction'
return result;
}
float precise_func_parameter(float b, precise out float c) {
float a = 0.5;
c = a + b; // noContration
return a - b; // Not noContraction
}
mat3 matrix (mat2x3 a, mat3x2 b) {
mat2x3 c = mat2x3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
precise mat3 result;
result = (a + c) * b; // should be noContraction
return result;
}
void main(){}

View File

@ -0,0 +1,89 @@
#version 450
struct T {
float f1;
float f2;
};
out B1 {precise T s; float x;} partial_precise_block;
precise out B2 {T s; float x;} all_precise_block;
float struct_member() {
float a = 1.0;
float b = 2.0;
float c = 3.0;
float d = 4.0;
precise float result;
T S, S2, S3;
S2.f1 = a + 0.2; // NoContraction
S2.f2 = b + 0.2; // NOT NoContraction
S3.f1 = a + b; // NOT NoContraction
S = S2; // "precise" propagated through parent object nodes
result = S.f1 + 0.1; // the ADD operation should be NoContraction
return result;
}
float complex_array_struct() {
precise float result;
struct T1 {
float t1_array[3];
float t1_scalar;
};
struct T2 {
T1 t1a[5];
T1 t1b[6];
T1 t1c[7];
};
struct T3 {float f; T2 t2; vec4 v; int p;};
T3 t3[10];
for(int i=0; i<10; i++) {
t3[i].f = i / 3.0; // Not NoContraction
t3[i].v = vec4(i * 1.5); // NoContraction
t3[i].p = i + 1;
for(int j=0; j<5; j++) {
for(int k = 0; k<3; k++) {
t3[i].t2.t1a[j].t1_array[k] = i * j + k; // Not NoContraction
}
t3[i].t2.t1a[j].t1_scalar = j * 2.0 / i; // Not NoContration
}
for(int j=0; j<6; j++) {
for(int k = 0; k<3; k++) {
t3[i].t2.t1b[j].t1_array[k] = i * j + k; // Not NoContraction
}
t3[i].t2.t1b[j].t1_scalar = j * 2.0 / i; // NoContraction
}
for(int j=0; j<6; j++) {
for(int k = 0; k<3; k++) {
t3[i].t2.t1c[j].t1_array[k] = i * j + k; // Not NoContraction because all operands are integers
}
t3[i].t2.t1c[j].t1_scalar = j * 2.0 / i; // Not NoContraction
}
}
int i = 2;
result = t3[5].t2.t1c[6].t1_array[1]
+ t3[2].t2.t1b[1].t1_scalar
+ t3[i - 1].v.xy.x; // NoContraction
return result;
}
float out_block() {
float a = 0.1;
float b = 0.2;
partial_precise_block.s.f1 = a + b; // NoContraction
partial_precise_block.s.f2 = a - b; // NoContraction
partial_precise_block.x = a * b; // Not NoContraction
all_precise_block.s.f1 = a + b + 1.0; // NoContraction
all_precise_block.s.f2 = a - b - 1.0; // NoContraction
all_precise_block.x = a * b * 2.0; // Also NoContraction
return a + b; // Not NoContraction
}
void main(){}

24
Test/spv.precise.tesc Normal file
View File

@ -0,0 +1,24 @@
#version 310 es
#extension GL_EXT_tessellation_shader : require
#extension GL_EXT_gpu_shader5 : require
layout(vertices = 3) out;
layout(location = 0) in highp vec2 in_tc_position[];
layout(location = 1) in highp float in_tc_tessParam[];
layout(location = 0) out highp vec2 in_te_position[];
precise gl_TessLevelOuter;
void main (void)
{
in_te_position[gl_InvocationID] = in_tc_position[gl_InvocationID];
gl_TessLevelInner[0] = 5.0;
gl_TessLevelInner[1] = 5.0;
gl_TessLevelOuter[0] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[1] + in_tc_tessParam[2]);
gl_TessLevelOuter[1] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[2] + in_tc_tessParam[0]);
gl_TessLevelOuter[2] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[0] + in_tc_tessParam[1]);
}

36
Test/spv.precise.tese Normal file
View File

@ -0,0 +1,36 @@
#version 310 es
#extension GL_EXT_tessellation_shader : require
#extension GL_EXT_gpu_shader5 : require
layout(triangles, equal_spacing) in;
layout(location = 0) in highp vec2 in_te_position[];
layout(location = 0) out mediump vec4 in_f_color;
precise gl_Position;
void main(void) {
highp vec2 pos = gl_TessCoord.x * in_te_position[0] +
gl_TessCoord.y * in_te_position[1] +
gl_TessCoord.z * in_te_position[2];
highp float f =
sqrt(3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z))) *
0.5 +
0.5;
in_f_color = vec4(gl_TessCoord * f, 1.0);
// Offset the position slightly, based on the parity of the bits in the float
// representation.
// This is done to detect possible small differences in edge vertex positions
// between patches.
uvec2 bits = floatBitsToUint(pos);
uint numBits = 0u;
for (uint i = 0u; i < 32u; i++)
numBits +=
((bits[0] << i) & 1u) + ((bits[1] << i) & 1u);
pos += float(numBits & 1u) * 0.04;
gl_Position = vec4(pos, 0.0, 1.0);
}

View File

@ -107,6 +107,8 @@ spv.specConstant.vert
spv.specConstant.comp spv.specConstant.comp
spv.specConstantComposite.vert spv.specConstantComposite.vert
spv.specConstantOperations.vert spv.specConstantOperations.vert
spv.precise.tese
spv.precise.tesc
# GLSL-level semantics # GLSL-level semantics
vulkan.frag vulkan.frag
vulkan.vert vulkan.vert

View File

@ -130,3 +130,5 @@ whileLoop.frag
nonVulkan.frag nonVulkan.frag
negativeArraySize.comp negativeArraySize.comp
spv.atomic.comp spv.atomic.comp
precise.tesc
precise_struct_block.vert

View File

@ -33,6 +33,7 @@ set(SOURCES
MachineIndependent/preprocessor/PpScanner.cpp MachineIndependent/preprocessor/PpScanner.cpp
MachineIndependent/preprocessor/PpSymbols.cpp MachineIndependent/preprocessor/PpSymbols.cpp
MachineIndependent/preprocessor/PpTokens.cpp MachineIndependent/preprocessor/PpTokens.cpp
MachineIndependent/propagateNoContraction.cpp
GenericCodeGen/CodeGen.cpp GenericCodeGen/CodeGen.cpp
GenericCodeGen/Link.cpp) GenericCodeGen/Link.cpp)
@ -62,6 +63,7 @@ set(HEADERS
MachineIndependent/SymbolTable.h MachineIndependent/SymbolTable.h
MachineIndependent/Versions.h MachineIndependent/Versions.h
MachineIndependent/parseVersions.h MachineIndependent/parseVersions.h
MachineIndependent/propagateNoContraction.h
MachineIndependent/preprocessor/PpContext.h MachineIndependent/preprocessor/PpContext.h
MachineIndependent/preprocessor/PpTokens.h) MachineIndependent/preprocessor/PpTokens.h)

View File

@ -42,6 +42,7 @@
#include "localintermediate.h" #include "localintermediate.h"
#include "RemoveTree.h" #include "RemoveTree.h"
#include "SymbolTable.h" #include "SymbolTable.h"
#include "propagateNoContraction.h"
#include <float.h> #include <float.h>
@ -1066,6 +1067,9 @@ bool TIntermediate::postProcess(TIntermNode* root, EShLanguage /*language*/)
if (aggRoot && aggRoot->getOp() == EOpNull) if (aggRoot && aggRoot->getOp() == EOpNull)
aggRoot->setOperator(EOpSequence); aggRoot->setOperator(EOpSequence);
// Propagate 'noContraction' label in backward from 'precise' variables.
glslang::PropagateNoContraction(*this);
return true; return true;
} }

View File

@ -0,0 +1,858 @@
//
// Copyright (C) 2015-2016 Google, Inc.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Visit the nodes in the glslang intermediate tree representation to
// propagate 'noContraction' qualifier.
//
#include "propagateNoContraction.h"
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include "localintermediate.h"
namespace {
// Use string to hold the accesschain information, as in most cases the
// accesschain is short and may contain only one element, which is the symbol
// ID.
// Example: struct {float a; float b;} s;
// Object s.a will be represented with: <symbol ID of s>/0
// Object s.b will be represented with: <symbol ID of s>/1
// Object s will be representend with: <symbol ID of s>
// For members of vector, matrix and arrays, they will be represented with the
// same symbol ID of their container symbol objects. This is because their
// precise'ness is always the same as their container symbol objects.
using ObjectAccessChain = std::string;
// The delimiter used in the ObjectAccessChain string to separate symbol ID and
// different level of struct indices.
const char ObjectAccesschainDelimiter = '/';
// Mapping from Symbol IDs of symbol nodes, to their defining operation
// nodes.
using NodeMapping = std::unordered_multimap<ObjectAccessChain, glslang::TIntermOperator*>;
// Mapping from object nodes to their accesschain info string.
using AccessChainMapping = std::unordered_map<glslang::TIntermTyped*, ObjectAccessChain>;
// Set of object IDs.
using ObjectAccesschainSet = std::unordered_set<ObjectAccessChain>;
// Set of return branch nodes.
using ReturnBranchNodeSet = std::unordered_set<glslang::TIntermBranch*>;
// A helper function to tell whether a node is 'noContraction'. Returns true if
// the node has 'noContraction' qualifier, otherwise false.
bool isPreciseObjectNode(glslang::TIntermTyped* node)
{
return node->getType().getQualifier().noContraction;
}
// Returns true if the opcode is a dereferencing one.
bool isDereferenceOperation(glslang::TOperator op)
{
switch (op) {
case glslang::EOpIndexDirect:
case glslang::EOpIndexDirectStruct:
case glslang::EOpIndexIndirect:
case glslang::EOpVectorSwizzle:
return true;
default:
return false;
}
}
// Returns true if the opcode leads to an assignment operation.
bool isAssignOperation(glslang::TOperator op)
{
switch (op) {
case glslang::EOpAssign:
case glslang::EOpAddAssign:
case glslang::EOpSubAssign:
case glslang::EOpMulAssign:
case glslang::EOpVectorTimesMatrixAssign:
case glslang::EOpVectorTimesScalarAssign:
case glslang::EOpMatrixTimesScalarAssign:
case glslang::EOpMatrixTimesMatrixAssign:
case glslang::EOpDivAssign:
case glslang::EOpModAssign:
case glslang::EOpAndAssign:
case glslang::EOpLeftShiftAssign:
case glslang::EOpRightShiftAssign:
case glslang::EOpInclusiveOrAssign:
case glslang::EOpExclusiveOrAssign:
case glslang::EOpPostIncrement:
case glslang::EOpPostDecrement:
case glslang::EOpPreIncrement:
case glslang::EOpPreDecrement:
return true;
default:
return false;
}
}
// A helper function to get the unsigned int from a given constant union node.
// Note the node should only holds a uint scalar.
unsigned getStructIndexFromConstantUnion(glslang::TIntermTyped* node)
{
assert(node->getAsConstantUnion() && node->getAsConstantUnion()->isScalar());
unsigned struct_dereference_index = node->getAsConstantUnion()->getConstArray()[0].getUConst();
return struct_dereference_index;
}
// A helper function to generate symbol_label.
ObjectAccessChain generateSymbolLabel(glslang::TIntermSymbol* node)
{
ObjectAccessChain symbol_id =
std::to_string(node->getId()) + "(" + node->getName().c_str() + ")";
return symbol_id;
}
// Returns true if the operation is an arithmetic operation and valid for
// 'NoContraction' decoration.
bool isArithmeticOperation(glslang::TOperator op)
{
switch (op) {
case glslang::EOpAddAssign:
case glslang::EOpSubAssign:
case glslang::EOpMulAssign:
case glslang::EOpVectorTimesMatrixAssign:
case glslang::EOpVectorTimesScalarAssign:
case glslang::EOpMatrixTimesScalarAssign:
case glslang::EOpMatrixTimesMatrixAssign:
case glslang::EOpDivAssign:
case glslang::EOpModAssign:
case glslang::EOpNegative:
case glslang::EOpAdd:
case glslang::EOpSub:
case glslang::EOpMul:
case glslang::EOpDiv:
case glslang::EOpMod:
case glslang::EOpVectorTimesScalar:
case glslang::EOpVectorTimesMatrix:
case glslang::EOpMatrixTimesVector:
case glslang::EOpMatrixTimesScalar:
case glslang::EOpMatrixTimesMatrix:
case glslang::EOpDot:
case glslang::EOpPostIncrement:
case glslang::EOpPostDecrement:
case glslang::EOpPreIncrement:
case glslang::EOpPreDecrement:
return true;
default:
return false;
}
}
// A helper class to help managing populating_initial_no_contraction_ flag.
template <typename T> class StateSettingGuard {
public:
StateSettingGuard(T* state_ptr, T new_state_value)
: state_ptr_(state_ptr), previous_state_(*state_ptr)
{
*state_ptr = new_state_value;
}
StateSettingGuard(T* state_ptr) : state_ptr_(state_ptr), previous_state_(*state_ptr) {}
void setState(T new_state_value) { *state_ptr_ = new_state_value; }
~StateSettingGuard() { *state_ptr_ = previous_state_; }
private:
T* state_ptr_;
T previous_state_;
};
// A helper function to get the front element from a given ObjectAccessChain
ObjectAccessChain getFrontElement(const ObjectAccessChain& chain)
{
size_t pos_delimiter = chain.find(ObjectAccesschainDelimiter);
return pos_delimiter == std::string::npos ? chain : chain.substr(0, pos_delimiter);
}
// A helper function to get the accesschain starting from the second element.
ObjectAccessChain subAccessChainFromSecondElement(const ObjectAccessChain& chain)
{
size_t pos_delimiter = chain.find(ObjectAccesschainDelimiter);
return pos_delimiter == std::string::npos ? "" : chain.substr(pos_delimiter + 1);
}
// A helper function to get the accesschain after removing a given prefix.
ObjectAccessChain getSubAccessChainAfterPrefix(const ObjectAccessChain& chain,
const ObjectAccessChain& prefix)
{
size_t pos = chain.find(prefix);
if (pos != 0)
return chain;
return chain.substr(prefix.length() + sizeof(ObjectAccesschainDelimiter));
}
//
// A traverser which traverses the whole AST and populates:
// 1) A mapping from symbol nodes' IDs to their defining operation nodes.
// 2) A set of accesschains of the initial precise object nodes.
//
class TSymbolDefinitionCollectingTraverser : public glslang::TIntermTraverser {
public:
TSymbolDefinitionCollectingTraverser(NodeMapping* symbol_definition_mapping,
AccessChainMapping* accesschain_mapping,
ObjectAccesschainSet* precise_objects,
ReturnBranchNodeSet* precise_return_nodes);
bool visitUnary(glslang::TVisit, glslang::TIntermUnary*) override;
bool visitBinary(glslang::TVisit, glslang::TIntermBinary*) override;
void visitSymbol(glslang::TIntermSymbol*) override;
bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*) override;
bool visitBranch(glslang::TVisit, glslang::TIntermBranch*) override;
protected:
// The mapping from symbol node IDs to their defining nodes. This should be
// populated along traversing the AST.
NodeMapping& symbol_definition_mapping_;
// The set of symbol node IDs for precise symbol nodes, the ones marked as
// 'noContraction'.
ObjectAccesschainSet& precise_objects_;
// The set of precise return nodes.
ReturnBranchNodeSet& precise_return_nodes_;
// A temporary cache of the symbol node whose defining node is to be found
// currently along traversing the AST.
ObjectAccessChain current_object_;
// A map from object node to its accesschain. This traverser stores
// the built accesschains into this map for each object node it has
// visited.
AccessChainMapping& accesschain_mapping_;
// The pointer to the Function Definition node, so we can get the
// precise'ness of the return expression from it when we traverse the
// return branch node.
glslang::TIntermAggregate* current_function_definition_node_;
};
TSymbolDefinitionCollectingTraverser::TSymbolDefinitionCollectingTraverser(
NodeMapping* symbol_definition_mapping, AccessChainMapping* accesschain_mapping,
ObjectAccesschainSet* precise_objects,
std::unordered_set<glslang::TIntermBranch*>* precise_return_nodes)
: TIntermTraverser(true, false, false), symbol_definition_mapping_(*symbol_definition_mapping),
precise_objects_(*precise_objects), current_object_(),
accesschain_mapping_(*accesschain_mapping), current_function_definition_node_(nullptr),
precise_return_nodes_(*precise_return_nodes) {}
// Visits a symbol node, set the current_object_ to the
// current node symbol ID, and record a mapping from this node to the current
// current_object_, which is the just obtained symbol
// ID.
void TSymbolDefinitionCollectingTraverser::visitSymbol(glslang::TIntermSymbol* node)
{
current_object_ = generateSymbolLabel(node);
accesschain_mapping_[node] = current_object_;
}
// Visits an aggregate node, traverses all of its children.
bool TSymbolDefinitionCollectingTraverser::visitAggregate(glslang::TVisit,
glslang::TIntermAggregate* node)
{
// This aggreagate node might be a function definition node, in which case we need to
// cache this node, so we can get the precise'ness information of the return value
// of this function later.
StateSettingGuard<glslang::TIntermAggregate*> current_function_definition_node_setting_guard(
&current_function_definition_node_);
if (node->getOp() == glslang::EOpFunction) {
// This is function definition node, we need to cache this node so that we can
// get the precise'ness of the return value later.
current_function_definition_node_setting_guard.setState(node);
}
// Traverse the items in the sequence.
glslang::TIntermSequence& seq = node->getSequence();
for (int i = 0; i < (int)seq.size(); ++i) {
current_object_.clear();
seq[i]->traverse(this);
}
return false;
}
bool TSymbolDefinitionCollectingTraverser::visitBranch(glslang::TVisit,
glslang::TIntermBranch* node)
{
if (node->getFlowOp() == glslang::EOpReturn && node->getExpression() &&
current_function_definition_node_ &&
current_function_definition_node_->getType().getQualifier().noContraction) {
// This node is a return node with expression, and its function has
// precise return value. We need to find the involved objects in its
// expression and add them to the set of initial precise objects.
precise_return_nodes_.insert(node);
node->getExpression()->traverse(this);
}
return false;
}
// Visits an unary node. This might be an implicit assignment like i++, i--. etc.
bool TSymbolDefinitionCollectingTraverser::visitUnary(glslang::TVisit /* visit */,
glslang::TIntermUnary* node)
{
current_object_.clear();
node->getOperand()->traverse(this);
if (isAssignOperation(node->getOp())) {
// We should always be able to get an accesschain of the operand node.
assert(!current_object_.empty());
// If the operand node object is 'precise', we collect its accesschain
// for the initial set of 'precise' objects.
if (isPreciseObjectNode(node->getOperand())) {
// The operand node is an 'precise' object node, add its
// accesschain to the set of 'precise' objects. This is to collect
// the initial set of 'precise' objects.
precise_objects_.insert(current_object_);
}
// Gets the symbol ID from the object's accesschain.
ObjectAccessChain id_symbol = getFrontElement(current_object_);
// Add a mapping from the symbol ID to this assignment operation node.
symbol_definition_mapping_.insert(std::make_pair(id_symbol, node));
}
// Unary node is not a dereference node, so we clear the accesschain which
// is under construction.
current_object_.clear();
return false;
}
// Visits a binary node and updates the mapping from symbol IDs to the definition
// nodes. Also collects the accesschains for the initial precise objects.
bool TSymbolDefinitionCollectingTraverser::visitBinary(glslang::TVisit /* visit */,
glslang::TIntermBinary* node)
{
// Traverses the left node to build the accesschain info for the object.
current_object_.clear();
node->getLeft()->traverse(this);
if (isAssignOperation(node->getOp())) {
// We should always be able to get an accesschain for the left node.
assert(!current_object_.empty());
// If the left node object is 'precise', it is an initial precise object
// specified in the shader source. Adds it to the initial worklist to
// process later.
if (isPreciseObjectNode(node->getLeft())) {
// The left node is an 'precise' object node, add its accesschain to
// the set of 'precise' objects. This is to collect the initial set
// of 'precise' objects.
precise_objects_.insert(current_object_);
}
// Gets the symbol ID from the object accesschain, which should be the
// first element recorded in the accesschain.
ObjectAccessChain id_symbol = getFrontElement(current_object_);
// Adds a mapping from the symbol ID to this assignment operation node.
symbol_definition_mapping_.insert(std::make_pair(id_symbol, node));
// Traverses the right node, there may be other 'assignment'
// operatrions in the right.
current_object_.clear();
node->getRight()->traverse(this);
} else if (isDereferenceOperation(node->getOp())) {
// The left node (parent node) is a struct type object. We need to
// record the accesschain information of the current node into its
// object id.
if (node->getOp() == glslang::EOpIndexDirectStruct) {
unsigned struct_dereference_index = getStructIndexFromConstantUnion(node->getRight());
current_object_.push_back(ObjectAccesschainDelimiter);
current_object_.append(std::to_string(struct_dereference_index));
}
accesschain_mapping_[node] = current_object_;
// For dereference node, there is no need to traverse the right child
// node as the right node should always be an integer type object.
} else {
// For other binary nodes, still traverse the right node.
current_object_.clear();
return true;
}
return false;
}
// Traverses the AST and returns a tuple of four members:
// 1) a mapping from symbol IDs to the definition nodes (aka. assignment nodes) of these symbols.
// 2) a mapping from object nodes in the AST to the accesschains of these objects.
// 3) a set of accesschains of precise objects.
// 4) a set of return nodes with precise expressions.
std::tuple<NodeMapping, AccessChainMapping, ObjectAccesschainSet, ReturnBranchNodeSet>
getSymbolToDefinitionMappingAndPreciseSymbolIDs(const glslang::TIntermediate& intermediate)
{
auto result_tuple = std::make_tuple(NodeMapping(), AccessChainMapping(), ObjectAccesschainSet(),
ReturnBranchNodeSet());
TIntermNode* root = intermediate.getTreeRoot();
if (root == 0)
return result_tuple;
NodeMapping& symbol_definition_mapping = std::get<0>(result_tuple);
AccessChainMapping& accesschain_mapping = std::get<1>(result_tuple);
ObjectAccesschainSet& precise_objects = std::get<2>(result_tuple);
ReturnBranchNodeSet& precise_return_nodes = std::get<3>(result_tuple);
// Traverses the AST and populate the results.
TSymbolDefinitionCollectingTraverser collector(&symbol_definition_mapping, &accesschain_mapping,
&precise_objects, &precise_return_nodes);
root->traverse(&collector);
return result_tuple;
}
//
// A traverser that determine whether the left node (or operand node for unary
// node) of an assignment node is 'precise', containing 'precise' or not,
// according to the accesschain a given precise object which share the same
// symbol as the left node.
//
// Post-orderly traverses the left node subtree of an binary assignment node and:
//
// 1) Propagates the 'precise' from the left object nodes to this object node.
//
// 2) Builds object accesschain along the traversal, and also compares with
// the accesschain of the given 'precise' object along with the traversal to
// tell if the node to be defined is 'precise' or not.
//
class TNoContractionAssigneeCheckingTraverser : public glslang::TIntermTraverser {
enum DecisionStatus {
// The object node to be assigned to may contain 'precise' objects and also not 'precise' objects.
Mixed = 0,
// The object node to be assigned to is either a 'precise' object or a struct objects whose members are all 'precise'.
Precise = 1,
// The object node to be assigned to is not a 'precise' object.
NotPreicse = 2,
};
public:
TNoContractionAssigneeCheckingTraverser(const AccessChainMapping& accesschain_mapping)
: TIntermTraverser(true, false, false), accesschain_mapping_(accesschain_mapping),
precise_object_(nullptr) {}
// Checks the precise'ness of a given assignment node with a precise object
// represented as accesschain. The precise object shares the same symbol
// with the assignee of the given assignment node. Return a tuple of two:
//
// 1) The precise'ness of the assignee node of this assignment node. True
// if the assignee contains 'precise' objects or is 'precise', false if
// the assignee is not 'precise' according to the accesschain of the given
// precise object.
//
// 2) The incremental accesschain from the assignee node to its nested
// 'precise' object, according to the accesschain of the given precise
// object. This incremental accesschain can be empty, which means the
// assignee is 'precise'. Otherwise it shows the path to the nested
// precise object.
std::tuple<bool, ObjectAccessChain>
getPrecisenessAndRemainedAccessChain(glslang::TIntermOperator* node,
const ObjectAccessChain& precise_object)
{
assert(isAssignOperation(node->getOp()));
precise_object_ = &precise_object;
ObjectAccessChain assignee_object;
if (glslang::TIntermBinary* BN = node->getAsBinaryNode()) {
// This is a binary assignment node, we need to check the
// precise'ness of the left node.
assert(accesschain_mapping_.count(BN->getLeft()));
// The left node (assignee node) is an object node, traverse the
// node to let the 'precise' of nesting objects being transfered to
// nested objects.
BN->getLeft()->traverse(this);
// After traversing the left node, if the left node is 'precise',
// we can conclude this assignment should propagate 'precise'.
if (isPreciseObjectNode(BN->getLeft())) {
return make_tuple(true, ObjectAccessChain());
}
// If the precise'ness of the left node (assignee node) can not
// be determined by now, we need to compare the accesschain string
// of the assignee object with the given precise object.
assignee_object = accesschain_mapping_.at(BN->getLeft());
} else if (glslang::TIntermUnary* UN = node->getAsUnaryNode()) {
// This is a unary assignment node, we need to check the
// precise'ness of the operand node. For unary assignment node, the
// operand node should always be an object node.
assert(accesschain_mapping_.count(UN->getOperand()));
// Traverse the operand node to let the 'precise' being propagated
// from lower nodes to upper nodes.
UN->getOperand()->traverse(this);
// After traversing the operand node, if the operand node is
// 'precise', this assignment should propagate 'precise'.
if (isPreciseObjectNode(UN->getOperand())) {
return make_tuple(true, ObjectAccessChain());
}
// If the precise'ness of the operand node (assignee node) can not
// be determined by now, we need to compare the accesschain string
// of the assignee object with the given precise object.
assignee_object = accesschain_mapping_.at(UN->getOperand());
} else {
// Not a binary or unary node, should not happen.
assert(false);
}
// Compare the accesschain string of the assignee node with the given
// precise object to determine if this assignment should propagate
// 'precise'.
if (assignee_object.find(precise_object) == 0) {
// The accesschain string of the given precise object is a prefix
// of assignee's accesschain string. The assignee should be
// 'precise'.
return make_tuple(true, ObjectAccessChain());
} else if (precise_object.find(assignee_object) == 0) {
// The assignee's accesschain string is a prefix of the given
// precise object, the assignee object contains 'precise' object,
// and we need to pass the remained accesschain to the object nodes
// in the right.
return make_tuple(true, getSubAccessChainAfterPrefix(precise_object, assignee_object));
} else {
// The accesschain strings do not match, the assignee object can
// not be labelled as 'precise' according to the given precise
// object.
return make_tuple(false, ObjectAccessChain());
}
}
protected:
bool visitBinary(glslang::TVisit, glslang::TIntermBinary* node) override;
void visitSymbol(glslang::TIntermSymbol* node) override;
// A map from object nodes to their accesschain string (used as object ID).
const AccessChainMapping& accesschain_mapping_;
// A given precise object, represented in it accesschain string. This
// precise object is used to be compared with the assignee node to tell if
// the assignee node is 'precise', contains 'precise' object or not
// 'precise'.
const ObjectAccessChain* precise_object_;
};
// Visits a binary node. If the node is an object node, it must be a dereference
// node. In such cases, if the left node is 'precise', this node should also be
// 'precise'.
bool TNoContractionAssigneeCheckingTraverser::visitBinary(glslang::TVisit,
glslang::TIntermBinary* node)
{
// Traverses the left so that we transfer the 'precise' from nesting object
// to its nested object.
node->getLeft()->traverse(this);
// If this binary node is an object node, we should have it in the
// accesschain_mapping_.
if (accesschain_mapping_.count(node)) {
// A binary object node must be a dereference node.
assert(isDereferenceOperation(node->getOp()));
// If the left node is 'precise', this node should also be precise,
// otherwise, compare with the given precise_object_. If the
// accesschain of this node matches with the given precise_object_,
// this node should be marked as 'precise'.
if (isPreciseObjectNode(node->getLeft())) {
node->getWritableType().getQualifier().noContraction = true;
} else if (accesschain_mapping_.at(node) == *precise_object_) {
node->getWritableType().getQualifier().noContraction = true;
}
}
return false;
}
// Visits a symbol node, if the symbol node ID (its accesschain string) matches
// with the given precise object, this node should be 'precise'.
void TNoContractionAssigneeCheckingTraverser::visitSymbol(glslang::TIntermSymbol* node)
{
// A symbol node should always be an object node, and should have been added
// to the map from object nodes to their accesschain strings.
assert(accesschain_mapping_.count(node));
if (accesschain_mapping_.at(node) == *precise_object_) {
node->getWritableType().getQualifier().noContraction = true;
}
}
//
// A traverser that only traverses the right side of binary assignment nodes
// and the operand node of unary assignment nodes.
//
// 1) Marks arithmetic operations 'NoContraction'.
//
// 2) Find the object which should be marked as 'precise' in the right and
// update the 'precise' object worklist.
//
class TNoContractionPropagator : public glslang::TIntermTraverser {
public:
TNoContractionPropagator(ObjectAccesschainSet* precise_objects,
const AccessChainMapping& accesschain_mapping)
: TIntermTraverser(true, false, false), remained_accesschain_(),
precise_objects_(*precise_objects), accesschain_mapping_(accesschain_mapping),
added_precise_object_ids_() {}
// Propagates 'precise' in the right nodes of a given assignment node with
// accesschain record from the assignee node to a 'precise' object it
// contains.
void
propagateNoContractionInOneExpression(glslang::TIntermTyped* defining_node,
const ObjectAccessChain& assignee_remained_accesschain)
{
remained_accesschain_ = assignee_remained_accesschain;
if (glslang::TIntermBinary* BN = defining_node->getAsBinaryNode()) {
assert(isAssignOperation(BN->getOp()));
BN->getRight()->traverse(this);
if (isArithmeticOperation(BN->getOp())) {
BN->getWritableType().getQualifier().noContraction = true;
}
} else if (glslang::TIntermUnary* UN = defining_node->getAsUnaryNode()) {
assert(isAssignOperation(UN->getOp()));
UN->getOperand()->traverse(this);
if (isArithmeticOperation(UN->getOp())) {
UN->getWritableType().getQualifier().noContraction = true;
}
}
}
// Propagates 'precise' in a given precise return node.
void propagateNoContractionInReturnNode(glslang::TIntermBranch* return_node)
{
remained_accesschain_ = "";
assert(return_node->getFlowOp() == glslang::EOpReturn && return_node->getExpression());
return_node->getExpression()->traverse(this);
}
protected:
// Visits an aggregate node. The node can be a initializer list, in which
// case we need to find the 'precise' or 'precise' containing object node
// with the accesschain record. In other cases, just need to traverse all
// the children nodes.
bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate* node) override
{
if (!remained_accesschain_.empty() && node->getOp() == glslang::EOpConstructStruct) {
// This is a struct initializer node, and the remained
// accesschain is not empty, we need to refer to the
// assignee_remained_access_chain_ to find the nested
// 'precise' object. And we don't need to visit other nodes in this
// aggreagate node.
// Gets the struct dereference index that leads to 'precise' object.
ObjectAccessChain precise_accesschain_index_str =
getFrontElement(remained_accesschain_);
unsigned precise_accesschain_index = std::stoul(precise_accesschain_index_str);
// Gets the node pointed by the accesschain index extracted before.
glslang::TIntermTyped* potential_precise_node =
node->getSequence()[precise_accesschain_index]->getAsTyped();
assert(potential_precise_node);
// Pop the front accesschain index from the path, and visit the nested node.
{
ObjectAccessChain next_level_accesschain =
subAccessChainFromSecondElement(remained_accesschain_);
StateSettingGuard<ObjectAccessChain> setup_remained_accesschain_for_next_level(
&remained_accesschain_, next_level_accesschain);
potential_precise_node->traverse(this);
}
return false;
}
return true;
}
// Visits a binary node. A binary node can be an object node, e.g. a dereference node.
// As only the top object nodes in the right side of an assignment needs to be visited
// and added to 'precise' worklist, this traverser won't visit the children nodes of
// an object node. If the binary node does not represent an object node, it should
// go on to traverse its children nodes and if it is an arithmetic operation node, this
// operation should be marked as 'noContraction'.
bool visitBinary(glslang::TVisit, glslang::TIntermBinary* node) override
{
if (isDereferenceOperation(node->getOp())) {
// This binary node is an object node. Need to update the precise
// object set with the accesschain of this node + remained
// accesschain .
ObjectAccessChain new_precise_accesschain = accesschain_mapping_.at(node);
if (remained_accesschain_.empty()) {
node->getWritableType().getQualifier().noContraction = true;
} else {
new_precise_accesschain += ObjectAccesschainDelimiter + remained_accesschain_;
}
// Cache the accesschain as added precise object, so we won't add the
// same object to the worklist again.
if (!added_precise_object_ids_.count(new_precise_accesschain)) {
precise_objects_.insert(new_precise_accesschain);
added_precise_object_ids_.insert(new_precise_accesschain);
}
// Only the upper-most object nodes should be visited, so do not
// visit children of this object node.
return false;
}
// If this is an arithmetic operation, marks this node as 'noContraction'.
if (isArithmeticOperation(node->getOp()) && node->getBasicType() != glslang::EbtInt) {
node->getWritableType().getQualifier().noContraction = true;
}
// As this node is not an object node, need to traverse the children nodes.
return true;
}
// Visits an unary node. An unary node can not be an object node. If the operation
// is an arithmetic operation, need to mark this node as 'noContraction'.
bool visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node) override
{
// If this is an arithmetic operation, marks this with 'noContraction'
if (isArithmeticOperation(node->getOp())) {
node->getWritableType().getQualifier().noContraction = true;
}
return true;
}
// Visits a symbol node. A symbol node is always an object node. So we
// should always be able to find its in our colected mapping from object
// nodes to accesschains. As an object node, a symbol node can be either
// 'precise' or containing 'precise' objects according to unused
// accesschain information we have when we visit this node.
void visitSymbol(glslang::TIntermSymbol* node) override
{
// Symbol nodes are object nodes and should always have an
// accesschain collected before matches with it.
assert(accesschain_mapping_.count(node));
ObjectAccessChain new_precise_accesschain = accesschain_mapping_.at(node);
// If the unused accesschain is empty, this symbol node should be
// marked as 'precise'. Otherwise, the unused accesschain should be
// appended to the symbol ID to build a new accesschain which points to
// the nested 'precise' object in this symbol object.
if (remained_accesschain_.empty()) {
node->getWritableType().getQualifier().noContraction = true;
} else {
new_precise_accesschain += ObjectAccesschainDelimiter + remained_accesschain_;
}
// Add the new 'precise' accesschain to the worklist and make sure we
// don't visit it again.
if (!added_precise_object_ids_.count(new_precise_accesschain)) {
precise_objects_.insert(new_precise_accesschain);
added_precise_object_ids_.insert(new_precise_accesschain);
}
}
// A set of precise objects, represented as accesschains.
ObjectAccesschainSet& precise_objects_;
// Visited symbol nodes, should not revisit these nodes.
ObjectAccesschainSet added_precise_object_ids_;
// The left node of an assignment operation might be an parent of 'precise' objects.
// This means the left node might not be an 'precise' object node, but it may contains
// 'precise' qualifier which should be propagated to the corresponding child node in
// the right. So we need the path from the left node to its nested 'precise' node to
// tell us how to find the corresponding 'precise' node in the right.
ObjectAccessChain remained_accesschain_;
// A map from node pointers to their accesschains.
const AccessChainMapping& accesschain_mapping_;
};
}
namespace glslang {
void PropagateNoContraction(const glslang::TIntermediate& intermediate)
{
// First, traverses the AST, records symbols with their defining operations
// and collects the initial set of precise symbols (symbol nodes that marked
// as 'noContraction') and precise return nodes.
auto mappings_and_precise_objects =
getSymbolToDefinitionMappingAndPreciseSymbolIDs(intermediate);
// The mapping of symbol node IDs to their defining nodes. This enables us
// to get the defining node directly from a given symbol ID without
// traversing the tree again.
NodeMapping& symbol_definition_mapping = std::get<0>(mappings_and_precise_objects);
// The mapping of object nodes to their accesschains recorded.
AccessChainMapping& accesschain_mapping = std::get<1>(mappings_and_precise_objects);
// The initial set of 'precise' objects which are represented as the
// accesschain toward them.
ObjectAccesschainSet& precise_object_accesschains = std::get<2>(mappings_and_precise_objects);
// The set of 'precise' return nodes.
ReturnBranchNodeSet& precise_return_nodes = std::get<3>(mappings_and_precise_objects);
// Second, uses the initial set of precise objects as a worklist, pops an
// accesschain, extract the symbol ID from it. Then:
// 1) Check the assignee object, see if it is 'precise' object node or
// contains 'precise' object. Obtain the incremental accesschain from the
// assignee node to its nested 'precise' node (if any).
// 2) If the assignee object node is 'precise' or it contains 'precise'
// objects, traverses the right side of the assignment operation
// expression to mark arithmetic operations as 'noContration' and update
// 'precise' accesschain worklist with new found object nodes.
// Repeat above steps until the worklist is empty.
TNoContractionAssigneeCheckingTraverser checker(accesschain_mapping);
TNoContractionPropagator propagator(&precise_object_accesschains, accesschain_mapping);
// We have two initial precise worklists to handle:
// 1) precise return nodes
// 2) precise object accesschains
// We should process the precise return nodes first and the involved
// objects in the return expression should be added to the precise object
// accesschain set.
while (!precise_return_nodes.empty()) {
glslang::TIntermBranch* precise_return_node = *precise_return_nodes.begin();
propagator.propagateNoContractionInReturnNode(precise_return_node);
precise_return_nodes.erase(precise_return_node);
}
while (!precise_object_accesschains.empty()) {
// Get the accesschain of a precise object from the worklist.
ObjectAccessChain precise_object_accesschain = *precise_object_accesschains.begin();
// Get the symbol id from the accesschain.
ObjectAccessChain symbol_id = getFrontElement(precise_object_accesschain);
// Get all the defining nodes of that symbol ID.
std::pair<NodeMapping::iterator, NodeMapping::iterator> range =
symbol_definition_mapping.equal_range(symbol_id);
// Visits all the assignment nodes of that symbol ID and
// 1) Check if the assignee node is 'precise' or contains 'precise'
// objects.
// 2) Propagate the 'precise' to the top layer object ndoes
// in the right side of the assignment operation, update the 'precise'
// worklist with new accesschains representing the new 'precise'
// objects, and mark arithmetic operations as 'noContraction'.
for (NodeMapping::iterator defining_node_iter = range.first;
defining_node_iter != range.second; defining_node_iter++) {
TIntermOperator* defining_node = defining_node_iter->second;
// Check the assignee node.
auto checker_result = checker.getPrecisenessAndRemainedAccessChain(
defining_node, precise_object_accesschain);
bool& contain_precise = std::get<0>(checker_result);
ObjectAccessChain& remained_accesschain = std::get<1>(checker_result);
// If the assignee node is 'precise' or contains 'precise', propagate the
// 'precise' to the right. Otherwise just skip this assignment node.
if (contain_precise) {
propagator.propagateNoContractionInOneExpression(defining_node,
remained_accesschain);
}
}
// Remove the last processed 'precise' object from the worklist.
precise_object_accesschains.erase(precise_object_accesschain);
}
}
};

View File

@ -0,0 +1,53 @@
//
// Copyright (C) 2015-2016 Google, Inc.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Visit the nodes in the glslang intermediate tree representation to
// propagate 'noContraction' qualifier.
//
#include "../Include/intermediate.h"
namespace glslang {
// Propagates the 'precise' qualifier for objects (objects marked with
// 'noContraction' qualifier) from the shader source specified 'precise'
// variables to all the involved objects, and add 'noContraction' qualifier for
// the involved arithmetic operations.
// Note that the same qualifier: 'noContraction' is used in both object nodes
// and arithmetic operation nodes, but has different meaning. For object nodes,
// 'noContraction' means the object is 'precise'; and for arithmetic operation
// nodes, it means the operation should not be contracted.
void PropagateNoContraction(const glslang::TIntermediate& intermediate);
};