summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-02-09 22:00:15 -0800
committerGitHub <noreply@github.com>2024-02-09 22:00:15 -0800
commit20ab16178e45d07b4dc0104a7a98865d18440b62 (patch)
tree5314057a48d5ad2346fa808e4cfacff0991ce9b9
parentf44da6cc5c0f211c13bd1eb0743d79c7861ea64e (diff)
Support link-time constants. (#3564)
* Support link-time constants. * Fix. * Fix.
-rw-r--r--build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj2
-rw-r--r--build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters6
-rw-r--r--source/slang/slang-check-decl.cpp7
-rw-r--r--source/slang/slang-check-expr.cpp3
-rw-r--r--source/slang/slang-diagnostic-defs.h8
-rw-r--r--source/slang/slang-mangle.cpp42
-rw-r--r--tools/gfx-unit-test/gfx-test-util.h2
-rw-r--r--tools/gfx-unit-test/link-time-constant.cpp156
-rw-r--r--tools/gfx-unit-test/link-time-constant.slang20
9 files changed, 229 insertions, 17 deletions
diff --git a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj
index 5cd61e7fe..335fa8156 100644
--- a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj
+++ b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj
@@ -303,6 +303,7 @@
<ClCompile Include="..\..\..\tools\gfx-unit-test\gfx-test-texture-util.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\gfx-test-util.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\instanced-draw-tests.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\link-time-constant.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\mutable-shader-object.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\nested-parameter-block.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\ray-tracing-tests.cpp" />
@@ -323,6 +324,7 @@
<None Include="..\..\..\tools\gfx-unit-test\compute-trivial.slang" />
<None Include="..\..\..\tools\gfx-unit-test\format-test-shaders.slang" />
<None Include="..\..\..\tools\gfx-unit-test\graphics-smoke.slang" />
+ <None Include="..\..\..\tools\gfx-unit-test\link-time-constant.slang" />
<None Include="..\..\..\tools\gfx-unit-test\mutable-shader-object.slang" />
<None Include="..\..\..\tools\gfx-unit-test\nested-parameter-block.slang" />
<None Include="..\..\..\tools\gfx-unit-test\ray-tracing-test-shaders.slang" />
diff --git a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters
index 58045ccee..fa5ca30e5 100644
--- a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters
+++ b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters
@@ -65,6 +65,9 @@
<ClCompile Include="..\..\..\tools\gfx-unit-test\instanced-draw-tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\link-time-constant.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\..\..\tools\gfx-unit-test\mutable-shader-object.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -121,6 +124,9 @@
<None Include="..\..\..\tools\gfx-unit-test\graphics-smoke.slang">
<Filter>Source Files</Filter>
</None>
+ <None Include="..\..\..\tools\gfx-unit-test\link-time-constant.slang">
+ <Filter>Source Files</Filter>
+ </None>
<None Include="..\..\..\tools\gfx-unit-test\mutable-shader-object.slang">
<Filter>Source Files</Filter>
</None>
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index 3882994da..2a6ee8abc 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -1471,6 +1471,11 @@ namespace Slang
}
else
{
+ if (varDecl->hasModifier<ExternModifier>())
+ {
+ getSink()->diagnose(initExpr, Diagnostics::externValueCannotHaveInitializer);
+ }
+
initExpr = CheckExpr(initExpr);
// TODO: We might need some additional steps here to ensure
@@ -1484,7 +1489,7 @@ namespace Slang
_validateCircularVarDefinition(varDecl);
}
-
+
// If we've gone down this path, then the variable
// declaration is actually pretty far along in checking
varDecl->setCheckState(DeclCheckState::DefinitionChecked);
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index 2f4906826..c04cb73e4 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -1659,6 +1659,9 @@ namespace Slang
return nullptr;
if(!decl->hasModifier<ConstModifier>())
return nullptr;
+ // Extern static const is not considered compile-time constant by the front-end.
+ if (decl->hasModifier<ExternModifier>())
+ return nullptr;
if (isInterfaceRequirement(decl))
{
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 9b599ae2e..ac1f9aff9 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -478,10 +478,10 @@ DIAGNOSTIC(30502, Error, cannotUseInitializerListForVectorOfUnknownSize, "cannot
DIAGNOSTIC(30503, Error, cannotUseInitializerListForMatrixOfUnknownSize, "cannot use initializer list for matrix of statically unknown size '$0' rows")
DIAGNOSTIC(30504, Error, cannotUseInitializerListForType, "cannot use initializer list for type '$0'")
-// 306xx: variables
-DIAGNOSTIC(30600, Error, varWithoutTypeMustHaveInitializer, "a variable declaration without an initial-value expression must be given an explicit type")
-
-DIAGNOSTIC(30610, Error, ambiguousDefaultInitializerForType, "more than one default initializer was found for type '$0'")
+// 3062x: variables
+DIAGNOSTIC(30620, Error, varWithoutTypeMustHaveInitializer, "a variable declaration without an initial-value expression must be given an explicit type")
+DIAGNOSTIC(30621, Error, externValueCannotHaveInitializer, "an 'extern' variable declaration cannot have a value.")
+DIAGNOSTIC(30622, Error, ambiguousDefaultInitializerForType, "more than one default initializer was found for type '$0'")
// 307xx: parameters
DIAGNOSTIC(30700, Error, outputParameterCannotHaveDefaultValue, "an 'out' or 'inout' parameter cannot have a default-value expression")
diff --git a/source/slang/slang-mangle.cpp b/source/slang/slang-mangle.cpp
index 3f701f385..9431533ac 100644
--- a/source/slang/slang-mangle.cpp
+++ b/source/slang/slang-mangle.cpp
@@ -132,7 +132,8 @@ namespace Slang
void emitQualifiedName(
ManglingContext* context,
- DeclRef<Decl> declRef);
+ DeclRef<Decl> declRef,
+ bool includeModuleName);
void emitSimpleIntVal(
ManglingContext* context,
@@ -211,7 +212,7 @@ namespace Slang
}
else if( auto declRefType = dynamicCast<DeclRefType>(type) )
{
- emitQualifiedName(context, declRefType->getDeclRef());
+ emitQualifiedName(context, declRefType->getDeclRef(), true);
}
else if (auto arrType = dynamicCast<ArrayExpressionType>(type))
{
@@ -222,7 +223,7 @@ namespace Slang
else if( auto thisType = dynamicCast<ThisType>(type) )
{
emitRaw(context, "t");
- emitQualifiedName(context, thisType->getInterfaceDeclRef());
+ emitQualifiedName(context, thisType->getInterfaceDeclRef(), true);
}
else if (const auto errorType = dynamicCast<ErrorType>(type))
{
@@ -356,8 +357,26 @@ namespace Slang
void emitQualifiedName(
ManglingContext* context,
- DeclRef<Decl> declRef)
+ DeclRef<Decl> declRef,
+ bool includeModuleName)
{
+ if (!includeModuleName)
+ {
+ if (as<ModuleDecl>(declRef))
+ return;
+ }
+ else
+ {
+ for (auto modifier : declRef.getDecl()->modifiers)
+ {
+ if (as<ExternModifier>(modifier) || as<HLSLExportModifier>(modifier))
+ {
+ includeModuleName = false;
+ break;
+ }
+ }
+ }
+
auto parentDeclRef = declRef.getParent();
if (as<FileDecl>(parentDeclRef))
parentDeclRef = parentDeclRef.getParent();
@@ -365,7 +384,7 @@ namespace Slang
auto parentGenericDeclRef = parentDeclRef.as<GenericDecl>();
if( parentDeclRef )
{
- emitQualifiedName(context, parentDeclRef);
+ emitQualifiedName(context, parentDeclRef, includeModuleName);
}
// A generic declaration is kind of a pseudo-declaration
@@ -490,7 +509,7 @@ namespace Slang
for (auto type : constraint.value)
{
emitRaw(context, "C");
- emitQualifiedName(context, makeDeclRef(constraint.key));
+ emitQualifiedName(context, makeDeclRef(constraint.key), true);
emitType(context, type);
}
}
@@ -579,7 +598,7 @@ namespace Slang
auto innerDecl = getInner(genericDecl);
- emitQualifiedName(context, makeDeclRef(innerDecl));
+ emitQualifiedName(context, makeDeclRef(innerDecl), true);
return;
}
else if (as<ForwardDerivativeRequirementDecl>(decl))
@@ -592,7 +611,8 @@ namespace Slang
}
// Now we encode the qualified name of the decl.
- emitQualifiedName(context, declRef);
+
+ emitQualifiedName(context, declRef, true);
}
static String getMangledName(ASTBuilder* astBuilder, DeclRef<Decl> const& declRef)
@@ -625,8 +645,8 @@ namespace Slang
SLANG_AST_BUILDER_RAII(astBuilder);
ManglingContext context(astBuilder);
emitRaw(&context, "_SW");
- emitQualifiedName(&context, sub);
- emitQualifiedName(&context, sup);
+ emitQualifiedName(&context, sub, true);
+ emitQualifiedName(&context, sup, true);
return context.sb.produceString();
}
@@ -643,7 +663,7 @@ namespace Slang
//
ManglingContext context(astBuilder);
emitRaw(&context, "_SW");
- emitQualifiedName(&context, sub);
+ emitQualifiedName(&context, sub, true);
emitType(&context, sup);
return context.sb.produceString();
}
diff --git a/tools/gfx-unit-test/gfx-test-util.h b/tools/gfx-unit-test/gfx-test-util.h
index 22b9b2fd3..501deeae0 100644
--- a/tools/gfx-unit-test/gfx-test-util.h
+++ b/tools/gfx-unit-test/gfx-test-util.h
@@ -8,7 +8,7 @@
namespace gfx_test
{
/// Helper function for print out diagnostic messages output by Slang compiler.
- void diagnoseIfNeeded(ISlangWriter* diagnosticWriter, slang::IBlob* diagnosticsBlob);
+ void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob);
/// Loads a compute shader module and produces a `gfx::IShaderProgram`.
Slang::Result loadComputeProgram(
diff --git a/tools/gfx-unit-test/link-time-constant.cpp b/tools/gfx-unit-test/link-time-constant.cpp
new file mode 100644
index 000000000..62cb294c1
--- /dev/null
+++ b/tools/gfx-unit-test/link-time-constant.cpp
@@ -0,0 +1,156 @@
+#include "tools/unit-test/slang-unit-test.h"
+
+#include "slang-gfx.h"
+#include "gfx-test-util.h"
+#include "tools/gfx-util/shader-cursor.h"
+#include "source/core/slang-basic.h"
+#include "source/core/slang-blob.h"
+
+using namespace gfx;
+
+namespace gfx_test
+{
+ static Slang::Result loadProgram(
+ gfx::IDevice* device,
+ Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram,
+ const char* shaderModuleName,
+ const char* entryPointName,
+ slang::ProgramLayout*& slangReflection,
+ const char* additionalModuleSource)
+ {
+ Slang::ComPtr<slang::ISession> slangSession;
+ SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef()));
+ Slang::ComPtr<slang::IBlob> diagnosticsBlob;
+ slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef());
+ diagnoseIfNeeded(diagnosticsBlob);
+ if (!module)
+ return SLANG_FAIL;
+
+ auto additionalModuleBlob = Slang::UnownedRawBlob::create(additionalModuleSource, strlen(additionalModuleSource));
+ slang::IModule* additionalModule = slangSession->loadModuleFromSource("linkedConstants", "path",
+ additionalModuleBlob);
+
+ ComPtr<slang::IEntryPoint> computeEntryPoint;
+ SLANG_RETURN_ON_FAIL(
+ module->findEntryPointByName(entryPointName, computeEntryPoint.writeRef()));
+
+ Slang::List<slang::IComponentType*> componentTypes;
+ componentTypes.add(module);
+ componentTypes.add(computeEntryPoint);
+ componentTypes.add(additionalModule);
+
+ Slang::ComPtr<slang::IComponentType> composedProgram;
+ SlangResult result = slangSession->createCompositeComponentType(
+ componentTypes.getBuffer(),
+ componentTypes.getCount(),
+ composedProgram.writeRef(),
+ diagnosticsBlob.writeRef());
+ diagnoseIfNeeded(diagnosticsBlob);
+ SLANG_RETURN_ON_FAIL(result);
+
+ ComPtr<slang::IComponentType> linkedProgram;
+ result = composedProgram->link(linkedProgram.writeRef(), diagnosticsBlob.writeRef());
+ diagnoseIfNeeded(diagnosticsBlob);
+ SLANG_RETURN_ON_FAIL(result);
+
+ composedProgram = linkedProgram;
+ slangReflection = composedProgram->getLayout();
+
+ gfx::IShaderProgram::Desc programDesc = {};
+ programDesc.slangGlobalScope = composedProgram.get();
+
+ auto shaderProgram = device->createProgram(programDesc);
+
+ outShaderProgram = shaderProgram;
+ return SLANG_OK;
+ }
+
+ void linkTimeConstantTestImpl(IDevice* device, UnitTestContext* context)
+ {
+ Slang::ComPtr<ITransientResourceHeap> transientHeap;
+ ITransientResourceHeap::Desc transientHeapDesc = {};
+ transientHeapDesc.constantBufferSize = 4096;
+ GFX_CHECK_CALL_ABORT(
+ device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef()));
+
+ ComPtr<IShaderProgram> shaderProgram;
+ slang::ProgramLayout* slangReflection;
+ GFX_CHECK_CALL_ABORT(loadProgram(device, shaderProgram, "link-time-constant", "computeMain", slangReflection,
+ R"(
+ export static const bool turnOnFeature = true;
+ export static const float constValue = 2.0;
+ )"));
+
+ ComputePipelineStateDesc pipelineDesc = {};
+ pipelineDesc.program = shaderProgram.get();
+ ComPtr<gfx::IPipelineState> pipelineState;
+ GFX_CHECK_CALL_ABORT(
+ device->createComputePipelineState(pipelineDesc, pipelineState.writeRef()));
+
+ const int numberCount = 4;
+ float initialData[] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ IBufferResource::Desc bufferDesc = {};
+ bufferDesc.sizeInBytes = numberCount * sizeof(float);
+ bufferDesc.format = gfx::Format::Unknown;
+ bufferDesc.elementSize = sizeof(float);
+ bufferDesc.allowedStates = ResourceStateSet(
+ ResourceState::ShaderResource,
+ ResourceState::UnorderedAccess,
+ ResourceState::CopyDestination,
+ ResourceState::CopySource);
+ bufferDesc.defaultState = ResourceState::UnorderedAccess;
+ bufferDesc.memoryType = MemoryType::DeviceLocal;
+
+ ComPtr<IBufferResource> numbersBuffer;
+ GFX_CHECK_CALL_ABORT(device->createBufferResource(
+ bufferDesc,
+ (void*)initialData,
+ numbersBuffer.writeRef()));
+
+ ComPtr<IResourceView> bufferView;
+ IResourceView::Desc viewDesc = {};
+ viewDesc.type = IResourceView::Type::UnorderedAccess;
+ viewDesc.format = Format::Unknown;
+ GFX_CHECK_CALL_ABORT(
+ device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef()));
+
+ // We have done all the set up work, now it is time to start recording a command buffer for
+ // GPU execution.
+ {
+ ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics };
+ auto queue = device->createCommandQueue(queueDesc);
+
+ auto commandBuffer = transientHeap->createCommandBuffer();
+ auto encoder = commandBuffer->encodeComputeCommands();
+
+ auto rootObject = encoder->bindPipeline(pipelineState);
+
+ ShaderCursor entryPointCursor(
+ rootObject->getEntryPoint(0)); // get a cursor the the first entry-point.
+ // Bind buffer view to the entry point.
+ entryPointCursor.getPath("buffer").setResource(bufferView);
+
+ encoder->dispatchCompute(1, 1, 1);
+ encoder->endEncoding();
+ commandBuffer->close();
+ queue->executeCommandBuffer(commandBuffer);
+ queue->waitOnHost();
+ }
+
+ compareComputeResult(
+ device,
+ numbersBuffer,
+ Slang::makeArray<float>(2.0));
+ }
+
+ SLANG_UNIT_TEST(linkTimeConstantD3D12)
+ {
+ runTestImpl(linkTimeConstantTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12);
+ }
+
+ SLANG_UNIT_TEST(linkTimeConstantVulkan)
+ {
+ runTestImpl(linkTimeConstantTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan);
+ }
+
+}
diff --git a/tools/gfx-unit-test/link-time-constant.slang b/tools/gfx-unit-test/link-time-constant.slang
new file mode 100644
index 000000000..385932dd4
--- /dev/null
+++ b/tools/gfx-unit-test/link-time-constant.slang
@@ -0,0 +1,20 @@
+extern static const bool turnOnFeature;
+extern static const float constValue;
+
+// Main entry-point. Write some value into buffer depending on link
+// time constant.
+[shader("compute")]
+[numthreads(4, 1, 1)]
+void computeMain(
+ uint3 sv_dispatchThreadID: SV_DispatchThreadID,
+ uniform RWStructuredBuffer<float> buffer)
+{
+ if (turnOnFeature)
+ {
+ buffer[0] = constValue;
+ }
+ else
+ {
+ buffer[0] = -1.0;
+ }
+}