8000 Fix wrong references to return value when function is inlined multiple times into the same scope by asl · Pull Request #5163 · p4lang/p4c · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Fix wrong references to return value when function is inlined multiple times into the same scope #5163

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

Merged
merged 2 commits into from
Mar 6, 2025

Conversation

asl
Copy link
Contributor
@asl asl commented Mar 4, 2025

Fixes #5162

@asl asl requested review from vlstill, ChrisDodd and fruffy March 4, 2025 20:35
@asl
Copy link
Contributor Author
asl commented Mar 4, 2025

See #5162 for the complete breakdown. Testcase distilled from very subtly miscompilation of large app :(

// { <body2>
// retval = <something2>
// a = retval + retval;
// }
Copy link
Contributor

Choose a reason for hiding this comment

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

These should get renamed to retval_1 and retval_2 -- that seems to happen with the inline-function3-frontend.p4 below, so this extra copy, while not harmful (and pretty much always eliminated by local_copyprop) should not be necessary?

Copy link
Contributor
@ChrisDodd ChrisDodd Mar 4, 2025

Choose a reason for hiding this comment

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

Perhaps the bug in 5162 was seen with a different midend.cpp than backends/p4test/midend.cpp? There would seem to be a subtle order dependency between inlinining and RemoveReturns and UniqueNames where non-unique names moved into the same scope? In general, inlining assumes names are globall unique (requires running UniqueNames before it).

Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps RemoveReturns should use namegen->newName("retval") rather than just using the fixed name "retval"?

Copy link
Contributor Author
@asl asl Mar 4, 2025

Choose a reason for hiding this comment

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

The function is same. Inlined twice. So, RemoveReturns will not help here as it will process the caller, not the callee.

The problem is at the callee side – we're passing PathExpression for return value which is "out the scope" here (see #5162 for step by step breakdown).

The bug is clearly reproducible with the mainline p4c as test shows.

In general, inlining assumes names are globall unique (requires running UniqueNames before it).

Indeed. And this PR ensures this.

Copy link
Contributor Author
@asl asl Mar 4, 2025

Choose a reason for hiding this comment

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

These should get renamed to retval_1 and retval_2 -- that seems to happen with the inline-function3-frontend.p4 below, so this extra copy, while not harmful (and pretty much always eliminated by local_copyprop) should not be necessary?

Yes, it is, after the fix :) Before the fix, it will be just a single value:

        y3_0 = tmp;
        if (y3_0 == 1w1) {
            y0 = 1w0;
        } else if (y0 != 1w1) @inlinedFrom("foo") {
            a_4 = bt3;
            retval_2 = a_4 + 1w1;
            y0 = retval_2 | retval_2;
        }
        bt = y0;
    }

After first inliner iteration (without the fix) we're having:

            } else if (y0_0 != 1w1) @inlinedFrom("foo") {
                bit<1> a_1;
                a_1 = bt2;
                @name("hasReturned") bool hasReturned_0;
                @name("retval") bit<1> retval_0;
                hasReturned_0 = false;
                {
                    hasReturned_0 = true;
                    retval_0 = a_1 + 1w1;
                }
                y0_0 = foo(bt3) | retval_0;
            }
            bt = y0_0;
        }

after second (note two different retval_0 here in different scopes, reference to outer one will be lost as the resolution is by the name):

            } else if (y0_0 != 1w1) @inlinedFrom("foo") {
                bit<1> a_1;
                a_1 = bt2;
                @name("hasReturned") bool hasReturned_0;
                @name("retval") bit<1> retval_0;
                hasReturned_0 = false;
                {
                    hasReturned_0 = true;
                    retval_0 = a_1 + 1w1;
                }
                @inlinedFrom("foo") {
                    bit<1> a_2;
                    a_2 = bt3;
                    @name("hasReturned") bool hasReturned_0;
                    @name("retval") bit<1> retval_0;
                    hasReturned_0 = false;
                    {
                        hasReturned_0 = true;
                        retval_0 = a_2 + 1w1;
                    }
                    y0_0 = retval_0 | retval_0;
                }
            }

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, ok -- I see. The problem is that the function is being inlined twice from the same source into the same scope. I'm concerned that if there are other names local to the function being inlined (eg, if it has a user-declared local var that is used somehow), the same thing will happen with that variable.

In this case retval is just a local variable in the function that was introduced by RemoveReturns.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I checked this case:

  • The function is inlined into own block, so all function locals are sealed there
  • We create new names for inout / out parameters, so we are good here as well
  • What remained is function return value, and this PR essentially handles this case

This is special "function case", actions do not return and therefore are fine.

@fruffy fruffy added core Topics concerning the core segments of the compiler (frontend, midend, parser) run-validation Use this tag to trigger a Validation CI run. labels Mar 4, 2025
@asl asl changed the title Fir wrong references to return value when function is inlined multiple times into the same scope Fix wrong references to return value when function is inlined multiple times into the same scope Mar 4, 2025
…e times into the same scope.

Signed-off-by: Anton Korobeynikov <anton@korobeynikov.info>
@asl asl force-pushed the fix-inline-result branch from d965e23 to 3d8e4aa Compare March 5, 2025 19:36
Signed-off-by: Anton Korobeynikov <anton@korobeynikov.info>
@asl asl force-pushed the fix-inline-result branch from 3d8e4aa to 4cc827a Compare March 5, 2025 21:24
@asl asl added this pull request to the merge queue Mar 5, 2025
Merged via the queue into p4lang:main with commit 126f849 Mar 6, 2025
21 checks passed
@asl asl deleted the fix-inline-result branch March 6, 2025 01:00
< 76A0 div id="issue-comment-box">
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Topics concerning the core segments of the compiler (frontend, midend, parser) run-validation Use this tag to trigger a Validation CI run.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

FunctionInliner emits wrong reference to return value when the same function is inlined multiple times
3 participants
0