Skip to content

Commit 639f546

Browse files
authored
New nonuniform analysis (KhronosGroup#2457)
This implements a new nonunifom analysis suggested by @jbolz. This change generates nonUniform decorations that were previously missing and avoids generation of incorrect decorations. Most notably, it now generates decorations for nonuniform functions and out params. It avoids generating decorations for lvalues which themselves are not nonuniform.
1 parent 74e8f05 commit 639f546

File tree

6 files changed

+496
-373
lines changed

6 files changed

+496
-373
lines changed

SPIRV/GlslangToSpv.cpp

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ class TGlslangToSpvTraverser : public glslang::TIntermTraverser {
149149
spv::Decoration TranslateInterpolationDecoration(const glslang::TQualifier& qualifier);
150150
spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier);
151151
spv::Decoration TranslateNonUniformDecoration(const glslang::TQualifier& qualifier);
152+
spv::Decoration TranslateNonUniformDecoration(const spv::Builder::AccessChain::CoherentFlags& coherentFlags);
152153
spv::Builder::AccessChain::CoherentFlags TranslateCoherent(const glslang::TType& type);
153154
spv::MemoryAccessMask TranslateMemoryAccess(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);
154155
spv::ImageOperandsMask TranslateImageOperands(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);
@@ -539,6 +540,20 @@ spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(const glsl
539540
return spv::DecorationMax;
540541
}
541542

543+
// If lvalue flags contains nonUniform, return SPIR-V NonUniform decoration.
544+
spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(
545+
const spv::Builder::AccessChain::CoherentFlags& coherentFlags)
546+
{
547+
#ifndef GLSLANG_WEB
548+
if (coherentFlags.isNonUniform()) {
549+
builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
550+
builder.addCapability(spv::CapabilityShaderNonUniformEXT);
551+
return spv::DecorationNonUniformEXT;
552+
} else
553+
#endif
554+
return spv::DecorationMax;
555+
}
556+
542557
spv::MemoryAccessMask TGlslangToSpvTraverser::TranslateMemoryAccess(
543558
const spv::Builder::AccessChain::CoherentFlags &coherentFlags)
544559
{
@@ -614,6 +629,7 @@ spv::Builder::AccessChain::CoherentFlags TGlslangToSpvTraverser::TranslateCohere
614629
flags.volatil;
615630
flags.isImage = type.getBasicType() == glslang::EbtSampler;
616631
#endif
632+
flags.nonUniform = type.getQualifier().nonUniform;
617633
return flags;
618634
}
619635

@@ -1376,6 +1392,8 @@ void InheritQualifiers(glslang::TQualifier& child, const glslang::TQualifier& pa
13761392
if (parent.writeonly)
13771393
child.writeonly = true;
13781394
#endif
1395+
if (parent.nonUniform)
1396+
child.nonUniform = true;
13791397
}
13801398

13811399
bool HasNonLayoutQualifiers(const glslang::TType& type, const glslang::TQualifier& qualifier)
@@ -1881,9 +1899,11 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
18811899
spv::Id leftRValue = accessChainLoad(node->getLeft()->getType());
18821900

18831901
// do the operation
1902+
spv::Builder::AccessChain::CoherentFlags coherentFlags = TranslateCoherent(node->getLeft()->getType());
1903+
coherentFlags |= TranslateCoherent(node->getRight()->getType());
18841904
OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
18851905
TranslateNoContractionDecoration(node->getType().getQualifier()),
1886-
TranslateNonUniformDecoration(node->getType().getQualifier()) };
1906+
TranslateNonUniformDecoration(coherentFlags) };
18871907
rValue = createBinaryOperation(node->getOp(), decorations,
18881908
convertGlslangToSpvType(node->getType()), leftRValue, rValue,
18891909
node->getType().getBasicType());
@@ -1914,13 +1934,16 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
19141934
if (! node->getLeft()->getType().isArray() &&
19151935
node->getLeft()->getType().isVector() &&
19161936
node->getOp() == glslang::EOpIndexDirect) {
1937+
// Swizzle is uniform so propagate uniform into access chain
1938+
spv::Builder::AccessChain::CoherentFlags coherentFlags = TranslateCoherent(node->getLeft()->getType());
1939+
coherentFlags.nonUniform = 0;
19171940
// This is essentially a hard-coded vector swizzle of size 1,
19181941
// so short circuit the access-chain stuff with a swizzle.
19191942
std::vector<unsigned> swizzle;
19201943
swizzle.push_back(glslangIndex);
19211944
int dummySize;
19221945
builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),
1923-
TranslateCoherent(node->getLeft()->getType()),
1946+
coherentFlags,
19241947
glslangIntermediate->getBaseAlignmentScalar(
19251948
node->getLeft()->getType(), dummySize));
19261949
} else {
@@ -1951,9 +1974,14 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
19511974
}
19521975
}
19531976

1977+
// Struct reference propagates uniform lvalue
1978+
spv::Builder::AccessChain::CoherentFlags coherentFlags =
1979+
TranslateCoherent(node->getLeft()->getType());
1980+
coherentFlags.nonUniform = 0;
1981+
19541982
// normal case for indexing array or structure or block
19551983
builder.accessChainPush(builder.makeIntConstant(spvIndex),
1956-
TranslateCoherent(node->getLeft()->getType()),
1984+
coherentFlags,
19571985
node->getLeft()->getType().getBufferReferenceAlignment());
19581986

19591987
// Add capabilities here for accessing PointSize and clip/cull distance.
@@ -1987,15 +2015,20 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
19872015
// restore the saved access chain
19882016
builder.setAccessChain(partial);
19892017

2018+
// Only if index is nonUniform should we propagate nonUniform into access chain
2019+
spv::Builder::AccessChain::CoherentFlags index_flags = TranslateCoherent(node->getRight()->getType());
2020+
spv::Builder::AccessChain::CoherentFlags coherent_flags = TranslateCoherent(node->getLeft()->getType());
2021+
coherent_flags.nonUniform = index_flags.nonUniform;
2022+
19902023
if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector()) {
19912024
int dummySize;
1992-
builder.accessChainPushComponent(index, convertGlslangToSpvType(node->getLeft()->getType()),
1993-
TranslateCoherent(node->getLeft()->getType()),
2025+
builder.accessChainPushComponent(
2026+
index, convertGlslangToSpvType(node->getLeft()->getType()), coherent_flags,
19942027
glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(),
19952028
dummySize));
19962029
} else
1997-
builder.accessChainPush(index, TranslateCoherent(node->getLeft()->getType()),
1998-
node->getLeft()->getType().getBufferReferenceAlignment());
2030+
builder.accessChainPush(index, coherent_flags,
2031+
node->getLeft()->getType().getBufferReferenceAlignment());
19992032
}
20002033
return false;
20012034
case glslang::EOpVectorSwizzle:
@@ -2119,7 +2152,7 @@ spv::Id TGlslangToSpvTraverser::translateForcedType(spv::Id object)
21192152
// handle 32-bit v.xy* -> 64-bit
21202153
builder.clearAccessChain();
21212154
builder.setAccessChainLValue(object);
2122-
object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, objectTypeId);
2155+
object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, spv::DecorationMax, objectTypeId);
21232156
std::vector<spv::Id> components;
21242157
components.push_back(builder.createCompositeExtract(object, builder.getContainedTypeId(objectTypeId), 0));
21252158
components.push_back(builder.createCompositeExtract(object, builder.getContainedTypeId(objectTypeId), 1));
@@ -2135,7 +2168,7 @@ spv::Id TGlslangToSpvTraverser::translateForcedType(spv::Id object)
21352168
// and we insert a transpose after loading the original non-transposed builtins
21362169
builder.clearAccessChain();
21372170
builder.setAccessChainLValue(object);
2138-
object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, objectTypeId);
2171+
object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, spv::DecorationMax, objectTypeId);
21392172
return builder.createUnaryOp(spv::OpTranspose, desiredTypeId, object);
21402173

21412174
} else {
@@ -2322,7 +2355,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
23222355
// The result of operation is always stored, but conditionally the
23232356
// consumed result. The consumed result is always an r-value.
23242357
builder.accessChainStore(result,
2325-
TranslateNonUniformDecoration(node->getOperand()->getType().getQualifier()));
2358+
TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags));
23262359
builder.clearAccessChain();
23272360
if (node->getOp() == glslang::EOpPreIncrement ||
23282361
node->getOp() == glslang::EOpPreDecrement)
@@ -2398,7 +2431,6 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
23982431
spv::Id invertedType = spv::NoType; // to use to override the natural type of the node
23992432
std::vector<spv::Builder::AccessChain> complexLvalues; // for holding swizzling l-values too complex for
24002433
// SPIR-V, for an out parameter
2401-
std::vector<glslang::TQualifier> complexLValueQualifiers;
24022434
std::vector<spv::Id> temporaryLvalues; // temporaries to pass, as proxies for complexLValues
24032435

24042436
auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ?
@@ -3020,7 +3052,6 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
30203052
// receive the result, and must later swizzle that into the original
30213053
// l-value.
30223054
complexLvalues.push_back(builder.getAccessChain());
3023-
complexLValueQualifiers.push_back(glslangOperands[arg]->getAsTyped()->getType().getQualifier());
30243055
temporaryLvalues.push_back(builder.createVariable(
30253056
spv::NoPrecision, spv::StorageClassFunction,
30263057
builder.accessChainGetInferredType(), "swizzleTemp"));
@@ -3125,7 +3156,8 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
31253156

31263157
for (unsigned int i = 0; i < temporaryLvalues.size(); ++i) {
31273158
builder.setAccessChain(complexLvalues[i]);
3128-
builder.accessChainStore(builder.createLoad(temporaryLvalues[i], spv::NoPrecision), TranslateNonUniformDecoration(complexLValueQualifiers[i]));
3159+
builder.accessChainStore(builder.createLoad(temporaryLvalues[i], spv::NoPrecision),
3160+
TranslateNonUniformDecoration(complexLvalues[i].coherentFlags));
31293161
}
31303162
}
31313163

@@ -4135,6 +4167,7 @@ spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type)
41354167
alignment |= type.getBufferReferenceAlignment();
41364168

41374169
spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type),
4170+
TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags),
41384171
TranslateNonUniformDecoration(type.getQualifier()),
41394172
nominalTypeId,
41404173
spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerAvailableKHRMask),
@@ -4202,7 +4235,7 @@ void TGlslangToSpvTraverser::accessChainStore(const glslang::TType& type, spv::I
42024235
unsigned int alignment = builder.getAccessChain().alignment;
42034236
alignment |= type.getBufferReferenceAlignment();
42044237

4205-
builder.accessChainStore(rvalue, TranslateNonUniformDecoration(type.getQualifier()),
4238+
builder.accessChainStore(rvalue, TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags),
42064239
spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) &
42074240
~spv::MemoryAccessMakePointerVisibleKHRMask),
42084241
TranslateMemoryScope(coherentFlags), alignment);
@@ -4734,8 +4767,10 @@ void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate&
47344767
}
47354768

47364769
if (lvalue) {
4737-
arguments.push_back(builder.accessChainGetLValue());
4770+
spv::Id lvalue_id = builder.accessChainGetLValue();
4771+
arguments.push_back(lvalue_id);
47384772
lvalueCoherentFlags = builder.getAccessChain().coherentFlags;
4773+
builder.addDecoration(lvalue_id, TranslateNonUniformDecoration(lvalueCoherentFlags));
47394774
lvalueCoherentFlags |= TranslateCoherent(glslangArguments[i]->getAsTyped()->getType());
47404775
} else
47414776
#endif
@@ -5415,6 +5450,7 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg
54155450
// 3. Make the call.
54165451
spv::Id result = builder.createFunctionCall(function, spvArgs);
54175452
builder.setPrecision(result, TranslatePrecisionDecoration(node->getType()));
5453+
builder.addDecoration(result, TranslateNonUniformDecoration(node->getType().getQualifier()));
54185454

54195455
// 4. Copy back out an "out" arguments.
54205456
lValueCount = 0;
@@ -5424,6 +5460,7 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg
54245460
else if (writableParam(qualifiers[a])) {
54255461
if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {
54265462
spv::Id copy = builder.createLoad(spvArgs[a], spv::NoPrecision);
5463+
builder.addDecoration(copy, TranslateNonUniformDecoration(argTypes[a]->getQualifier()));
54275464
builder.setAccessChain(lValues[lValueCount]);
54285465
multiTypeStore(*argTypes[a], copy);
54295466
}
@@ -8228,9 +8265,6 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol
82288265
builder.addDecoration(id, memory[i]);
82298266
}
82308267

8231-
// nonuniform
8232-
builder.addDecoration(id, TranslateNonUniformDecoration(symbol->getType().getQualifier()));
8233-
82348268
if (builtIn == spv::BuiltInSampleMask) {
82358269
spv::Decoration decoration;
82368270
// GL_NV_sample_mask_override_coverage extension

SPIRV/SpvBuilder.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2798,8 +2798,9 @@ void Builder::accessChainStore(Id rvalue, Decoration nonUniform, spv::MemoryAcce
27982798
}
27992799

28002800
// Comments in header
2801-
Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resultType,
2802-
spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
2801+
Id Builder::accessChainLoad(Decoration precision, Decoration l_nonUniform,
2802+
Decoration r_nonUniform, Id resultType, spv::MemoryAccessMask memoryAccess,
2803+
spv::Scope scope, unsigned int alignment)
28032804
{
28042805
Id id;
28052806

@@ -2863,9 +2864,9 @@ Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resu
28632864
// Buffer accesses need the access chain decorated, and this is where
28642865
// loaded image types get decorated. TODO: This should maybe move to
28652866
// createImageTextureFunctionCall.
2866-
addDecoration(id, nonUniform);
2867+
addDecoration(id, l_nonUniform);
28672868
id = createLoad(id, precision, memoryAccess, scope, alignment);
2868-
addDecoration(id, nonUniform);
2869+
addDecoration(id, r_nonUniform);
28692870
}
28702871

28712872
// Done, unless there are swizzles to do
@@ -2886,7 +2887,7 @@ Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resu
28862887
if (accessChain.component != NoResult)
28872888
id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision);
28882889

2889-
addDecoration(id, nonUniform);
2890+
addDecoration(id, r_nonUniform);
28902891
return id;
28912892
}
28922893

SPIRV/SpvBuilder.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,7 @@ class Builder {
625625
CoherentFlags operator |=(const CoherentFlags &other) { return *this; }
626626
#else
627627
bool isVolatile() const { return volatil; }
628+
bool isNonUniform() const { return nonUniform; }
628629
bool anyCoherent() const {
629630
return coherent || devicecoherent || queuefamilycoherent || workgroupcoherent ||
630631
subgroupcoherent || shadercallcoherent;
@@ -639,6 +640,7 @@ class Builder {
639640
unsigned nonprivate : 1;
640641
unsigned volatil : 1;
641642
unsigned isImage : 1;
643+
unsigned nonUniform : 1;
642644

643645
void clear() {
644646
coherent = 0;
@@ -650,6 +652,7 @@ class Builder {
650652
nonprivate = 0;
651653
volatil = 0;
652654
isImage = 0;
655+
nonUniform = 0;
653656
}
654657

655658
CoherentFlags operator |=(const CoherentFlags &other) {
@@ -662,6 +665,7 @@ class Builder {
662665
nonprivate |= other.nonprivate;
663666
volatil |= other.volatil;
664667
isImage |= other.isImage;
668+
nonUniform |= other.nonUniform;
665669
return *this;
666670
}
667671
#endif
@@ -727,7 +731,7 @@ class Builder {
727731
spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
728732

729733
// use accessChain and swizzle to load an r-value
730-
Id accessChainLoad(Decoration precision, Decoration nonUniform, Id ResultType,
734+
Id accessChainLoad(Decoration precision, Decoration l_nonUniform, Decoration r_nonUniform, Id ResultType,
731735
spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax,
732736
unsigned int alignment = 0);
733737

0 commit comments

Comments
 (0)