-
Notifications
You must be signed in to change notification settings - Fork 12
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
Global var hoisting #226
Global var hoisting #226
Conversation
Documentation for this branch can be viewed at https://sites.ecmwf.int/docs/loki/226/index.html |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #226 +/- ##
==========================================
+ Coverage 92.31% 92.36% +0.04%
==========================================
Files 95 95
Lines 17368 17478 +110
==========================================
+ Hits 16034 16144 +110
Misses 1334 1334
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, this looks very good to me!
I've left a few suggestions for stylistic improvements and flagged a potential issue when an import shadows an import in a parent scope. Arguably, this is an almost academic edge case and bad practice anyway, but the fix is easy.
@@ -409,22 +412,36 @@ def test_global_variable_analysis(frontend, key, config, global_variable_analysi | |||
'global_var_analysis_kernel_mod#kernel_a': { | |||
'defines_symbols': set(), | |||
'uses_symbols': { | |||
('iarr(1:3)', 'global_var_analysis_header_mod'), ('rarr(1:5, 1:3)', 'global_var_analysis_header_mod') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find the in-line special casing around OMNI
hard to read. Especially, because it's mixed with a different way of distinguishing between OMNI and the others already. Could we maybe pull this out and add a corresponding comment that explains this?
A possible pattern would be this:
if frontend == OMNI:
# OMNI replaces all parameters by their values. For other frontends we get the
# parameters as additional analysis data entries
nfld_dim = '1:3'
nval_dim = '1:3'
nfld_data = set()
nval_data = set()
else:
nfld_dim = 'nfld'
nval_dim = 'nval'
nfld_data = {('nfld', 'global_var_analysis_header_mod')}
nval_data = {('nval', 'global_var_analysis_header_mod')}
expected_trafo_data = {
'global_var_analysis_header_mod#nval': {
...
'offload': nval_data,
}
...
'global_var_analysis_kernel_mod#kernel_a': {
'defines_symbols': set(),
'uses_symbols': nval_data | nfld_data | {
(f'iarr({nfld_dim})', 'global_var_analysis_header_mod'),
(f'rarr({nval_dim}, {nfld_dim})', 'global_var_analysis_header_mod'),
},
...
all_defines_symbols = set() | ||
all_uses_symbols = set() | ||
for _, value in defines_symbols.items(): | ||
all_defines_symbols |= value | ||
for _, value in uses_symbols.items(): | ||
all_uses_symbols |= value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't this achieve the same?
all_defines_symbols = set() | |
all_uses_symbols = set() | |
for _, value in defines_symbols.items(): | |
all_defines_symbols |= value | |
for _, value in uses_symbols.items(): | |
all_uses_symbols |= value | |
all_defines_symbols = set.union(*defines_symbols.values(), set()} | |
all_uses_symbols = set.union(*uses_symbols.values(), set()} |
scope = routine | ||
while scope: | ||
import_map.update(scope.import_map) | ||
scope = scope.parent |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mind you: this poses the risk of overwriting a shadowed symbol - for example:
module a_mod
use b_mod, only: a, b, c
contains
subroutine a_routine
use c_mod, only c
! symbol_map will now contain c => b_mod
! because the parent scope is processed after the inner scope
end subroutine a_routine
end module a_mod
One way to avoid this would be to use
import_map = CaseInsensitiveDict(
(s.name, imprt) for imprt in routine.all_imports[::-1] for s in imprt.symbols
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Unfortunately, there's still a bit left related to the imports, which may just have been an oversight. Otherwise good to go!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only had a brief look, but looks very neat and well tested! GTG from me.
…zing the slightly modified 'GlobalVariableAnalysis' for analysis)
… discard them in the transformation pass instead (if wanted/necessary)
Co-authored-by: Balthasar Reuter <[email protected]>
Co-authored-by: Balthasar Reuter <[email protected]>
8518a21
to
a840d1d
Compare
Global/Imported variable hoisting.
Convert e.g.,
to:
Tested locally with CLOUDSC Loki C transpilation. However, this requires PR #208.