-
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
Allow inlining of Statement Functions #345
Conversation
Documentation for this branch can be viewed at https://sites.ecmwf.int/docs/loki/345/index.html |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #345 +/- ##
==========================================
+ Coverage 95.29% 95.31% +0.02%
==========================================
Files 170 170
Lines 36414 36467 +53
==========================================
+ Hits 34701 34760 +59
+ Misses 1713 1707 -6
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
Maybe it would be better to not replicate the functionality of |
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 great. Small remarks on improving the implementation and I agree with your suggestion to merge the expression map update.
real, intent(inout) :: ret(:) | ||
real :: ret2 | ||
real, parameter :: rtt = 1.0 | ||
{stmt_decls_code if stmt_decls else ''} |
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.
We would usually have a header include instead, no?
{stmt_decls_code if stmt_decls else ''} | |
{stmt_decls_code if stmt_decls else '#include "fcttre.func.h"'} |
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.
That is correct. However, it does not change anything here.
loki/transformations/inline.py
Outdated
|
||
def inline_statement_functions(routine): | ||
""" | ||
Replaces `InlineCall` expression to statement functions with the |
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.
Replaces `InlineCall` expression to statement functions with the | |
Replaces :any:`InlineCall` expression to statement functions with the |
loki/transformations/inline.py
Outdated
@@ -339,6 +360,89 @@ def inline_elemental_functions(routine): | |||
routine.spec = Transformer(import_map).visit(routine.spec) | |||
|
|||
|
|||
def recursive_inline_expression_map_update(expr_map, max_iterations=10): |
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 agree with your remark, it's probably best to avoid the code duplication and instead introduce an additional argument mapper_cls=SubstituteExpressionsMapper
to the recursive_expression_map_update
function.
# Inline Statement Functions | ||
if self.inline_stmt_funcs: | ||
inline_statement_functions(routine) | ||
|
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.
This code path is currently untested. Can we add a test where InlineTransformation
is called to apply the statement function inlining?
loki/transformations/inline.py
Outdated
function = expr.routine | ||
v_result = expr.routine.variable | ||
# Substitute all arguments through the elemental body | ||
arg_map = dict(zip(function.arguments, expr.parameters)) |
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.
Just wondering: Wouldn't arg_map = dict(expr.arg_iter())
work here, and also below for "regular" inline calls? That should also take care of keyword arguments.
(Cc @mlange05)
loki/transformations/inline.py
Outdated
if call.procedure_type is BasicType.DEFERRED: | ||
continue | ||
if call.procedure_type.is_function and isinstance(call.routine, StatementFunction): |
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.
Just a little hint to avoid repeated lookup of type info:
if call.procedure_type is BasicType.DEFERRED: | |
continue | |
if call.procedure_type.is_function and isinstance(call.routine, StatementFunction): | |
proc_type = call.procedure_type | |
if proc_type is BasicType.DEFERRED: | |
continue | |
if proc_type.is_function and isinstance(proc_type.procedure, StatementFunction): |
loki/transformations/inline.py
Outdated
stmt_arguments = set() | ||
stmt_func_map = {} | ||
for stmt_func_decl in stmt_func_decls: | ||
for arg in stmt_func_decl.arguments: | ||
stmt_arguments.add(arg) | ||
stmt_func_map[stmt_func_decl] = None | ||
# remove the statement function declarations | ||
routine.spec = Transformer(stmt_func_map).visit(routine.spec) | ||
|
||
# remove the declarations of the statement function arguments | ||
decls = FindNodes(VariableDeclaration).visit(routine.spec) | ||
decls = tuple(d for d in decls if any(isinstance(s, sym.ProcedureSymbol) or s in stmt_arguments for s in d.symbols)) | ||
decl_map = {} | ||
for decl in decls: | ||
decl_map[decl] = None | ||
routine.spec = Transformer(decl_map).visit(routine.spec) |
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.
This boils down to removing a bunch of variable declarations and everything in stmt_func_decls
, so that should be possible in a single Transformer
pass. Maybe something along these lines works?
vars_to_remove = {stmt_func.variable.name.lower() for stmt_func in stmt_func_decls}
vars_to_remove += {arg.name.lower() for stmt_func in stmt_func_decls for arg in stmt_func.arguments}
spec_map = {stmt_func: None for stmt_func in stmt_func_decls}
for decl in routine.declarations:
if any(var in vars_to_remove for var in decl.symbols):
symbols = tuple(var for var in decl.symbols if var not in vars_to_remove)
if symbols:
decl._update(symbols=symbols)
else:
spec_map[decl] = None
routine.spec = Transformer(spec_map).visit(routine.spec)
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 great now!
Due to other merged PRs we have a conflict now, would you mind rebasing this over latest main? I hope this will then also trigger the tests again.
loki/transformations/inline.py
Outdated
# if it is an inline call to a Statement Function | ||
if isinstance(expr.routine, StatementFunction): | ||
function = expr.routine | ||
v_result = expr.routine.variable |
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.
This looks unused?
…ement functions to be default False
… InlineTransformation
…nd corresponding function arguments
838b353
to
a29f729
Compare
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.
Looks fantastic! Neatly implemented, neatly tested and very powerful! Very nice! GTG from me.
@@ -468,7 +468,7 @@ def replace_selected_kind(routine): | |||
routine.spec.prepend(imprt) | |||
|
|||
|
|||
def recursive_expression_map_update(expr_map, max_iterations=10): | |||
def recursive_expression_map_update(expr_map, max_iterations=10, mapper_cls=SubstituteExpressionsMapper): |
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.
No action: Very neat! 👏
From
to