Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assigning to kernel argument leads to no error but wrong behavior #5619

Closed
yuanming-hu opened this issue Aug 3, 2022 · 9 comments · Fixed by #5990
Closed

Assigning to kernel argument leads to no error but wrong behavior #5619

yuanming-hu opened this issue Aug 3, 2022 · 9 comments · Fixed by #5990
Assignees
Labels
bug We've confirmed that this is an BUG

Comments

@yuanming-hu
Copy link
Member

Describe the bug

The code below

import taichi as ti

ti.init()

@ti.kernel
def test(a: ti.i32):
    if True:
        a = 1
    print(a)

test(0)

Should either emits an error (kernel argument cannot be assigned), or print 1. But it prints 0:

[Taichi] version 1.0.4, llvm 10.0.0, commit 2827db2c, linux, python 3.8.10
[Taichi] Starting on arch=x64
0
@yuanming-hu yuanming-hu added potential bug Something that looks like a bug but not yet confirmed bug We've confirmed that this is an BUG and removed potential bug Something that looks like a bug but not yet confirmed labels Aug 3, 2022
@taichi-gardener taichi-gardener moved this to Untriaged in Taichi Lang Aug 3, 2022
@bobcao3
Copy link
Collaborator

bobcao3 commented Aug 4, 2022

I'd advocate for non-mutable function parameters unless it's a pointer/template type, and should make this an error. (ndarrays and fields parameters can be considered as a reference semantically)

@yuanming-hu
Copy link
Member Author

yuanming-hu commented Aug 5, 2022

I'd advocate for non-mutable function parameters unless it's a pointer/template type, and should make this an error. (ndarrays and fields parameters can be considered as a reference semantically)

Agreed. Let me make a decision here: kernel arguments (scalars/vectors/matrices) should be non-mutable.

@jim19930609 jim19930609 moved this from Untriaged to Todo in Taichi Lang Aug 5, 2022
@lin-hitonami
Copy link
Contributor

lin-hitonami commented Aug 5, 2022

I once made it immutable in #3105 but this broke some internal code because we allowed them to be mutable in the past, and the PR was reverted very soon. If we do make this change this time, we may need to notify the users in the release note.

@yuanming-hu
Copy link
Member Author

I once made it immutable in #3105 but this broke some internal code because we allowed them to be mutable in the past, and the PR was reverted very soon. If we do make this change this time, we may need to notify the users in the release note.

OK... Thanks for the info! Sounds like we need a deeper discussion on this. If we take the mutable solution and make it watertight, do we need much more work? For example, allowing atomic adds to the argument sounds like a lot of work (you may need a pointer to the argument list?):

@ti.kernel
def foo(a: ti.i32):
    for i in range(10):
        a += i
    print(a)

If the amount of work to make the arguments mutable is huge, we'd rather make it immutable.

@bobcao3
Copy link
Collaborator

bobcao3 commented Aug 6, 2022

If it's internal code we are breaking we should fix them ourselves. I'm not exactly sure how this is done? In the IR we have ArgLoad but I don't think it works the same way as allocas. I think we should just make it a compiler warning at first and keep it what it is in the codegen, and then make it an error some versions later

@lin-hitonami
Copy link
Contributor

I once made it immutable in #3105 but this broke some internal code because we allowed them to be mutable in the past, and the PR was reverted very soon. If we do make this change this time, we may need to notify the users in the release note.

OK... Thanks for the info! Sounds like we need a deeper discussion on this. If we take the mutable solution and make it watertight, do we need much more work? For example, allowing atomic adds to the argument sounds like a lot of work (you may need a pointer to the argument list?):

@ti.kernel
def foo(a: ti.i32):
    for i in range(10):
        a += i
    print(a)

If the amount of work to make the arguments mutable is huge, we'd rather make it immutable.

The solution turns out to be pretty simple: we can assign the argument to a new variable.

@yuanming-hu
Copy link
Member Author

yuanming-hu commented Aug 8, 2022

The solution turns out to be pretty simple: we can assign the argument to a new variable.

Yeah, that could be a solution. But I'm afraid that may lead to some confusion: if one thread modifies that variable, is that visible to other threads? Users will assume the kernel arguments are shared among threads (since it's kernel-level) instead of being thread-local. What about serial offloaded tasks? E.g.,

@ti.kernel
def foo(a: ti.i32):
    for i in range(10):
        a = i
    print(a) # What should be the result here?

The other thing I worry about is register usage on GPUs. We may need an extra optimization pass to eliminate these introduced temporary variables.

@lin-hitonami
Copy link
Contributor

Yeah, that could be a solution. But I'm afraid that may lead to some confusion: if one thread modifies that variable, is that visible to other threads? Users will assume the kernel arguments are shared among threads (since it's kernel-level) instead of being thread-local. What about serial offloaded tasks? E.g.,

@ti.kernel
def foo(a: ti.i32):
    for i in range(10):
        a = i
    print(a) # What should be the result here?

If we make a a new variable, a is shared among threads. If one thread modifies that variable, it is not guaranteed to be visible to other threads, and it's the user's responsibility to handle that.

The other thing I worry about is register usage on GPUs. We may need an extra optimization pass to eliminate these introduced temporary variables.

Yeah. Writing this may take a while. It's possible that I can finish writing the pass before 1.1.0 releases (2 days left) but I can't 100% guarantee. The fastest temporary solution is to throw a warning (or error?) when user alter a scalar argument in non-outermost scope.

@lin-hitonami
Copy link
Contributor

According to offline discussions, we decide to make kernel arguments immutable.

Repository owner moved this from Todo to Done in Taichi Lang Sep 13, 2022
lin-hitonami added a commit that referenced this issue Sep 13, 2022
Related issue = fixes #5619 

<!--
Thank you for your contribution!

If it is your first time contributing to Taichi, please read our
Contributor Guidelines:
  https://docs.taichi-lang.org/docs/contributor_guide

- Please always prepend your PR title with tags such as [CUDA], [Lang],
[Doc], [Example]. For a complete list of valid PR tags, please check out
https://github.com/taichi-dev/taichi/blob/master/misc/prtags.json.
- Use upper-case tags (e.g., [Metal]) for PRs that change public APIs.
Otherwise, please use lower-case tags (e.g., [metal]).
- More details:
https://docs.taichi-lang.org/docs/contributor_guide#pr-title-format-and-tags

- Please fill in the issue number that this PR relates to.
- If your PR fixes the issue **completely**, use the `close` or `fixes`
prefix so that GitHub automatically closes the issue when the PR is
merged. For example,
    Related issue = close #2345
- If the PR does not belong to any existing issue, free to leave it
blank.
-->

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug We've confirmed that this is an BUG
Projects
Status: Done
3 participants