summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaizhangNV <149626564+kaizhangNV@users.noreply.github.com>2025-03-26 14:42:30 -0500
committerGitHub <noreply@github.com>2025-03-26 12:42:30 -0700
commitb3deec2001ea34e20e9a6af8ddf5cf3866cafac0 (patch)
tree68052183f6c2d3b610a34027e5911113c1506414
parent05f24d294917a2599d635fe2e53b75cdca26cfdd (diff)
Eliminate empty struct on metal target (#6603)
* Eliminate empty struct on metal target Close 6573. We previously disabled the type legalization for ParameterBlock on Metal, but Metal doesn't allow empty struct in the argument buffer which is mapped from ParameterBlock, so we will need legalizeEmptyTypes on Metal target. * update test * update function name
-rw-r--r--source/slang/slang-emit.cpp9
-rw-r--r--source/slang/slang-ir-legalize-types.cpp10
-rw-r--r--source/slang/slang-legalize-types.cpp6
-rw-r--r--source/slang/slang-legalize-types.h2
-rw-r--r--tests/metal/empty-struct-remove.slang33
5 files changed, 59 insertions, 1 deletions
diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp
index 841f44a80..8d7577b52 100644
--- a/source/slang/slang-emit.cpp
+++ b/source/slang/slang-emit.cpp
@@ -1278,6 +1278,15 @@ Result linkAndOptimizeIR(
//
legalizeResourceTypes(targetProgram, irModule, sink);
+ // We also need to legalize empty types for Metal targets.
+ switch (target)
+ {
+ case CodeGenTarget::Metal:
+ case CodeGenTarget::MetalLib:
+ case CodeGenTarget::MetalLibAssembly:
+ legalizeEmptyTypes(targetProgram, irModule, sink);
+ break;
+ }
// Debugging output of legalization
#if 0
dumpIRIfEnabled(codeGenContext, irModule, "LEGALIZED");
diff --git a/source/slang/slang-ir-legalize-types.cpp b/source/slang/slang-ir-legalize-types.cpp
index 197cd93c5..837193abc 100644
--- a/source/slang/slang-ir-legalize-types.cpp
+++ b/source/slang/slang-ir-legalize-types.cpp
@@ -4123,6 +4123,11 @@ struct IREmptyTypeLegalizationContext : IRTypeLegalizationContext
bool isSimpleType(IRType* type) override
{
+ if (isMetalTarget(targetProgram->getTargetReq()))
+ {
+ return false;
+ }
+
// If type is used as public interface, then treat it as simple.
for (auto decor : type->getDecorations())
{
@@ -4145,6 +4150,11 @@ struct IREmptyTypeLegalizationContext : IRTypeLegalizationContext
{
return LegalType();
}
+
+ virtual bool shouldLegalizeParameterBlockElementType() override
+ {
+ return isMetalTarget(targetProgram->getTargetReq());
+ }
};
// The main entry points that are used when transforming IR code
diff --git a/source/slang/slang-legalize-types.cpp b/source/slang/slang-legalize-types.cpp
index e26475522..cc2c12d42 100644
--- a/source/slang/slang-legalize-types.cpp
+++ b/source/slang/slang-legalize-types.cpp
@@ -1211,11 +1211,15 @@ LegalType legalizeTypeImpl(TypeLegalizationContext* context, IRType* type)
LegalType legalElementType;
if (isMetalTarget(context->targetProgram->getTargetReq()) &&
- as<IRParameterBlockType>(uniformBufferType))
+ as<IRParameterBlockType>(uniformBufferType) &&
+ !context->shouldLegalizeParameterBlockElementType())
{
// On Metal, we do not need to legalize the element type of
// a parameter block because we can translate it directly into
// an argument buffer.
+ //
+ // But we do need empty type legalized for Metal, because Metal doesn't
+ // allow empty struct in argument buffer.
legalElementType = LegalType::simple(originalElementType);
}
else
diff --git a/source/slang/slang-legalize-types.h b/source/slang/slang-legalize-types.h
index ae76cbd39..f1b15877d 100644
--- a/source/slang/slang-legalize-types.h
+++ b/source/slang/slang-legalize-types.h
@@ -659,6 +659,8 @@ struct IRTypeLegalizationContext
IROp op,
LegalType legalElementType,
IRInst* layoutOperand) = 0;
+
+ virtual bool shouldLegalizeParameterBlockElementType() { return false; }
};
// This typedef exists to support pre-existing code from when
diff --git a/tests/metal/empty-struct-remove.slang b/tests/metal/empty-struct-remove.slang
new file mode 100644
index 000000000..2d9ee436b
--- /dev/null
+++ b/tests/metal/empty-struct-remove.slang
@@ -0,0 +1,33 @@
+
+//TEST:SIMPLE(filecheck=LIB):-target metallib -entry computeMain -stage compute -DMETAL
+//TEST:SIMPLE(filecheck=METAL):-target metal -entry computeMain -stage compute -DMETAL
+
+// METAL-NOT: struct emptyStruct
+struct emptyStruct
+{
+ void set(RWStructuredBuffer<int> buffer, int value) {buffer[0] = value;}
+}
+
+
+struct MyStruct
+{
+ RWStructuredBuffer<int> buffer;
+ int value;
+ void set()
+ {
+ e.set(buffer, value);
+ }
+ emptyStruct e;
+}
+
+ParameterBlock<MyStruct> param;
+
+// LIB: @computeMain
+[shader("compute")]
+[numthreads(1, 1, 1)]
+void computeMain(
+ uint tid: SV_DispatchThreadID,
+)
+{
+ param.set();
+}