mirror of
https://github.com/RPCS3/glslang.git
synced 2024-11-24 19:59:40 +00:00
Merge pull request #222 from Qining/support-precise
Full stack: Support *precise* qualifier
This commit is contained in:
commit
3357d870e4
@ -33,8 +33,6 @@
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//
|
||||
// Author: John Kessenich, LunarG
|
||||
//
|
||||
// Visit the nodes in the glslang intermediate tree representation to
|
||||
// translate them to SPIR-V.
|
||||
@ -135,10 +133,10 @@ protected:
|
||||
spv::Id createImageTextureFunctionCall(glslang::TIntermOperator* node);
|
||||
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 createBinaryMatrixOperation(spv::Op, spv::Decoration precision, 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 createUnaryMatrixOperation(spv::Op, spv::Decoration precision, spv::Id typeId, spv::Id operand,glslang::TBasicType typeProxy);
|
||||
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::Decoration noContraction, spv::Id typeId, spv::Id left, spv::Id right);
|
||||
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::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 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);
|
||||
@ -244,7 +242,7 @@ spv::StorageClass TranslateStorageClass(const glslang::TType& type)
|
||||
case glslang::EvqGlobal: return spv::StorageClassPrivate;
|
||||
case glslang::EvqConstReadOnly: return spv::StorageClassFunction;
|
||||
case glslang::EvqTemporary: return spv::StorageClassFunction;
|
||||
default:
|
||||
default:
|
||||
assert(0);
|
||||
return spv::StorageClassFunction;
|
||||
}
|
||||
@ -385,6 +383,15 @@ spv::Decoration TranslateInvariantDecoration(const glslang::TQualifier& qualifie
|
||||
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.
|
||||
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.
|
||||
bool IsDescriptorResource(const glslang::TType& type)
|
||||
{
|
||||
@ -782,7 +789,7 @@ TGlslangToSpvTraverser::~TGlslangToSpvTraverser()
|
||||
//
|
||||
|
||||
//
|
||||
// Symbols can turn into
|
||||
// Symbols can turn into
|
||||
// - uniform/input reads
|
||||
// - output writes
|
||||
// - 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());
|
||||
|
||||
// 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,
|
||||
node->getType().getBasicType());
|
||||
|
||||
@ -992,6 +1000,7 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
|
||||
|
||||
// get result
|
||||
spv::Id result = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()),
|
||||
TranslateNoContractionDecoration(node->getType().getQualifier()),
|
||||
convertGlslangToSpvType(node->getType()), left, right,
|
||||
node->getLeft()->getType().getBasicType());
|
||||
|
||||
@ -1058,6 +1067,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
|
||||
operand = accessChainLoad(node->getOperand()->getType());
|
||||
|
||||
spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
|
||||
spv::Decoration noContraction = TranslateNoContractionDecoration(node->getType().getQualifier());
|
||||
|
||||
// it could be a conversion
|
||||
if (! result)
|
||||
@ -1065,7 +1075,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
|
||||
|
||||
// if not, then possibly an operation
|
||||
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) {
|
||||
builder.clearAccessChain();
|
||||
@ -1096,7 +1106,8 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
|
||||
else
|
||||
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,
|
||||
node->getType().getBasicType());
|
||||
assert(result != spv::NoResult);
|
||||
@ -1331,7 +1342,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
||||
break;
|
||||
}
|
||||
case glslang::EOpMul:
|
||||
// compontent-wise matrix multiply
|
||||
// compontent-wise matrix multiply
|
||||
binOp = glslang::EOpMul;
|
||||
break;
|
||||
case glslang::EOpOuterProduct:
|
||||
@ -1340,7 +1351,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
||||
break;
|
||||
case glslang::EOpDot:
|
||||
{
|
||||
// for scalar dot product, use multiply
|
||||
// for scalar dot product, use multiply
|
||||
glslang::TIntermSequence& glslangOperands = node->getSequence();
|
||||
if (! glslangOperands[0]->getAsTyped()->isVector())
|
||||
binOp = glslang::EOpMul;
|
||||
@ -1395,8 +1406,8 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
||||
right->traverse(this);
|
||||
spv::Id rightId = accessChainLoad(right->getType());
|
||||
|
||||
result = createBinaryOperation(binOp, precision,
|
||||
convertGlslangToSpvType(node->getType()), leftId, rightId,
|
||||
result = createBinaryOperation(binOp, precision, TranslateNoContractionDecoration(node->getType().getQualifier()),
|
||||
convertGlslangToSpvType(node->getType()), leftId, rightId,
|
||||
left->getType().getBasicType(), reduceComparison);
|
||||
|
||||
// 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());
|
||||
break;
|
||||
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;
|
||||
default:
|
||||
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);
|
||||
}
|
||||
|
||||
// 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
|
||||
if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) ||
|
||||
(int)codeSegments.size() == defaultSegment)
|
||||
@ -1695,7 +1710,7 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T
|
||||
|
||||
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.
|
||||
// This includes specialization constants.
|
||||
if (node->getQualifier().isConstant()) {
|
||||
@ -1999,7 +2014,7 @@ spv::Id TGlslangToSpvTraverser::makeArraySizeId(const glslang::TArraySizes& arra
|
||||
specNode->traverse(this);
|
||||
return accessChainLoad(specNode->getAsTyped()->getType());
|
||||
}
|
||||
|
||||
|
||||
// Otherwise, need a compile-time (front end) size, get it:
|
||||
int size = arraySizes.getDimSize(dim);
|
||||
assert(size > 0);
|
||||
@ -2146,7 +2161,7 @@ void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& /*structTy
|
||||
// Getting this far means we need explicit offsets
|
||||
if (currentOffset < 0)
|
||||
currentOffset = 0;
|
||||
|
||||
|
||||
// Now, currentOffset is valid (either 0, or from a previous nextOffset),
|
||||
// but possibly not yet correctly aligned.
|
||||
|
||||
@ -2176,7 +2191,7 @@ void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslF
|
||||
// so that it's available to call.
|
||||
// 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:
|
||||
//
|
||||
// - "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)
|
||||
{
|
||||
// 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().
|
||||
spv::Function* function = functionMap[node->getName().c_str()];
|
||||
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.
|
||||
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,
|
||||
glslang::TBasicType typeProxy, bool reduceComparison)
|
||||
{
|
||||
@ -2797,13 +2813,15 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv
|
||||
if (binOp != spv::OpNop) {
|
||||
assert(comparison == false);
|
||||
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
|
||||
if (needMatchingVectors)
|
||||
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)
|
||||
@ -2872,8 +2890,11 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv
|
||||
break;
|
||||
}
|
||||
|
||||
if (binOp != spv::OpNop)
|
||||
return builder.setPrecision(builder.createBinOp(binOp, typeId, left, right), precision);
|
||||
if (binOp != spv::OpNop) {
|
||||
spv::Id result = builder.createBinOp(binOp, typeId, left, right);
|
||||
addDecoration(result, noContraction);
|
||||
return builder.setPrecision(result, precision);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2892,7 +2913,7 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv
|
||||
// matrix op scalar 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;
|
||||
|
||||
@ -2928,8 +2949,11 @@ spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Dec
|
||||
break;
|
||||
}
|
||||
|
||||
if (firstClass)
|
||||
return builder.setPrecision(builder.createBinOp(op, typeId, left, right), precision);
|
||||
if (firstClass) {
|
||||
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.
|
||||
// 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);
|
||||
spv::Id leftVec = leftMat ? builder.createCompositeExtract( left, vecType, indexes) : smearVec;
|
||||
spv::Id rightVec = rightMat ? builder.createCompositeExtract(right, vecType, indexes) : smearVec;
|
||||
results.push_back(builder.createBinOp(op, vecType, leftVec, rightVec));
|
||||
builder.setPrecision(results.back(), precision);
|
||||
spv::Id result = builder.createBinOp(op, vecType, leftVec, rightVec);
|
||||
addDecoration(result, noContraction);
|
||||
results.push_back(builder.setPrecision(result, precision));
|
||||
}
|
||||
|
||||
// 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;
|
||||
int libCall = -1;
|
||||
@ -2989,7 +3014,7 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv:
|
||||
if (isFloat) {
|
||||
unaryOp = spv::OpFNegate;
|
||||
if (builder.isMatrixType(typeId))
|
||||
return createUnaryMatrixOperation(unaryOp, precision, typeId, operand, typeProxy);
|
||||
return createUnaryMatrixOperation(unaryOp, precision, noContraction, typeId, operand, typeProxy);
|
||||
} else
|
||||
unaryOp = spv::OpSNegate;
|
||||
break;
|
||||
@ -3271,11 +3296,12 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv:
|
||||
id = builder.createUnaryOp(unaryOp, typeId, operand);
|
||||
}
|
||||
|
||||
addDecoration(id, noContraction);
|
||||
return builder.setPrecision(id, precision);
|
||||
}
|
||||
|
||||
// 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.
|
||||
// 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;
|
||||
indexes.push_back(c);
|
||||
spv::Id vec = builder.createCompositeExtract(operand, vecType, indexes);
|
||||
results.push_back(builder.createUnaryOp(op, vecType, vec));
|
||||
builder.setPrecision(results.back(), precision);
|
||||
spv::Id vec_result = builder.createUnaryOp(op, vecType, vec);
|
||||
addDecoration(vec_result, noContraction);
|
||||
results.push_back(builder.setPrecision(vec_result, precision));
|
||||
}
|
||||
|
||||
// put the pieces together
|
||||
@ -4125,7 +4152,7 @@ bool TGlslangToSpvTraverser::isTrivialLeaf(const glslang::TIntermTyped* node)
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A node is trivial if it is a single operation with no side effects.
|
||||
// Error on the side of saying non-trivial.
|
||||
|
768
Test/baseResults/precise.tesc.out
Normal file
768
Test/baseResults/precise.tesc.out
Normal 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
|
||||
|
1045
Test/baseResults/precise_struct_block.vert.out
Normal file
1045
Test/baseResults/precise_struct_block.vert.out
Normal file
File diff suppressed because it is too large
Load Diff
122
Test/baseResults/spv.precise.tesc.out
Normal file
122
Test/baseResults/spv.precise.tesc.out
Normal 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
|
192
Test/baseResults/spv.precise.tese.out
Normal file
192
Test/baseResults/spv.precise.tese.out
Normal 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
109
Test/precise.tesc
Normal 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(){}
|
89
Test/precise_struct_block.vert
Normal file
89
Test/precise_struct_block.vert
Normal 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
24
Test/spv.precise.tesc
Normal 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
36
Test/spv.precise.tese
Normal 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);
|
||||
}
|
@ -107,6 +107,8 @@ spv.specConstant.vert
|
||||
spv.specConstant.comp
|
||||
spv.specConstantComposite.vert
|
||||
spv.specConstantOperations.vert
|
||||
spv.precise.tese
|
||||
spv.precise.tesc
|
||||
# GLSL-level semantics
|
||||
vulkan.frag
|
||||
vulkan.vert
|
||||
|
@ -130,3 +130,5 @@ whileLoop.frag
|
||||
nonVulkan.frag
|
||||
negativeArraySize.comp
|
||||
spv.atomic.comp
|
||||
precise.tesc
|
||||
precise_struct_block.vert
|
||||
|
@ -33,6 +33,7 @@ set(SOURCES
|
||||
MachineIndependent/preprocessor/PpScanner.cpp
|
||||
MachineIndependent/preprocessor/PpSymbols.cpp
|
||||
MachineIndependent/preprocessor/PpTokens.cpp
|
||||
MachineIndependent/propagateNoContraction.cpp
|
||||
GenericCodeGen/CodeGen.cpp
|
||||
GenericCodeGen/Link.cpp)
|
||||
|
||||
@ -62,6 +63,7 @@ set(HEADERS
|
||||
MachineIndependent/SymbolTable.h
|
||||
MachineIndependent/Versions.h
|
||||
MachineIndependent/parseVersions.h
|
||||
MachineIndependent/propagateNoContraction.h
|
||||
MachineIndependent/preprocessor/PpContext.h
|
||||
MachineIndependent/preprocessor/PpTokens.h)
|
||||
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "localintermediate.h"
|
||||
#include "RemoveTree.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "propagateNoContraction.h"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
@ -1066,6 +1067,9 @@ bool TIntermediate::postProcess(TIntermNode* root, EShLanguage /*language*/)
|
||||
if (aggRoot && aggRoot->getOp() == EOpNull)
|
||||
aggRoot->setOperator(EOpSequence);
|
||||
|
||||
// Propagate 'noContraction' label in backward from 'precise' variables.
|
||||
glslang::PropagateNoContraction(*this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
858
glslang/MachineIndependent/propagateNoContraction.cpp
Normal file
858
glslang/MachineIndependent/propagateNoContraction.cpp
Normal 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(
|
||||
¤t_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);
|
||||
}
|
||||
}
|
||||
};
|
53
glslang/MachineIndependent/propagateNoContraction.h
Normal file
53
glslang/MachineIndependent/propagateNoContraction.h
Normal 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);
|
||||
};
|
Loading…
Reference in New Issue
Block a user