summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/slang/slang-ast-modifier.h1
-rw-r--r--source/slang/slang-emit-c-like.cpp2
-rw-r--r--source/slang/slang-emit-c-like.h4
-rw-r--r--source/slang/slang-emit-hlsl.cpp46
-rw-r--r--source/slang/slang-emit-hlsl.h2
-rw-r--r--source/slang/slang-ir-inst-defs.h1
-rw-r--r--source/slang/slang-ir-insts.h6
-rw-r--r--source/slang/slang-ir-link.cpp29
-rw-r--r--source/slang/slang-ir.cpp38
-rw-r--r--source/slang/slang-lower-to-ir.cpp29
-rw-r--r--source/slang/slang-parser.cpp3
-rw-r--r--tests/library/export-library.slang14
-rw-r--r--tests/library/export-test.slang27
-rw-r--r--tests/library/export-test.slang.expected.txt4
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