Merge branch 'master' into hlsl-frontend
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user