summaryrefslogtreecommitdiff
path: root/source/slang
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-06-08 05:12:49 -0700
committerGitHub <noreply@github.com>2024-06-08 05:12:49 -0700
commit9a23a9aab3721828526c921db1e779008e133e8f (patch)
treeb49448075cdffe278fd6760e2879bc061eb8e0af /source/slang
parentbc680e74bd8a0c415cab5ed6fe00b762c26b8b8d (diff)
SPIRV `Block` decoration fixes. (#4303)
* SPIRV `Block` decoration fixes. - SPIRV does not allow duplicate `Block` decorations. So we shouldn't be generating them. - Also fixes duplication of OpName. - SPIRV and HLSL do not allow ConstantBuffer with trailing unsized arrays. Added a check in the front-end against such code. * Convert failing cross-compile tests to filecheck. --------- Co-authored-by: Jay Kwak <82421531+jkwak-work@users.noreply.github.com>
Diffstat (limited to 'source/slang')
-rw-r--r--source/slang/slang-capability.cpp17
-rw-r--r--source/slang/slang-capability.h3
-rw-r--r--source/slang/slang-check-decl.cpp87
-rw-r--r--source/slang/slang-check-impl.h7
-rw-r--r--source/slang/slang-compiler.cpp38
-rw-r--r--source/slang/slang-diagnostic-defs.h2
-rw-r--r--source/slang/slang-emit-spirv.cpp5
-rw-r--r--source/slang/slang-ir-glsl-legalize.cpp2
-rw-r--r--source/slang/slang-ir-specialize-target-switch.cpp4
-rw-r--r--source/slang/slang-options.cpp7
-rw-r--r--source/slang/slang-profile.h2
11 files changed, 170 insertions, 4 deletions
diff --git a/source/slang/slang-capability.cpp b/source/slang/slang-capability.cpp
index 750026a64..21b2641b4 100644
--- a/source/slang/slang-capability.cpp
+++ b/source/slang/slang-capability.cpp
@@ -252,6 +252,23 @@ void CapabilitySet::addUnexpandedCapabilites(CapabilityName atom)
addConjunction(*cr, CapabilityAtom::Invalid, CapabilityAtom::Invalid);
}
+CapabilityAtom CapabilitySet::getUniquelyImpliedStageAtom() const
+{
+ CapabilityAtom result = CapabilityAtom::Invalid;
+ for (auto& targetKV : m_targetSets)
+ {
+ if (targetKV.second.shaderStageSets.getCount() == 1)
+ {
+ auto thisStage = targetKV.second.shaderStageSets.begin()->first;
+ if (result == CapabilityAtom::Invalid)
+ result = thisStage;
+ else if (result != thisStage)
+ return CapabilityAtom::Invalid;
+ }
+ }
+ return result;
+}
+
CapabilitySet::CapabilitySet()
{}
diff --git a/source/slang/slang-capability.h b/source/slang/slang-capability.h
index 6e123a9a6..8fd9e2bd4 100644
--- a/source/slang/slang-capability.h
+++ b/source/slang/slang-capability.h
@@ -184,6 +184,9 @@ public:
CapabilityTargetSets& getCapabilityTargetSets() { return m_targetSets; }
const CapabilityTargetSets& getCapabilityTargetSets() const { return m_targetSets; }
+ // If this capability set uniquely implies one stage atom, return it. Otherwise returns CapabilityAtom::Invalid.
+ CapabilityAtom getUniquelyImpliedStageAtom() const;
+
struct AtomSets
{
struct Iterator
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index 95528b185..bf61a6c2e 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -2101,6 +2101,19 @@ namespace Slang
{
getSink()->diagnose(varDecl->type.exp->loc, Diagnostics::incompleteTypeCannotBeUsedInBuffer, elementType);
}
+ if (doesTypeHaveTag(elementType, TypeTag::Unsized))
+ {
+ // If the element type is unsized, it can only be an array of resource types that we can legalize out.
+ // Ordinary unsized arrays are not allowed in a constant buffer since we cannot translate it to
+ // valid HLSL or SPIRV.
+ ArrayExpressionType* trailingArrayType = nullptr;
+ VarDeclBase* trailingArrayField = getTrailingUnsizedArrayElement(elementType, varDecl, trailingArrayType);
+ if (trailingArrayField && !isOpaqueHandleType(trailingArrayType->getElementType()))
+ {
+ getSink()->diagnose(trailingArrayField->loc, Diagnostics::cannotUseUnsizedTypeInConstantBuffer, trailingArrayType);
+ getSink()->diagnose(varDecl->loc, Diagnostics::seeConstantBufferDefinition);
+ }
+ }
}
else if (varDecl->findModifier<HLSLUniformModifier>())
{
@@ -10420,6 +10433,80 @@ namespace Slang
return defaultVis;
}
+ VarDeclBase* getTrailingUnsizedArrayElement(Type* type, VarDeclBase* parentVar, ArrayExpressionType*& outArrayType)
+ {
+ while (auto modifiedType = as<ModifiedType>(type))
+ type = modifiedType->getBase();
+ HashSet<Type*> seenTypes;
+ for (;;)
+ {
+ if (auto arrayType = as<ArrayExpressionType>(type))
+ {
+ if (arrayType->isUnsized())
+ {
+ outArrayType = arrayType;
+ return parentVar;
+ }
+ else
+ return nullptr;
+ }
+ else if (auto declRefType = as<DeclRefType>(type))
+ {
+ if (auto aggTypeDecl = declRefType->getDeclRef().as<AggTypeDecl>())
+ {
+ auto varDecls = aggTypeDecl.getDecl()->getMembersOfType<VarDeclBase>();
+ if (varDecls.getCount() == 0)
+ return nullptr;
+ VarDeclBase* lastVarDecl = nullptr;
+ for (auto varDecl : varDecls)
+ {
+ if (isEffectivelyStatic(varDecl))
+ continue;
+ lastVarDecl = varDecl;
+ }
+ auto lastMember = _getMemberDeclRef(
+ getCurrentASTBuilder(), aggTypeDecl, lastVarDecl).as<VarDeclBase>();
+ auto varType = getType(getCurrentASTBuilder(), lastMember);
+ if (!varType)
+ return nullptr;
+ if (!seenTypes.add(type))
+ return nullptr;
+ type = varType;
+ parentVar = lastMember.getDecl();
+ continue;
+ }
+ }
+ }
+ return nullptr;
+ }
+
+ bool isOpaqueHandleType(Type* type)
+ {
+ while (auto modifiedType = as<ModifiedType>(type))
+ type = modifiedType->getBase();
+ if (as<ResourceType>(type))
+ return true;
+ if (as<SamplerStateType>(type))
+ return true;
+ if (as<UniformParameterGroupType>(type))
+ return true;
+ if (as<HLSLStructuredBufferTypeBase>(type))
+ return true;
+ if (as<UntypedBufferResourceType>(type))
+ return true;
+ if (as<GLSLShaderStorageBufferType>(type))
+ return true;
+ if (as<FeedbackType>(type))
+ return true;
+ if (as<HLSLPatchType>(type))
+ return true;
+ if (as<HLSLStreamOutputType>(type))
+ return true;
+ if (as<MeshOutputType>(type))
+ return true;
+ return false;
+ }
+
void diagnoseCapabilityProvenance(CompilerOptionSet& optionSet, DiagnosticSink* sink, Decl* decl, CapabilityAtom atomToFind, bool optionallyNeverPrintDecl)
{
HashSet<Decl*> printedDecls;
diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h
index 2554d0d85..ab6bc6585 100644
--- a/source/slang/slang-check-impl.h
+++ b/source/slang/slang-check-impl.h
@@ -2837,6 +2837,13 @@ namespace Slang
DeclVisibility getDeclVisibility(Decl* decl);
+ // If `type` is unsized, return the trailing unsized array field that makes it so.
+ VarDeclBase* getTrailingUnsizedArrayElement(Type* type, VarDeclBase* rootObject, ArrayExpressionType*& outArrayType);
+
+ // Test if `type` can be an opaque handle on certain targets, this includes
+ // texture, buffer, sampler, acceleration structure, etc.
+ bool isOpaqueHandleType(Type* type);
+
void diagnoseCapabilityProvenance(CompilerOptionSet& optionSet, DiagnosticSink* sink, Decl* decl, CapabilityAtom atomToFind, bool optionallyNeverPrintDecl = false);
void _ensureAllDeclsRec(
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp
index 147d4a889..0277bb092 100644
--- a/source/slang/slang-compiler.cpp
+++ b/source/slang/slang-compiler.cpp
@@ -433,6 +433,44 @@ namespace Slang
return UnownedStringSlice();
}
+ Stage getStageFromAtom(CapabilityAtom atom)
+ {
+ switch (atom)
+ {
+ case CapabilityAtom::vertex:
+ return Stage::Vertex;
+ case CapabilityAtom::hull:
+ return Stage::Hull;
+ case CapabilityAtom::domain:
+ return Stage::Domain;
+ case CapabilityAtom::geometry:
+ return Stage::Geometry;
+ case CapabilityAtom::fragment:
+ return Stage::Fragment;
+ case CapabilityAtom::compute:
+ return Stage::Compute;
+ case CapabilityAtom::mesh:
+ return Stage::Mesh;
+ case CapabilityAtom::amplification:
+ return Stage::Amplification;
+ case CapabilityAtom::anyhit:
+ return Stage::AnyHit;
+ case CapabilityAtom::closesthit:
+ return Stage::ClosestHit;
+ case CapabilityAtom::intersection:
+ return Stage::Intersection;
+ case CapabilityAtom::raygen:
+ return Stage::RayGeneration;
+ case CapabilityAtom::miss:
+ return Stage::Miss;
+ case CapabilityAtom::callable:
+ return Stage::Callable;
+ default:
+ SLANG_UNEXPECTED("unknown stage atom");
+ UNREACHABLE_RETURN(Stage::Unknown);
+ }
+ }
+
SlangResult checkExternalCompilerSupport(Session* session, PassThroughMode passThrough)
{
// Check if the type is supported on this compile
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index b011227fd..100543864 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -28,6 +28,7 @@ DIAGNOSTIC(-1, Note, implicitParameterMatchingFailedBecauseShaderDoesNotDefineCo
DIAGNOSTIC(-1, Note, implicitParameterMatchingFailedBecauseTypeMismatch, "implicit parameter matching failed because the component of the same name does not match parameter type '$0'.")
DIAGNOSTIC(-1, Note, noteShaderIsTargetingPipeine, "shader '$0' is targeting pipeline '$1'")
DIAGNOSTIC(-1, Note, seeDefinitionOf, "see definition of '$0'")
+DIAGNOSTIC(-1, Note, seeConstantBufferDefinition, "see constant buffer definition.")
DIAGNOSTIC(-1, Note, seeInterfaceDefinitionOf, "see interface definition of '$0'")
DIAGNOSTIC(-1, Note, seeUsingOf, "see using of '$0'")
DIAGNOSTIC(-1, Note, seeDefinitionOfShader, "see definition of shader '$0'")
@@ -459,6 +460,7 @@ DIAGNOSTIC(31211, Error, derivativeGroupLinearMustBeMultiple4ForTotalThreadCount
DIAGNOSTIC(31212, Error, onlyOneOfDerivativeGroupLinearOrQuadCanBeSet, "cannot set compute derivative group linear and compute derivative group quad at the same time")
DIAGNOSTIC(31213, Error, cudaKernelMustReturnVoid, "return type of a CUDA kernel function cannot be non-void.")
DIAGNOSTIC(31214, Error, differentiableKernelEntryPointCannotHaveDifferentiableParams, "differentiable kernel entry point cannot have differentiable parameters. Consider using DiffTensorView to pass differentiable data, or marking this parameter with 'no_diff'")
+DIAGNOSTIC(31215, Error, cannotUseUnsizedTypeInConstantBuffer, "cannot use unsized type '$0' in a constant buffer.")
// Enums
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index 769e36861..1ef3a31e0 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -1481,7 +1481,8 @@ struct SPIRVEmitContext
if (structSize >= (uint64_t)IRSizeAndAlignment::kIndeterminateSize)
{
IRBuilder builder(inst);
- if (isSpirv14OrLater() || !inst->findDecorationImpl(kIROp_SPIRVBufferBlockDecoration))
+ if ((isSpirv14OrLater() || !inst->findDecorationImpl(kIROp_SPIRVBufferBlockDecoration))
+ && !inst->findDecorationImpl(kIROp_SPIRVBlockDecoration))
{
auto decoration = builder.addDecoration(inst, kIROp_SPIRVBlockDecoration);
emitDecoration(getID(spvStructType), decoration);
@@ -2308,7 +2309,6 @@ struct SPIRVEmitContext
maybeEmitPointerDecoration(varInst, param);
if (auto layout = getVarLayout(param))
emitVarLayout(param, varInst, layout);
- maybeEmitName(varInst, param);
emitDecorations(param, getID(varInst));
return varInst;
}
@@ -2332,7 +2332,6 @@ struct SPIRVEmitContext
maybeEmitPointerDecoration(varInst, globalVar);
if(layout)
emitVarLayout(globalVar, varInst, layout);
- maybeEmitName(varInst, globalVar);
emitDecorations(globalVar, getID(varInst));
return varInst;
}
diff --git a/source/slang/slang-ir-glsl-legalize.cpp b/source/slang/slang-ir-glsl-legalize.cpp
index eb5905dfe..9b30b6072 100644
--- a/source/slang/slang-ir-glsl-legalize.cpp
+++ b/source/slang/slang-ir-glsl-legalize.cpp
@@ -1525,6 +1525,8 @@ ScalarizedVal createGLSLGlobalVaryings(
StringBuilder namehintSB;
if (auto nameHint = leafVar->findDecoration<IRNameHintDecoration>())
{
+ if (leafVar->getOp() == kIROp_Func)
+ namehintSB << "entryPointParam_";
namehintSB << nameHint->getName();
}
OuterParamInfoLink outerParamInfo;
diff --git a/source/slang/slang-ir-specialize-target-switch.cpp b/source/slang/slang-ir-specialize-target-switch.cpp
index fac1dd484..46ea51192 100644
--- a/source/slang/slang-ir-specialize-target-switch.cpp
+++ b/source/slang/slang-ir-specialize-target-switch.cpp
@@ -31,7 +31,9 @@ namespace Slang
bool isBetterForTarget = capSet.isBetterForTarget(bestCapSet, target->getTargetCaps(), isEqual);
if (isBetterForTarget)
{
- bool targetImpliesCapSet = (target->getTargetCaps().implies(capSet, true) || capSet.isEmpty());
+ CapabilitySet joinedCapSet = capSet;
+ joinedCapSet.join(target->getTargetCaps());
+ bool targetImpliesCapSet = target->getTargetCaps().implies(joinedCapSet, true);
if (targetImpliesCapSet)
{
// Now check if bestCapSet contains targetCaps. If it does not then this is an invalid target
diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp
index 7b4b02f68..4bbd0dcaf 100644
--- a/source/slang/slang-options.cpp
+++ b/source/slang/slang-options.cpp
@@ -1051,6 +1051,13 @@ void OptionsParser::setProfileVersion(RawTarget* rawTarget, ProfileVersion profi
void OptionsParser::addCapabilityAtom(RawTarget* rawTarget, CapabilityName atom)
{
+ CapabilitySet capSet(atom);
+ auto stageAtom = capSet.getUniquelyImpliedStageAtom();
+ if (stageAtom != CapabilityAtom::Invalid)
+ {
+ Stage stage = getStageFromAtom(stageAtom);
+ setStage(getCurrentEntryPoint(), stage);
+ }
rawTarget->optionSet.addCapabilityAtom(atom);
}
diff --git a/source/slang/slang-profile.h b/source/slang/slang-profile.h
index bd6feab23..9a164805b 100644
--- a/source/slang/slang-profile.h
+++ b/source/slang/slang-profile.h
@@ -128,6 +128,8 @@ namespace Slang
Stage findStageByName(String const& name);
UnownedStringSlice getStageText(Stage stage);
+
+ Stage getStageFromAtom(CapabilityAtom atom);
}
#endif