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

Passing a result of an assembly function call with void (unspecified) return value as an argument optimizes away the call to that assembly function #1201

Open
1 task done
novusnota opened this issue Dec 18, 2024 · 3 comments
Labels
feature: asm Tact-embedded assembly functions kind: bug Something isn't working or isn't right

Comments

@novusnota
Copy link
Member

novusnota commented Dec 18, 2024

Are you using the latest released (or pre-released, a.k.a. "next") version?

  • I'm using the latest Tact version

Tact source code

// This pushes an `x` onto the stack
asm fun hey(x: Int) {}

// Cleaning up
asm fun drop() { DROP }

fun showcase() {
    // Current depth of the stack: 3,
    // assuming `showcase()` will be called within internal message receiver

    // Calling this pushes 42 onto the stack,
    // so the depth of it is now 4
    hey(42);

    // But calling this optimizes away the call to the `hey(27)` entirely!
    // As if it was never called and, therefore, 27 is not pushed onto the stack,
    // so the current depth is still 4
    dump(hey(27));

    // Clean-up
    drop(); // removes the 42, not 27, which was never placed there
}

Relevant Tact/build system log output

No response

What happened?

No response

What did you expect?

I expected both 42 and 27 on the stack, since there were no explicit return type specified in hey() function.

Steps to reproduce

No response

How do you run Tact?

Blueprint

Anything else?

No response

@novusnota novusnota added the kind: bug Something isn't working or isn't right label Dec 18, 2024
@anton-trunov anton-trunov added the feature: asm Tact-embedded assembly functions label Dec 18, 2024
@Gusarich
Copy link
Member

I don't think it's a good idea to push something onto the stack inside a function without treating it as a return value. This approach makes it very easy to mess up the stack managed by Tact/FunC.

@anton-trunov
Copy link
Member

// But calling this optimizes away the call to the `hey(27)` entirely!
// As if it was never called and, therefore, 27 is not pushed onto the stack,
// so the current depth is still 4
dump(hey(27));

It does not seem hey(27) is optimized away, because dump consumes the top of the stack (27)

@novusnota
Copy link
Member Author

// But calling this optimizes away the call to the hey(27) entirely!
// As if it was never called and, therefore, 27 is not pushed onto the stack,
// so the current depth is still 4
dump(hey(27));
It does not seem hey(27) is optimized away, because dump consumes the top of the stack (27)

Sure, but the 27 doesn't even appear on the stack, dump just voluntatily prints void

// This pushes an `x` onto the stack
asm fun hey(x: Int) { }

asm fun drop() { DROP }

fun showcase() {
    // Current depth of the stack: 3,
    // assuming `showcase()` will be called within internal message receiver

    // Calling this pushes 42 onto the stack,
    // so the depth of it is now 4
    hey(42);
    dumpStack();

    // But calling this optimizes away the call to the `hey(27)` entirely!
    // As if it was never called and, therefore, 27 is not pushed onto the stack,
    // so the current depth is still 4
    dump(hey(27));
    dumpStack();

    // Clean-up
    drop(); // removes the 42, not 27, which was never placed there
}

When called, showcase() yields:

Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature: asm Tact-embedded assembly functions kind: bug Something isn't working or isn't right
Projects
None yet
Development

No branches or pull requests

3 participants