Skip to content

Comments

Eliminate empty struct on metal target#6603

Merged
kaizhangNV merged 3 commits intoshader-slang:masterfrom
kaizhangNV:metal_empty_struct
Mar 26, 2025
Merged

Eliminate empty struct on metal target#6603
kaizhangNV merged 3 commits intoshader-slang:masterfrom
kaizhangNV:metal_empty_struct

Conversation

@kaizhangNV
Copy link
Contributor

@kaizhangNV kaizhangNV commented Mar 14, 2025

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.

@kaizhangNV kaizhangNV requested a review from a team as a code owner March 14, 2025 03:51
@kaizhangNV kaizhangNV added the pr: non-breaking PRs without breaking changes label Mar 14, 2025
@kaizhangNV kaizhangNV force-pushed the metal_empty_struct branch 2 times, most recently from 518efe4 to 6ead786 Compare March 14, 2025 04:09

bool isSimpleType(IRType* type) override
{
if (isMetalTarget(targetProgram->getTargetReq()))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed? Seems very hacky.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because all the following decor check are based on C/C++.
For shader target, we always want to handle the type recursively. Otherwise, it will just return a LegalType::simple(type);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What really should be treated as non-simple type in this case is a type whose leaf type is a struct. However, we shouldn't repeat ourselves to do such check here, because there are already existing logic in legalizeTypeImpl() doing the same thing. We just want to make sure on Metal target, this will execute the logic in that function without early return.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding a check inside the type legalization context, is is possible to create a different TypeLegalizationContext for the metal target, or not run legalizeEmptyTypes if the target is metal in slang-emit.cpp:1286?
I think we should try to keep all target-specific conditions at the top-level in linkAndOptimize so it's clear what's getting run/not run on different backends..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I feel that the logic is almost 100% overlap with legalizeEmptyTypes. So there is no need to create different TypeLegalizationContext.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And, we need to run legalizeEmptyTypes if the target is metal, that is the point of this change actually.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm..
I guess, since the legalization context does accept a TargetProgram, it's fine if target-specific stuff happens there.

@kaizhangNV kaizhangNV mentioned this pull request Mar 18, 2025
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.
Copy link
Collaborator

@saipraveenb25 saipraveenb25 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@kaizhangNV kaizhangNV merged commit b3deec2 into shader-slang:master Mar 26, 2025
16 checks passed
@kaizhangNV kaizhangNV deleted the metal_empty_struct branch March 26, 2025 19:42
@jkwak-work
Copy link
Collaborator

jkwak-work commented Mar 31, 2025

This PR seems to be causing CI failures.
https://github.com/shader-slang/slang/actions/runs/14092090746

The new test fails with the following error,

metal 32023.155: C:\Users\jkwak\AppData\Local\Temp\unkB06B.tmp.metal(30): error :  cannot initialize a member subobject of type 'int' with an lvalue of type 'device int *const constant'
    MyStruct_0 _S1 = { (*param_0).buffer_1, (*param_0).value_1 };
                       ^~~~~~~~~~~~~~~~~~~
1 error generated.

It looks like MyStruct_0 gets only one member variable whose type is int.
So it is an error to assign two values on the construction.

The following shader is the generated metal shader,

#include <metal_stdlib>
#include <metal_math>
#include <metal_texture>
using namespace metal;
void emptyStruct_set_0(int device* buffer_0, int value_0)
{
    *(buffer_0+int(0)) = value_0;
    return;
}

struct MyStruct_0
{
    int value_1;
};

void MyStruct_set_0(MyStruct_0 this_0, int device* this_buffer_0)
{
    emptyStruct_set_0(this_buffer_0, this_0.value_1);
    return;
}

struct MyStruct_1
{
    int device* buffer_1;
    int value_1;
};

[[kernel]] void computeMain(uint3 tid_0 [[thread_position_in_grid]], MyStruct_1 constant* param_0 [[buffer(0)]])
{
    MyStruct_0 _S1 = { (*param_0).buffer_1, (*param_0).value_1 };
    MyStruct_set_0(_S1, (*param_0).buffer_1);
    return;
}

I am wondering how this test passed CI, if it did.

@fairywreath
Copy link
Contributor

fairywreath commented Mar 31, 2025

The incorrect Metal code is caused by having RWStructuredBuffer<int> buffer; inside a struct. I have a temporary fix #6709 for the empty struct test that resolves this. Issue seems to be unrelated to the empty struct elimination, a separate fix to have RWStructuredBuffer inside a struct not emit incorrect metal code is required.

jkwak-work added a commit to jkwak-work/slang that referenced this pull request Mar 31, 2025
jkwak-work added a commit that referenced this pull request Mar 31, 2025
kaizhangNV added a commit to kaizhangNV/slang that referenced this pull request Apr 1, 2025
kaizhangNV added a commit to kaizhangNV/slang that referenced this pull request Apr 2, 2025
kaizhangNV added a commit to kaizhangNV/slang that referenced this pull request Apr 2, 2025
kaizhangNV added a commit to kaizhangNV/slang that referenced this pull request Apr 2, 2025
kaizhangNV added a commit that referenced this pull request Apr 2, 2025
* Reapply "Eliminate empty struct on metal target (#6603)" (#6711)

This reverts commit bc9dc65.

* Remove argument in make_struct call corresponding to void field

This is a follow-up of #6543, where we leave the VoidType field as it in
make_struct call during legalization pass.

So during cleaning_void IR pass, when we remove "VoidType" from struct,
we will have to also clean up the argument corresponding to the
"VoidType" field.
szihs pushed a commit to szihs/slang that referenced this pull request May 7, 2025
* 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
szihs pushed a commit to szihs/slang that referenced this pull request May 7, 2025
szihs pushed a commit to szihs/slang that referenced this pull request May 7, 2025
* Reapply "Eliminate empty struct on metal target (shader-slang#6603)" (shader-slang#6711)

This reverts commit bc9dc65.

* Remove argument in make_struct call corresponding to void field

This is a follow-up of shader-slang#6543, where we leave the VoidType field as it in
make_struct call during legalization pass.

So during cleaning_void IR pass, when we remove "VoidType" from struct,
we will have to also clean up the argument corresponding to the
"VoidType" field.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr: non-breaking PRs without breaking changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Metal: emit empty struct

5 participants