diff options
| -rw-r--r-- | docs/user-guide/a3-02-reference-capability-atoms.md | 3 | ||||
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 18 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 10 | ||||
| -rw-r--r-- | source/slang/slang-parameter-binding.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-type-layout.cpp | 12 | ||||
| -rw-r--r-- | source/slang/slang-type-layout.h | 10 | ||||
| -rw-r--r-- | tests/diagnostics/incomplete-type.slang | 11 | ||||
| -rw-r--r-- | tools/slang-test/test-reporter.cpp | 5 | ||||
| -rw-r--r-- | tools/slang-unit-test/unit-test-link-time-type-reflection.cpp | 228 |
9 files changed, 253 insertions, 46 deletions
diff --git a/docs/user-guide/a3-02-reference-capability-atoms.md b/docs/user-guide/a3-02-reference-capability-atoms.md index 015104310..7f759ca24 100644 --- a/docs/user-guide/a3-02-reference-capability-atoms.md +++ b/docs/user-guide/a3-02-reference-capability-atoms.md @@ -984,6 +984,9 @@ Compound Capabilities `cpp_cuda_hlsl_spirv` > CPP, CUDA, HLSL, and SPIRV code-gen targets +`cpp_cuda_metal_spirv` +> CPP, CUDA, Metal, and SPIRV code-gen targets + `cpp_cuda_spirv` > CPP, CUDA and SPIRV code-gen targets diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 4711eaddd..4362f0926 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -2922,13 +2922,6 @@ void SemanticsDeclBodyVisitor::checkVarDeclCommon(VarDeclBase* varDecl) if (auto elementType = getConstantBufferElementType(varDecl->getType())) { - if (doesTypeHaveTag(elementType, TypeTag::Incomplete)) - { - 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 @@ -2947,17 +2940,6 @@ void SemanticsDeclBodyVisitor::checkVarDeclCommon(VarDeclBase* varDecl) } } } - else if (varDecl->findModifier<HLSLUniformModifier>()) - { - auto varType = varDecl->getType(); - if (doesTypeHaveTag(varType, TypeTag::Incomplete)) - { - getSink()->diagnose( - varDecl->type.exp->loc, - Diagnostics::incompleteTypeCannotBeUsedInUniformParameter, - varType); - } - } maybeRegisterDifferentiableType(getASTBuilder(), varDecl->getType()); } diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 2febd317e..64b1423ac 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -1455,16 +1455,6 @@ DIAGNOSTIC( "modifier '$0' is redundant or conflicting with existing modifier '$1'") DIAGNOSTIC(31203, Error, cannotExportIncompleteType, "cannot export incomplete type '$0'") DIAGNOSTIC( - 31204, - Error, - incompleteTypeCannotBeUsedInBuffer, - "incomplete type '$0' cannot be used in a buffer") -DIAGNOSTIC( - 31205, - Error, - incompleteTypeCannotBeUsedInUniformParameter, - "incomplete type '$0' cannot be used in a uniform parameter") -DIAGNOSTIC( 31206, Error, memoryQualifierNotAllowedOnANonImageTypeParameter, diff --git a/source/slang/slang-parameter-binding.cpp b/source/slang/slang-parameter-binding.cpp index 4b91056fc..b79f96022 100644 --- a/source/slang/slang-parameter-binding.cpp +++ b/source/slang/slang-parameter-binding.cpp @@ -2420,7 +2420,7 @@ static RefPtr<TypeLayout> processEntryPointVaryingParameter( if (auto structDeclRef = declRef.as<StructDecl>()) { RefPtr<StructTypeLayout> structLayout = new StructTypeLayout(); - structLayout->type = type; + structLayout->type = declRefType; // We will recursively walk the fields of a `struct` type // to compute layouts for those fields. diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp index efd41bd86..fb40382c5 100644 --- a/source/slang/slang-type-layout.cpp +++ b/source/slang/slang-type-layout.cpp @@ -4918,7 +4918,8 @@ static TypeLayoutResult _createTypeLayout(TypeLayoutContext& context, Type* type else if (auto vecType = as<VectorExpressionType>(type)) { auto elementType = vecType->getElementType(); - size_t elementCount = (size_t)getIntVal(vecType->getElementCount()); + size_t elementCount = + (size_t)getIntVal(context.tryResolveLinkTimeVal(vecType->getElementCount())); auto element = _createTypeLayout(context, elementType); @@ -4944,8 +4945,9 @@ static TypeLayoutResult _createTypeLayout(TypeLayoutContext& context, Type* type } else if (auto matType = as<MatrixExpressionType>(type)) { - size_t rowCount = (size_t)getIntVal(matType->getRowCount()); - size_t colCount = (size_t)getIntVal(matType->getColumnCount()); + size_t rowCount = (size_t)getIntVal(context.tryResolveLinkTimeVal(matType->getRowCount())); + size_t colCount = + (size_t)getIntVal(context.tryResolveLinkTimeVal(matType->getColumnCount())); auto elementType = matType->getElementType(); auto elementResult = _createTypeLayout(context, elementType); @@ -5031,7 +5033,7 @@ static TypeLayoutResult _createTypeLayout(TypeLayoutContext& context, Type* type context, arrayType, arrayType->getElementType(), - arrayType->getElementCount()); + context.tryResolveLinkTimeVal(arrayType->getElementCount())); } else if (auto atomicType = as<AtomicType>(type)) { @@ -5181,7 +5183,7 @@ static TypeLayoutResult _createTypeLayout(TypeLayoutContext& context, Type* type StructTypeLayoutBuilder typeLayoutBuilder; StructTypeLayoutBuilder pendingDataTypeLayoutBuilder; - typeLayoutBuilder.beginLayout(type, rules); + typeLayoutBuilder.beginLayout(declRefType, rules); auto typeLayout = typeLayoutBuilder.getTypeLayout(); _addLayout(context, type, typeLayout); diff --git a/source/slang/slang-type-layout.h b/source/slang/slang-type-layout.h index bcb842013..84840c043 100644 --- a/source/slang/slang-type-layout.h +++ b/source/slang/slang-type-layout.h @@ -1231,6 +1231,16 @@ struct TypeLayoutContext } return result; } + + IntVal* tryResolveLinkTimeVal(IntVal* inVal) const + { + if (!programLayout) + return inVal; + auto constIntVal = programLayout->getProgram()->tryFoldIntVal(inVal); + if (constIntVal) + return constIntVal; + return inVal; + } }; // diff --git a/tests/diagnostics/incomplete-type.slang b/tests/diagnostics/incomplete-type.slang deleted file mode 100644 index 873673045..000000000 --- a/tests/diagnostics/incomplete-type.slang +++ /dev/null @@ -1,11 +0,0 @@ -//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): - -extern struct ExtType; - -struct MyType -{ - ExtType arr[2]; -} - -// CHECK: ([[#@LINE+1]]): error 31204 -ConstantBuffer<MyType> buffer; diff --git a/tools/slang-test/test-reporter.cpp b/tools/slang-test/test-reporter.cpp index 3aba10566..00f570b6c 100644 --- a/tools/slang-test/test-reporter.cpp +++ b/tools/slang-test/test-reporter.cpp @@ -610,9 +610,9 @@ void TestReporter::message(TestMessageType type, const String& message) if (canWriteStdError()) { + fprintf(stderr, "[%s] ", m_currentInfo.name.getBuffer()); if (type == TestMessageType::RunError || type == TestMessageType::TestFailure) { - fprintf(stderr, "error: "); fputs(message.getBuffer(), stderr); fprintf(stderr, "\n"); } @@ -627,6 +627,9 @@ void TestReporter::message(TestMessageType type, const String& message) { m_currentMessage << "\n"; } + + if (m_currentInfo.name.getLength()) + m_currentMessage << "[" << m_currentInfo.name << "] "; m_currentMessage.append(message); } diff --git a/tools/slang-unit-test/unit-test-link-time-type-reflection.cpp b/tools/slang-unit-test/unit-test-link-time-type-reflection.cpp new file mode 100644 index 000000000..c42fd2f16 --- /dev/null +++ b/tools/slang-unit-test/unit-test-link-time-type-reflection.cpp @@ -0,0 +1,228 @@ +// unit-test-translation-unit-import.cpp + +#include "../../source/core/slang-io.h" +#include "../../source/core/slang-process.h" +#include "slang-com-ptr.h" +#include "slang.h" +#include "unit-test/slang-unit-test.h" + +#include <stdio.h> +#include <stdlib.h> + +using namespace Slang; + +static String getTypeFullName(slang::TypeReflection* type) +{ + ComPtr<ISlangBlob> blob; + type->getFullName(blob.writeRef()); + return String((const char*)blob->getBufferPointer()); +} + +// Test that the reflection API provides correct info about modules with link-time types. + +SLANG_UNIT_TEST(linkTimeTypeReflection) +{ + // Source for a module that contains can be specialized with a link-time type. + const char* userSourceBody = R"( + interface IMaterial { float4 load(); } + extern struct Material : IMaterial; + ConstantBuffer<Material> gMaterial; + + RWTexture2D tex; + + extern static const int count; + uniform uint4 buffers[count]; + + [numthreads(1,1,1)] + [shader("compute")] + void computeMain() { + tex[uint2(0, 0)] = gMaterial.load(); + } + )"; + + String moduleName = "linkTimeTypeReflection_Compute"; + + ComPtr<slang::IGlobalSession> globalSession; + SLANG_CHECK(slang_createGlobalSession(SLANG_API_VERSION, globalSession.writeRef()) == SLANG_OK); + slang::TargetDesc targetDesc = {}; + targetDesc.format = SLANG_SPIRV_ASM; + targetDesc.profile = globalSession->findProfile("spirv_1_5"); + slang::SessionDesc sessionDesc = {}; + sessionDesc.targetCount = 1; + sessionDesc.targets = &targetDesc; + ComPtr<slang::ISession> session; + SLANG_CHECK(globalSession->createSession(sessionDesc, session.writeRef()) == SLANG_OK); + + ComPtr<slang::IBlob> diagnosticBlob; + auto module = session->loadModuleFromSourceString( + moduleName.getBuffer(), + (moduleName + ".slang").getBuffer(), + userSourceBody, + diagnosticBlob.writeRef()); + SLANG_CHECK_ABORT(module != nullptr); + + // Source for a module that defines the link-time type. + String configModuleSource = "import " + moduleName + ";\n" + R"( + export struct Material : IMaterial = MyMaterial; + export static const int count = 11; + + struct MyMaterial : IMaterial { + int data; + Texture2D diffuse; + float4 load() { return diffuse.Load(uint3(0,0,0)); } + } + )"; + auto configModule = session->loadModuleFromSourceString( + "config", + "config.slang", + configModuleSource.getBuffer(), + diagnosticBlob.writeRef()); + SLANG_CHECK_ABORT(configModule != nullptr); + + slang::IComponentType* components[] = {module, configModule}; + + ComPtr<slang::IComponentType> compositeProgram; + session->createCompositeComponentType( + components, + 2, + compositeProgram.writeRef(), + diagnosticBlob.writeRef()); + SLANG_CHECK_ABORT(compositeProgram != nullptr); + + ComPtr<slang::IComponentType> linkedProgram; + compositeProgram->link(linkedProgram.writeRef(), diagnosticBlob.writeRef()); + SLANG_CHECK_ABORT(linkedProgram != nullptr); + + auto programLayout = linkedProgram->getLayout(); + auto var0 = programLayout->getParameterByIndex(0); + + // `gMaterial`'s binding starts at 1, because there is an implicit global uniform buffer. + SLANG_CHECK(var0->getOffset(slang::ParameterCategory::DescriptorTableSlot) == 1); + SLANG_CHECK(var0->getTypeLayout()->getSize(slang::ParameterCategory::DescriptorTableSlot) == 2); + + auto elementLayout = var0->getTypeLayout()->getElementTypeLayout(); + SLANG_CHECK_ABORT(elementLayout != nullptr); + SLANG_CHECK(elementLayout->getSize() == 16); + + auto var1 = programLayout->getParameterByIndex(1); + SLANG_CHECK(var1->getOffset(slang::ParameterCategory::DescriptorTableSlot) == 3); + + auto var2 = programLayout->getParameterByIndex(2); + SLANG_CHECK(var2->getTypeLayout()->getSize() == 11 * 16); + + ComPtr<slang::IBlob> codeBlob; + linkedProgram->getTargetCode(0, codeBlob.writeRef(), diagnosticBlob.writeRef()); + + SLANG_CHECK_ABORT(codeBlob.get()); + + auto spirvStr = UnownedStringSlice((const char*)codeBlob->getBufferPointer()); + + SLANG_CHECK(spirvStr.indexOf(toSlice("OpDecorate %tex Binding 3")) != -1); +} + + +// Test that the reflection API provides correct info about modules using link-time constants in a +// `Conditional` field. + +SLANG_UNIT_TEST(linkTimeConditionalReflection) +{ + // Source for a module that contains can be specialized with a link-time constant. + const char* userSourceBody = R"( + module LinkTimeConditional; + + extern static const bool hasNormal; + extern static const bool hasColor; + + struct VertexOut + { + float4 pos : SV_Position; + float someData; + Conditional<float3, hasNormal> normal; + Conditional<float3, hasColor> color; + } + + [shader("vertex")] + VertexOut vertexMain() + { + VertexOut v; + v.pos = float4(0,0,0,1); + v.someData = 2.0f; + v.normal.set(float3(1,0,0)); + v.color.set(float3(1,1,1)); + return v; + } + )"; + + String moduleName = "LinkTimeConditional"; + + ComPtr<slang::IGlobalSession> globalSession; + SLANG_CHECK(slang_createGlobalSession(SLANG_API_VERSION, globalSession.writeRef()) == SLANG_OK); + slang::TargetDesc targetDesc = {}; + targetDesc.format = SLANG_SPIRV_ASM; + targetDesc.profile = globalSession->findProfile("spirv_1_5"); + slang::SessionDesc sessionDesc = {}; + sessionDesc.targetCount = 1; + sessionDesc.targets = &targetDesc; + ComPtr<slang::ISession> session; + SLANG_CHECK(globalSession->createSession(sessionDesc, session.writeRef()) == SLANG_OK); + + ComPtr<slang::IBlob> diagnosticBlob; + auto module = session->loadModuleFromSourceString( + moduleName.getBuffer(), + (moduleName + ".slang").getBuffer(), + userSourceBody, + diagnosticBlob.writeRef()); + SLANG_CHECK_ABORT(module != nullptr); + + // Source for a module that defines the link-time constants. + String configModuleSource = R"( + export static const bool hasNormal = false; + export static const bool hasColor = true; + )"; + auto configModule = session->loadModuleFromSourceString( + "config", + "config.slang", + configModuleSource.getBuffer(), + diagnosticBlob.writeRef()); + SLANG_CHECK_ABORT(configModule != nullptr); + + ComPtr<slang::IEntryPoint> entryPoint; + module->getDefinedEntryPoint(0, entryPoint.writeRef()); + + slang::IComponentType* components[] = {module, configModule, entryPoint}; + + ComPtr<slang::IComponentType> compositeProgram; + session->createCompositeComponentType( + components, + 3, + compositeProgram.writeRef(), + diagnosticBlob.writeRef()); + SLANG_CHECK_ABORT(compositeProgram != nullptr); + + ComPtr<slang::IComponentType> linkedProgram; + compositeProgram->link(linkedProgram.writeRef(), diagnosticBlob.writeRef()); + SLANG_CHECK_ABORT(linkedProgram != nullptr); + + auto programLayout = linkedProgram->getLayout(); + + auto entryPointLayout = programLayout->getEntryPointByIndex(0); + + auto resultLayout = entryPointLayout->getResultVarLayout(); + SLANG_CHECK_ABORT(resultLayout != nullptr); + + // Number of varying output is 2, because `pos` is a system value that doesn't count towards + // varying output. + SLANG_CHECK( + resultLayout->getTypeLayout()->getSize(slang::ParameterCategory::VaryingOutput) == 2); + + ComPtr<slang::IBlob> codeBlob; + linkedProgram->getTargetCode(0, codeBlob.writeRef(), diagnosticBlob.writeRef()); + + SLANG_CHECK_ABORT(codeBlob.get()); + + auto spirvStr = UnownedStringSlice((const char*)codeBlob->getBufferPointer()); + + // Test that the resulting spirv defines output at location 1, but not at location 2. + SLANG_CHECK(spirvStr.indexOf(toSlice("Location 1")) != -1); + SLANG_CHECK(spirvStr.indexOf(toSlice("Location 2")) == -1); +} |
