diff options
| -rw-r--r-- | source/slang/slang-ast-modifier.h | 1 | ||||
| -rw-r--r-- | source/slang/slang-emit-c-like.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-emit-c-like.h | 4 | ||||
| -rw-r--r-- | source/slang/slang-emit-hlsl.cpp | 46 | ||||
| -rw-r--r-- | source/slang/slang-emit-hlsl.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-ir-inst-defs.h | 1 | ||||
| -rw-r--r-- | source/slang/slang-ir-insts.h | 6 | ||||
| -rw-r--r-- | source/slang/slang-ir-link.cpp | 29 | ||||
| -rw-r--r-- | source/slang/slang-ir.cpp | 38 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 29 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 3 | ||||
| -rw-r--r-- | tests/library/export-library.slang | 14 | ||||
| -rw-r--r-- | tests/library/export-test.slang | 27 | ||||
| -rw-r--r-- | tests/library/export-test.slang.expected.txt | 4 |
14 files changed, 150 insertions, 56 deletions
diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h index 6a142454d..8654a2391 100644 --- a/source/slang/slang-ast-modifier.h +++ b/source/slang/slang-ast-modifier.h @@ -20,6 +20,7 @@ class PublicModifier : public Modifier { SLANG_AST_CLASS(PublicModifier)}; class RequireModifier : public Modifier { SLANG_AST_CLASS(RequireModifier)}; class ParamModifier : public Modifier { SLANG_AST_CLASS(ParamModifier)}; class ExternModifier : public Modifier { SLANG_AST_CLASS(ExternModifier)}; +class HLSLExportModifier : public Modifier { SLANG_AST_CLASS(HLSLExportModifier) }; class InputModifier : public Modifier { SLANG_AST_CLASS(InputModifier)}; class TransparentModifier : public Modifier { SLANG_AST_CLASS(TransparentModifier)}; class FromStdLibModifier : public Modifier { SLANG_AST_CLASS(FromStdLibModifier)}; diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 90ccb3e73..06e1e782b 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -2928,7 +2928,7 @@ void CLikeSourceEmitter::emitFunc(IRFunc* func) } } -void CLikeSourceEmitter::emitFuncDecorations(IRFunc* func) +void CLikeSourceEmitter::emitFuncDecorationsImpl(IRFunc* func) { for(auto decoration : func->getDecorations()) { diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h index a74d874a7..25bafecf9 100644 --- a/source/slang/slang-emit-c-like.h +++ b/source/slang/slang-emit-c-like.h @@ -360,7 +360,7 @@ public: bool isTargetIntrinsic(IRFunc* func); void emitFunc(IRFunc* func); - void emitFuncDecorations(IRFunc* func); + void emitFuncDecorations(IRFunc* func) { emitFuncDecorationsImpl(func); } void emitStruct(IRStructType* structType); @@ -469,6 +469,8 @@ public: virtual void emitFuncDecorationImpl(IRDecoration* decoration) { SLANG_UNUSED(decoration); } virtual void emitLivenessImpl(IRInst* inst); + virtual void emitFuncDecorationsImpl(IRFunc* func); + // Only needed for glsl output with $ prefix intrinsics - so perhaps removable in the future virtual void emitTextureOrTextureSamplerTypeImpl(IRTextureTypeBase* type, char const* baseName) { SLANG_UNUSED(type); SLANG_UNUSED(baseName); } // Again necessary for & prefix intrinsics. May be removable in the future diff --git a/source/slang/slang-emit-hlsl.cpp b/source/slang/slang-emit-hlsl.cpp index 650012b9f..945f00499 100644 --- a/source/slang/slang-emit-hlsl.cpp +++ b/source/slang/slang-emit-hlsl.cpp @@ -727,28 +727,40 @@ void HLSLSourceEmitter::emitLoopControlDecorationImpl(IRLoopControlDecoration* d } } -void HLSLSourceEmitter::emitFuncDecorationImpl(IRDecoration* decoration) +static bool _canEmitExport(const Profile& profile) { - switch( decoration->getOp() ) - { - case kIROp_PublicDecoration: + const auto family = profile.getFamily(); + const auto version = profile.getVersion(); + // Is ita late enough version of shader model to output with 'export' + return (family == ProfileFamily::DX && version >= ProfileVersion::DX_6_1); +} + +/* virtual */void HLSLSourceEmitter::emitFuncDecorationsImpl(IRFunc* func) +{ + // Specially handle export, as we don't want to emit it multiple times + if (getTargetReq()->isWholeProgramRequest() && + _canEmitExport(m_effectiveProfile)) { - auto profile = m_effectiveProfile; - - const auto family = profile.getFamily(); - const auto version = profile.getVersion(); - - // If it's whole program and it's for a late enough version of shader model - // output with 'export' - if (getTargetReq()->isWholeProgramRequest() && - family == ProfileFamily::DX && - version >= ProfileVersion::DX_6_1) + for (auto decoration : func->getDecorations()) { - m_writer->emit("export\n"); + const auto op = decoration->getOp(); + if (op == kIROp_PublicDecoration || + op == kIROp_HLSLExportDecoration) + { + m_writer->emit("export\n"); + break; + } } - break; } - + + // Use the default for others + Super::emitFuncDecorationsImpl(func); +} + +void HLSLSourceEmitter::emitFuncDecorationImpl(IRDecoration* decoration) +{ + switch( decoration->getOp() ) + { case kIROp_NoInlineDecoration: m_writer->emit("[noinline]\n"); break; diff --git a/source/slang/slang-emit-hlsl.h b/source/slang/slang-emit-hlsl.h index eeda7c0b7..bbd8ad15e 100644 --- a/source/slang/slang-emit-hlsl.h +++ b/source/slang/slang-emit-hlsl.h @@ -46,7 +46,7 @@ protected: virtual void emitSimpleValueImpl(IRInst* inst) SLANG_OVERRIDE; virtual void emitLoopControlDecorationImpl(IRLoopControlDecoration* decl) SLANG_OVERRIDE; virtual void emitFuncDecorationImpl(IRDecoration* decoration) SLANG_OVERRIDE; - + virtual void emitFuncDecorationsImpl(IRFunc* func) SLANG_OVERRIDE; virtual void handleRequiredCapabilitiesImpl(IRInst* inst) SLANG_OVERRIDE; virtual void emitPreludeDirectivesImpl() SLANG_OVERRIDE; diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index fa977fd89..c09af19fe 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -546,6 +546,7 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0) INST(GloballyCoherentDecoration, globallyCoherent, 0, 0) INST(PreciseDecoration, precise, 0, 0) INST(PublicDecoration, public, 0, 0) + INST(HLSLExportDecoration, hlslExport, 0, 0) INST(PatchConstantFuncDecoration, patchConstantFunc, 1, 0) INST(OutputControlPointsDecoration, outputControlPoints, 1, 0) diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index 96fe350f8..a3b11ea80 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -268,6 +268,7 @@ IR_SIMPLE_DECORATION(EarlyDepthStencilDecoration) IR_SIMPLE_DECORATION(GloballyCoherentDecoration) IR_SIMPLE_DECORATION(PreciseDecoration) IR_SIMPLE_DECORATION(PublicDecoration) +IR_SIMPLE_DECORATION(HLSLExportDecoration) IR_SIMPLE_DECORATION(KeepAliveDecoration) IR_SIMPLE_DECORATION(RequiresNVAPIDecoration) IR_SIMPLE_DECORATION(NoInlineDecoration) @@ -2880,7 +2881,10 @@ public: { addDecoration(value, kIROp_PublicDecoration); } - + void addHLSLExportDecoration(IRInst* value) + { + addDecoration(value, kIROp_HLSLExportDecoration); + } void addNVAPIMagicDecoration(IRInst* value, UnownedStringSlice const& name) { addDecoration(value, kIROp_NVAPIMagicDecoration, getStringValue(name)); diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp index 8c1edc032..80ba0b610 100644 --- a/source/slang/slang-ir-link.cpp +++ b/source/slang/slang-ir-link.cpp @@ -441,6 +441,7 @@ static void cloneExtraDecorations( default: break; + case kIROp_HLSLExportDecoration: case kIROp_BindExistentialSlotsDecoration: case kIROp_LayoutDecoration: case kIROp_PublicDecoration: @@ -1348,6 +1349,20 @@ struct IRSpecializationState } }; +static bool _isPublicOrHLSLExported(IRInst* inst) +{ + for (auto decoration : inst->getDecorations()) + { + const auto op = decoration->getOp(); + if (op == kIROp_PublicDecoration || + op == kIROp_HLSLExportDecoration) + { + return true; + } + } + return false; +} + LinkedIR linkIR( CodeGenContext* codeGenContext) { @@ -1495,14 +1510,14 @@ LinkedIR linkIR( { for (auto inst : irModule->getGlobalInsts()) { - auto hasPublic = inst->findDecoration<IRPublicDecoration>(); - if (!hasPublic) - continue; - - auto cloned = cloneValue(context, inst); - if (!cloned->findDecorationImpl(kIROp_KeepAliveDecoration)) + // Is it `public` or (HLSL) `export` clone + if (_isPublicOrHLSLExported(inst)) { - context->builder->addKeepAliveDecoration(cloned); + auto cloned = cloneValue(context, inst); + if (!cloned->findDecorationImpl(kIROp_KeepAliveDecoration)) + { + context->builder->addKeepAliveDecoration(cloned); + } } } } diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 782f259ee..b3c19d419 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -30,23 +30,27 @@ namespace Slang { switch (op) { - case kIROp_EarlyDepthStencilDecoration: return true; - case kIROp_GloballyCoherentDecoration: return true; - case kIROp_KeepAliveDecoration: return true; - case kIROp_LineAdjInputPrimitiveTypeDecoration: return true; - case kIROp_LineInputPrimitiveTypeDecoration: return true; - case kIROp_NoInlineDecoration: return true; - case kIROp_PointInputPrimitiveTypeDecoration: return true; - case kIROp_PreciseDecoration: return true; - case kIROp_PublicDecoration: return true; - case kIROp_ReadNoneDecoration: return true; - case kIROp_RequiresNVAPIDecoration: return true; - case kIROp_TriangleAdjInputPrimitiveTypeDecoration: return true; - case kIROp_TriangleInputPrimitiveTypeDecoration: return true; - case kIROp_UnsafeForceInlineEarlyDecoration: return true; - case kIROp_VulkanCallablePayloadDecoration: return true; - case kIROp_VulkanHitAttributesDecoration: return true; - case kIROp_VulkanRayPayloadDecoration: return true; + case kIROp_EarlyDepthStencilDecoration: + case kIROp_GloballyCoherentDecoration: + case kIROp_KeepAliveDecoration: + case kIROp_LineAdjInputPrimitiveTypeDecoration: + case kIROp_LineInputPrimitiveTypeDecoration: + case kIROp_NoInlineDecoration: + case kIROp_PointInputPrimitiveTypeDecoration: + case kIROp_PreciseDecoration: + case kIROp_PublicDecoration: + case kIROp_HLSLExportDecoration: + case kIROp_ReadNoneDecoration: + case kIROp_RequiresNVAPIDecoration: + case kIROp_TriangleAdjInputPrimitiveTypeDecoration: + case kIROp_TriangleInputPrimitiveTypeDecoration: + case kIROp_UnsafeForceInlineEarlyDecoration: + case kIROp_VulkanCallablePayloadDecoration: + case kIROp_VulkanHitAttributesDecoration: + case kIROp_VulkanRayPayloadDecoration: + { + return true; + } default: break; } return false; diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 7a99faa58..a185efba9 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -1047,6 +1047,11 @@ static void addLinkageDecoration( builder->addPublicDecoration(inst); builder->addKeepAliveDecoration(inst); } + if (decl->findModifier<HLSLExportModifier>()) + { + builder->addHLSLExportDecoration(inst); + builder->addKeepAliveDecoration(inst); + } if (decl->findModifier<ExternCppModifier>()) { builder->addExternCppDecoration(inst, mangledName); @@ -5408,6 +5413,10 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> bool isPublicType(Type* type) { + // TODO(JS): + // Not clear how should handle HLSLExportModifier here. + // In the HLSL spec 'export' is only applicable to functions. So for now we ignore. + if (auto declRefType = as<DeclRefType>(type)) { if (declRefType->declRef.getDecl()->findModifier<PublicModifier>()) @@ -5595,6 +5604,11 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> irWitnessTable->setOperand(0, irSubType); addLinkageDecoration(context, irWitnessTable, inheritanceDecl, mangledName.getUnownedSlice()); + + // TODO(JS): + // Not clear what to do here around HLSLExportModifier. + // In HLSL it only (currently) applies to functions, so perhaps do nothing is reasonable. + if (parentDecl->findModifier<PublicModifier>()) { subBuilder->addPublicDecoration(irWitnessTable); @@ -6340,7 +6354,11 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> SLANG_UNREACHABLE("associatedtype should have been handled by visitAssocTypeDecl."); } - bool isPublicType = decl->findModifier<PublicModifier>() != nullptr; + // TODO(JS): + // Not clear what to do around HLSLExportModifier. + // The HLSL spec says it only applies to functions, so we ignore for now. + + const bool isPublicType = decl->findModifier<PublicModifier>() != nullptr; // Given a declaration of a type, we need to make sure // to output "witness tables" for any interfaces this @@ -7424,15 +7442,6 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> getBuilder()->addSimpleDecoration<IRNoInlineDecoration>(irFunc); } -#if 0 - // Not needed as added as part of adding linkage decoration. - // Ie in call to addLinkageDecoration - if (decl->findModifier<PublicModifier>()) - { - getBuilder()->addSimpleDecoration<IRPublicDecoration>(irFunc); - } -#endif - if (auto attr = decl->findModifier<InstanceAttribute>()) { IRIntLit* intLit = _getIntLitFromAttribute(getBuilder(), attr); diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index bf0b94120..db532a601 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -6278,7 +6278,7 @@ namespace Slang _makeParseModifier("require", RequireModifier::kReflectClassInfo), _makeParseModifier("param", ParamModifier::kReflectClassInfo), _makeParseModifier("extern", ExternModifier::kReflectClassInfo), - + _makeParseModifier("row_major", HLSLRowMajorLayoutModifier::kReflectClassInfo), _makeParseModifier("column_major", HLSLColumnMajorLayoutModifier::kReflectClassInfo), @@ -6293,6 +6293,7 @@ namespace Slang _makeParseModifier("static", HLSLStaticModifier::kReflectClassInfo), _makeParseModifier("uniform", HLSLUniformModifier::kReflectClassInfo), _makeParseModifier("volatile", HLSLVolatileModifier::kReflectClassInfo), + _makeParseModifier("export", HLSLExportModifier::kReflectClassInfo), // Modifiers for geometry shader input _makeParseModifier("point", HLSLPointModifier::kReflectClassInfo), diff --git a/tests/library/export-library.slang b/tests/library/export-library.slang new file mode 100644 index 000000000..f96b1e143 --- /dev/null +++ b/tests/library/export-library.slang @@ -0,0 +1,14 @@ +//TEST_IGNORE_FILE: + +// export-library.slang + +int doThing(int b) +{ + return b + b + 1; +} + +export int foo(int a) +{ + return a * a + 1 + doThing(a + 2); +} + diff --git a/tests/library/export-test.slang b/tests/library/export-test.slang new file mode 100644 index 000000000..a85396126 --- /dev/null +++ b/tests/library/export-test.slang @@ -0,0 +1,27 @@ +// export-test.slang + +// A test to try out the basics of using libraries that can be linked (by downstream tools), via the HLSL `export` keyword. +// (This is in contrast to Slang modules and Slangs own linkage mechanisms) + +// This didn't work for lib_6_2 when compiling via DXC (!). Even though it's stated elsewhere the feature is available from 6.1 + +//TEST:COMPILE: tests/library/export-library.slang -profile lib_6_3 -target dxil -o tests/library/export-library.dxil +//TEST:COMPILE: tests/library/export-test.slang -entry computeMain -profile cs_6_3 -target dxil -r tests/library/export-library.dxil -o tests/library/export-test.dxil + +// Test the produced kernel. + +//TEST:COMPARE_COMPUTE_EX:-slang -compute -profile cs_6_3 -dx12 -use-dxil -shaderobj -Xslang... -r tests/library/export-library.dxil -X. + +extern int foo(int a); + +//TEST_INPUT:ubuffer(data=[0 0 0 0 ], stride=4):out,name outputBuffer +RWStructuredBuffer<int> outputBuffer; + +[shader("compute")] +[numthreads(4, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + int index = (int)dispatchThreadID.x; + + outputBuffer[index] = foo(index); +} diff --git a/tests/library/export-test.slang.expected.txt b/tests/library/export-test.slang.expected.txt new file mode 100644 index 000000000..c0e0beb96 --- /dev/null +++ b/tests/library/export-test.slang.expected.txt @@ -0,0 +1,4 @@ +6 +9 +E +15 |
