Merge branch 'master' into hlsl-frontend

This commit is contained in:
John Kessenich
2016-04-03 20:36:48 -06:00
66 changed files with 3048 additions and 588 deletions

View File

@@ -128,8 +128,9 @@ protected:
void addDecoration(spv::Id id, spv::Decoration dec, unsigned value);
void addMemberDecoration(spv::Id id, int member, spv::Decoration dec);
void addMemberDecoration(spv::Id id, int member, spv::Decoration dec, unsigned value);
spv::Id createSpvSpecConstant(const glslang::TIntermTyped&);
spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant);
spv::Id createSpvConstant(const glslang::TIntermTyped&);
spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant);
spv::Id createSpvConstantFromConstSubTree(glslang::TIntermTyped* subTree);
bool isTrivialLeaf(const glslang::TIntermTyped* node);
bool isTrivial(const glslang::TIntermTyped* node);
spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);
@@ -1527,7 +1528,7 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T
void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
{
int nextConst = 0;
spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst, false);
spv::Id constant = createSpvConstantFromConstUnionArray(node->getType(), node->getConstArray(), nextConst, false);
builder.clearAccessChain();
builder.setAccessChainRValue(constant);
@@ -1636,8 +1637,8 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol*
// 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().storage == glslang::EvqConst) {
return createSpvSpecConstant(*node);
if (node->getQualifier().isConstant()) {
return createSpvConstant(*node);
}
// Now, handle actual variables
@@ -3444,11 +3445,12 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
builder.promoteScalar(precision, operands.front(), operands[2]);
break;
case glslang::EOpMix:
if (isFloat)
if (! builder.isBoolType(builder.getScalarTypeId(builder.getTypeId(operands.back())))) {
assert(isFloat);
libCall = spv::GLSLstd450FMix;
else {
} else {
opCode = spv::OpSelect;
spv::MissingFunctionality("translating integer mix to OpSelect");
std::swap(operands.front(), operands.back());
}
builder.promoteScalar(precision, operands.front(), operands.back());
break;
@@ -3738,15 +3740,15 @@ void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::De
// recursively walks. So, this function walks the "top" of the tree:
// - emit specialization constant-building instructions for specConstant
// - when running into a non-spec-constant, switch to createSpvConstant()
spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermTyped& node)
spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TIntermTyped& node)
{
assert(node.getQualifier().storage == glslang::EvqConst);
assert(node.getQualifier().isConstant());
if (! node.getQualifier().specConstant) {
// hand off to the non-spec-constant path
assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr);
int nextConst = 0;
return createSpvConstant(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
nextConst, false);
}
@@ -3755,7 +3757,7 @@ spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermType
if (node.getAsSymbolNode() && node.getQualifier().hasSpecConstantId()) {
// this is a direct literal assigned to a layout(constant_id=) declaration
int nextConst = 0;
return createSpvConstant(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
nextConst, true);
} else {
// gl_WorkgroupSize is a special case until the front-end handles hierarchical specialization constants,
@@ -3769,8 +3771,11 @@ spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermType
addDecoration(dimConstId.back(), spv::DecorationSpecId, glslangIntermediate->getLocalSizeSpecId(dim));
}
return builder.makeCompositeConstant(builder.makeVectorType(builder.makeUintType(32), 3), dimConstId, true);
} else if (auto* sn = node.getAsSymbolNode()){
return createSpvConstantFromConstSubTree(sn->getConstSubtree());
} else {
spv::MissingFunctionality("specialization-constant expression trees");
spv::MissingFunctionality("Neither a front-end constant nor a spec constant.");
exit(1);
return spv::NoResult;
}
}
@@ -3782,7 +3787,7 @@ spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermType
// If there are not enough elements present in 'consts', 0 will be substituted;
// an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
//
spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant)
spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant)
{
// vector of constants for SPIR-V
std::vector<spv::Id> spvConsts;
@@ -3793,15 +3798,15 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangT
if (glslangType.isArray()) {
glslang::TType elementType(glslangType, 0);
for (int i = 0; i < glslangType.getOuterArraySize(); ++i)
spvConsts.push_back(createSpvConstant(elementType, consts, nextConst, false));
spvConsts.push_back(createSpvConstantFromConstUnionArray(elementType, consts, nextConst, false));
} else if (glslangType.isMatrix()) {
glslang::TType vectorType(glslangType, 0);
for (int col = 0; col < glslangType.getMatrixCols(); ++col)
spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst, false));
spvConsts.push_back(createSpvConstantFromConstUnionArray(vectorType, consts, nextConst, false));
} else if (glslangType.getStruct()) {
glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst, false));
spvConsts.push_back(createSpvConstantFromConstUnionArray(*iter->type, consts, nextConst, false));
} else if (glslangType.isVector()) {
for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {
bool zero = nextConst >= consts.size();
@@ -3858,6 +3863,97 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangT
return builder.makeCompositeConstant(typeId, spvConsts);
}
namespace {
class SpecConstantOpModeGuard {
public:
SpecConstantOpModeGuard(spv::Builder* builder)
: builder_(builder) {
previous_flag_ = builder->isInSpecConstCodeGenMode();
builder->setToSpecConstCodeGenMode();
}
~SpecConstantOpModeGuard() {
previous_flag_ ? builder_->setToSpecConstCodeGenMode()
: builder_->setToNormalCodeGenMode();
}
private:
spv::Builder* builder_;
bool previous_flag_;
};
}
// Create constant ID from const initializer sub tree.
spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstSubTree(
glslang::TIntermTyped* subTree)
{
const glslang::TType& glslangType = subTree->getType();
spv::Id typeId = convertGlslangToSpvType(glslangType);
bool is_spec_const = subTree->getType().getQualifier().isSpecConstant();
if (const glslang::TIntermAggregate* an = subTree->getAsAggregate()) {
// Aggregate node, we should generate OpConstantComposite or
// OpSpecConstantComposite instruction.
std::vector<spv::Id> const_constituents;
for (auto NI = an->getSequence().begin(); NI != an->getSequence().end();
NI++) {
const_constituents.push_back(
createSpvConstantFromConstSubTree((*NI)->getAsTyped()));
}
// Note that constructors are aggregate nodes, so expressions like:
// float x = float(y) will become an aggregate node. If 'x' is declared
// as a constant, the aggregate node representing 'float(y)' will be
// processed here.
if (builder.isVectorType(typeId) || builder.isMatrixType(typeId) ||
builder.isAggregateType(typeId)) {
return builder.makeCompositeConstant(typeId, const_constituents, is_spec_const);
} else {
assert(builder.isScalarType(typeId) && const_constituents.size() == 1);
return const_constituents.front();
}
} else if (glslang::TIntermBinary* bn = subTree->getAsBinaryNode()) {
// Binary operation node, we should generate OpSpecConstantOp <binary op>
// This case should only happen when Specialization Constants are involved.
// Spec constants defined with binary operations and other constants requires
// OpSpecConstantOp instruction.
SpecConstantOpModeGuard set_to_spec_const_mode(&builder);
bn->traverse(this);
return accessChainLoad(bn->getType());
} else if (glslang::TIntermUnary* un = subTree->getAsUnaryNode()) {
// Unary operation node, similar to binary operation node, should only
// happen when specialization constants are involved.
// Spec constants defined with unary operations and other constants requires
// OpSpecConstantOp instruction.
SpecConstantOpModeGuard set_to_spec_const_mode(&builder);
un->traverse(this);
return accessChainLoad(un->getType());
} else if (const glslang::TIntermConstantUnion* cn = subTree->getAsConstantUnion()) {
// ConstantUnion node, should redirect to
// createSpvConstantFromConstUnionArray
int nextConst = 0;
return createSpvConstantFromConstUnionArray(
glslangType, cn->getConstArray(), nextConst, is_spec_const);
} else if (const glslang::TIntermSymbol* sn = subTree->getAsSymbolNode()) {
// Symbol node. Call getSymbolId(). This should cover both cases 1) the
// symbol has already been assigned an ID, 2) need a new ID for this
// symbol.
return getSymbolId(sn);
} else {
spv::MissingFunctionality(
"createSpvConstantFromConstSubTree() not covered TIntermTyped* const "
"initializer subtree.");
return spv::NoResult;
}
}
// Return true if the node is a constant or symbol whose reading has no
// non-trivial observable cost or effect.
bool TGlslangToSpvTraverser::isTrivialLeaf(const glslang::TIntermTyped* node)

View File

@@ -573,7 +573,7 @@ namespace spv {
op_fn_nop);
// Window size for context-sensitive canonicalization values
// Emperical best size from a single data set. TODO: Would be a good tunable.
// Empirical best size from a single data set. TODO: Would be a good tunable.
// We essentially perform a little convolution around each instruction,
// to capture the flavor of nearby code, to hopefully match to similar
// code in other modules.

View File

@@ -64,7 +64,8 @@ Builder::Builder(unsigned int magicNumber) :
builderNumber(magicNumber),
buildPoint(0),
uniqueId(0),
mainFunction(0)
mainFunction(0),
generatingOpCodeForSpecConst(false)
{
clearAccessChain();
}
@@ -1063,6 +1064,11 @@ Id Builder::createArrayLength(Id base, unsigned int member)
Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
{
// Generate code for spec constants if in spec constant operation
// generation mode.
if (generatingOpCodeForSpecConst) {
return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), std::vector<Id>(1, index));
}
Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
extract->addIdOperand(composite);
extract->addImmediateOperand(index);
@@ -1073,6 +1079,11 @@ Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
Id Builder::createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes)
{
// Generate code for spec constants if in spec constant operation
// generation mode.
if (generatingOpCodeForSpecConst) {
return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), indexes);
}
Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
extract->addIdOperand(composite);
for (int i = 0; i < (int)indexes.size(); ++i)
@@ -1170,6 +1181,11 @@ void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemant
// An opcode that has one operands, a result id, and a type
Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
{
// Generate code for spec constants if in spec constant operation
// generation mode.
if (generatingOpCodeForSpecConst) {
return createSpecConstantOp(opCode, typeId, std::vector<Id>(1, operand), std::vector<Id>());
}
Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
op->addIdOperand(operand);
buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
@@ -1179,6 +1195,13 @@ Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)
{
// Generate code for spec constants if in spec constant operation
// generation mode.
if (generatingOpCodeForSpecConst) {
std::vector<Id> operands(2);
operands[0] = left; operands[1] = right;
return createSpecConstantOp(opCode, typeId, operands, std::vector<Id>());
}
Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
op->addIdOperand(left);
op->addIdOperand(right);
@@ -1208,6 +1231,20 @@ Id Builder::createOp(Op opCode, Id typeId, const std::vector<Id>& operands)
return op->getResultId();
}
Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector<Id>& operands, const std::vector<unsigned>& literals)
{
Instruction* op = new Instruction(getUniqueId(), typeId, OpSpecConstantOp);
op->addImmediateOperand((unsigned) opCode);
for (auto it = operands.cbegin(); it != operands.cend(); ++it)
op->addIdOperand(*it);
for (auto it = literals.cbegin(); it != literals.cend(); ++it)
op->addImmediateOperand(*it);
module.mapInstruction(op);
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(op));
return op->getResultId();
}
Id Builder::createFunctionCall(spv::Function* function, std::vector<spv::Id>& args)
{
Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);
@@ -1225,6 +1262,11 @@ Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, std:
if (channels.size() == 1)
return setPrecision(createCompositeExtract(source, typeId, channels.front()), precision);
if (generatingOpCodeForSpecConst) {
std::vector<Id> operands(2);
operands[0] = operands[1] = source;
return setPrecision(createSpecConstantOp(OpVectorShuffle, typeId, operands, channels), precision);
}
Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
assert(isVector(source));
swizzle->addIdOperand(source);
@@ -1290,10 +1332,23 @@ Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType)
if (numComponents == 1)
return scalar;
Instruction* smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);
for (int c = 0; c < numComponents; ++c)
smear->addIdOperand(scalar);
buildPoint->addInstruction(std::unique_ptr<Instruction>(smear));
Instruction* smear = nullptr;
if (generatingOpCodeForSpecConst) {
auto members = std::vector<spv::Id>(numComponents, scalar);
// 'scalar' can not be spec constant here. All spec constant involved
// promotion is done in createSpvConstantFromConstUnionArray(). This
// 'if' branch is only accessed when 'scalar' is used in the def-chain
// of other vector type spec constants. In such cases, all the
// instructions needed to promote 'scalar' to a vector type constants
// should be added at module level.
auto result_id = makeCompositeConstant(vectorType, members, false);
smear = module.getInstruction(result_id);
} else {
smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);
for (int c = 0; c < numComponents; ++c)
smear->addIdOperand(scalar);
buildPoint->addInstruction(std::unique_ptr<Instruction>(smear));
}
return setPrecision(smear->getResultId(), precision);
}
@@ -2158,7 +2213,7 @@ void Builder::eliminateDeadDecorations() {
}
}
decorations.erase(std::remove_if(decorations.begin(), decorations.end(),
[&unreachable_definitions](std::unique_ptr<Instruction>& I) {
[&unreachable_definitions](std::unique_ptr<Instruction>& I) -> bool {
Instruction* inst = I.get();
Id decoration_id = inst->getIdOperand(0);
return unreachable_definitions.count(decoration_id) != 0;
@@ -2268,7 +2323,7 @@ void Builder::simplifyAccessChainSwizzle()
// To the extent any swizzling can become part of the chain
// of accesses instead of a post operation, make it so.
// If 'dynamic' is true, include transfering a non-static component index,
// If 'dynamic' is true, include transferring a non-static component index,
// otherwise, only transfer static indexes.
//
// Also, Boolean vectors are likely to be special. While

View File

@@ -262,6 +262,7 @@ public:
Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
Id createOp(Op, Id typeId, const std::vector<Id>& operands);
Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);
Id createSpecConstantOp(Op, Id typeId, const std::vector<spv::Id>& operands, const std::vector<unsigned>& literals);
// Take an rvalue (source) and a set of channels to extract from it to
// make a new rvalue, which is returned.
@@ -521,6 +522,13 @@ public:
void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control);
// Sets to generate opcode for specialization constants.
void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
// Sets to generate opcode for non-specialization constants (normal mode).
void setToNormalCodeGenMode() { generatingOpCodeForSpecConst = false; }
// Check if the builder is generating code for spec constants.
bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; }
protected:
Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const;
@@ -544,6 +552,7 @@ public:
Block* buildPoint;
Id uniqueId;
Function* mainFunction;
bool generatingOpCodeForSpecConst;
AccessChain accessChain;
// special blocks of instructions for output