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

FParser: Perform in-place scope attachment during parse #242

Merged
merged 11 commits into from
Mar 12, 2024

Conversation

mlange05
Copy link
Collaborator

@mlange05 mlange05 commented Mar 9, 2024

Note: This is the second part to optimising the performance of the FP frontend, as detailed in PR #234. It contributes significantly to the throughput number presented in #234 .

The key idea behind this PR is to avoid the costly rescoping pass of the subroutine/module bodies after the initial IR generation. Instead we now use the scope argument passed through the AST-to-IR converter whenever possible.

One caveat to this is that we still need to do one AttachScopes pass after parsing the spec, as we might encounter symbols used in shape declarations out of sequence (yay, Fortran!). I have adjusted one of the tests to capture this accordingly.

There are also a few little tricks involved, and I've added a small utility to temporarily override dict values, as we now need to be careful when and what to pass down the AST parse tree. There is still one hacky workaround left that forces type re-evaluation from scope for ProcedureDesignators, as the recursive lookup for parents still injects, wrongly-typed pseudo-symbols into the scope (via Symbol.variable_map). I leave it to a follow-on to fix this correctly.

@mlange05 mlange05 requested a review from reuterbal March 9, 2024 06:45
Copy link

github-actions bot commented Mar 9, 2024

Documentation for this branch can be viewed at https://sites.ecmwf.int/docs/loki/242/index.html

Copy link

codecov bot commented Mar 9, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 92.50%. Comparing base (970e0b6) to head (eba11ee).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #242      +/-   ##
==========================================
+ Coverage   92.47%   92.50%   +0.02%     
==========================================
  Files          95       95              
  Lines       17473    17503      +30     
==========================================
+ Hits        16159    16191      +32     
+ Misses       1314     1312       -2     
Flag Coverage Δ
lint_rules 96.22% <ø> (ø)
loki 92.46% <100.00%> (+0.02%) ⬆️
transformations 91.98% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@mlange05 mlange05 marked this pull request as ready for review March 9, 2024 11:37
@mlange05
Copy link
Collaborator Author

Confirmed clean with ec-physics regression.

Copy link
Collaborator

@reuterbal reuterbal left a comment

Choose a reason for hiding this comment

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

Many thanks for grinding through this! I can't claim to fully understand the justification/rationale behind every changed line but it does look sane to me and the expanded testing for edge cases is much appreciated.

Left two comments/suggestions but they are entirely optional.

Comment on lines +351 to +357
name = o.tostr()
scope = kwargs.get('scope', None)
parent = kwargs.get('parent')
if parent:
scope = parent.scope
if scope:
scope = scope.get_symbol_scope(name)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm assuming this is the discussed handling of derived type members, that ensures

  1. that we create symbol table entries in the scope where the derived type instance has been declared (and not the typedef scope).
  2. we attach symbols to the scope where they are declared (and not the closest one)

For future sanity: Would it be worth adding a comment explaining why it's done like this?

@@ -2929,7 +2979,7 @@ def visit_Assignment_Stmt(self, o, **kwargs):

# Special-case: Identify statement functions using our internal symbol table
symbol_attrs = kwargs['scope'].symbol_attrs
if isinstance(lhs, sym.Array) and lhs.name in symbol_attrs:
if isinstance(lhs, sym.Array) and not lhs.parent and lhs.name in symbol_attrs:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Haha, I think I've hit that one end of last week, too...

Comment on lines +2497 to +2505
scope = kwargs.get('scope', None)
parent = self.visit(o.children[0], **kwargs)
if parent:
scope = parent.scope
name = self.visit(o.children[2], **kwargs)
name = name.clone(name=f'{parent.name}%{name.name}', parent=parent)
# Hack: Need to force re-evaluation of the type from parent here via `type=None`
# To fix this, we should stop creating symbols in the enclosing scope
# when determining the type of drieved type members from their parent.
name = name.clone(name=f'{parent.name}%{name.name}', parent=parent, scope=scope, type=None)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just looking at the visit_Name, not having actually tested this: Wouldn't passing down parent in the recursion to obtain name work around the scope issue here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Alas, no (I tried!). I'm using this hack in two places, each associated with a specific failure in the test base (both in test_scheduler.py). Neither was fixed by passing the parent down (even though I can see what you mean).

I still believe (but not 100% on this), that this is due to us (unintentionally) unrolling all potential local subcomponent variables of a derived-type variable in the local scope. I tried dropping this, but it opened another can of worms, so dropped it. Maybe worth capturing this in an issue instead?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Captured in #243

@reuterbal reuterbal merged commit 1ab6144 into main Mar 12, 2024
12 checks passed
@reuterbal reuterbal deleted the naml-fparser-inplace-scope-attachment branch March 12, 2024 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants