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

Replace ref by literal #2828

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open

Conversation

hbrunie
Copy link
Collaborator

@hbrunie hbrunie commented Dec 17, 2024

Replacing PsyIR Reference by PsyIR Literal when it is easy to do so.
Same file, same subroutine, or subroutine contained in module.
Build a param_table with symbol name and Literal, then go through psyir references and symbol_table array type shapes to look for ref with name contained in param_table.

Issues:

  • it seems that initial value will always be a literal, is this expected behavior? If so I can remove a test raise error not triggered yet.
  • I might have found a bug: `character(len=4), parameter :: x = "toto" is not parsed a a is_constant.

@hbrunie hbrunie requested a review from arporter December 17, 2024 10:39
@hbrunie hbrunie self-assigned this Dec 17, 2024
@hbrunie hbrunie requested a review from sergisiso December 17, 2024 10:40
@hbrunie hbrunie added ready for review PSyIR Core PSyIR functionality labels Dec 17, 2024
@arporter
Copy link
Member

  • it seems that initial value will always be a literal, is this expected behavior? If so I can remove a test raise error not triggered yet.

Thanks Hugo. I'm pretty sure we allow any PSyIR expression as an initial value?

@hbrunie
Copy link
Collaborator Author

hbrunie commented Dec 17, 2024

  • it seems that initial value will always be a literal, is this expected behavior? If so I can remove a test raise error not triggered yet.

Thanks Hugo. I'm pretty sure we allow any PSyIR expression as an initial value?

Thanks. I made a test showing the current limit of this MR with respect to non-literal initial value (for example a binary operation).

But I don't understand why
character (len=4), parameter :: x ="toto" does not make a constant symbol with initial_value being

@arporter
Copy link
Member

But I don't understand why
character (len=4), parameter :: x ="toto" does not make a constant symbol with initial_value being

I think that's because we don't support the len=xxx specification on a character declaration.

Copy link

codecov bot commented Dec 17, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 99.89%. Comparing base (6afc06a) to head (bd12495).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #2828   +/-   ##
=======================================
  Coverage   99.89%   99.89%           
=======================================
  Files         359      360    +1     
  Lines       51073    51143   +70     
=======================================
+ Hits        51021    51091   +70     
  Misses         52       52           

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

@hbrunie
Copy link
Collaborator Author

hbrunie commented Dec 17, 2024

But I don't understand why
character (len=4), parameter :: x ="toto" does not make a constant symbol with initial_value being

I think that's because we don't support the len=xxx specification on a character declaration.

That's ok. I don't deal with "complex" right hand side for now. If this is not a Literal, the parameter is just ignored.

Copy link
Member

@arporter arporter left a comment

Choose a reason for hiding this comment

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

Good stuff Hugo, thanks for this.
Mostly my comments are about docstrings :-)
As you hint in one of your comments, I'm wondering whether we should always consider all constant symbols that are in scope, rather than explicitly looking at the Routine and Container symbol tables?
I also think it would be better if we quietly skipped constant symbols with a non-Literal value rather than raise an error. That would enable the transformation to do as much as it can rather than aborting early.
Coverage is good and the new test file fully covers the new source file.
If you feel brave, it would be good to try the transformation 'for real' by adding it to the transformation script that we use for NEMO in the integration tests. You could add it immediately after the call to enhance_tree_information:

enhance_tree_information(subroutine)
normalise_loops(
subroutine,
hoist_local_arrays=True,
convert_array_notation=True,
loopify_array_intrinsics=True,
convert_range_loops=True,
hoist_expressions=True
)

@hbrunie
Copy link
Collaborator Author

hbrunie commented Jan 20, 2025

Good stuff Hugo, thanks for this. Mostly my comments are about docstrings :-) As you hint in one of your comments, I'm wondering whether we should always consider all constant symbols that are in scope, rather than explicitly looking at the Routine and Container symbol tables? I also think it would be better if we quietly skipped constant symbols with a non-Literal value rather than raise an error. That would enable the transformation to do as much as it can rather than aborting early. Coverage is good and the new test file fully covers the new source file. If you feel brave, it would be good to try the transformation 'for real' by adding it to the transformation script that we use for NEMO in the integration tests. You could add it immediately after the call to enhance_tree_information:

enhance_tree_information(subroutine)
normalise_loops(
subroutine,
hoist_local_arrays=True,
convert_array_notation=True,
loopify_array_intrinsics=True,
convert_range_loops=True,
hoist_expressions=True
)

I am not sure Andrew about what you meant by : " should we always consider all constant symbols that are in scope, rather than explicitly looking at the Routine and Container symbol tables?"
Could you explain?

Besides, when you say "quietly skipping" does it mean that if the transformation finds a non-literal symbol it should not even throw a warning?
I thought that this could be handled by the transformation caller with exception catchers.
But I will do the change, and skip it quietly.

@hbrunie
Copy link
Collaborator Author

hbrunie commented Jan 23, 2025

@arporter I think I addressed all your concerns. Please let me know. Best, Hugo.

## NOTE: (From Andrew) We may want to look at all symbols in scope
# rather than just those in the parent symbol table?
if node.parent is not None and isinstance(node.parent, Container):
if node.parent.symbol_table is not None:
Copy link
Member

Choose a reason for hiding this comment

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

A Container is always constructed with a SymbolTable so this check should be unnecessary?

rbbl = ReplaceReferenceByLiteralTrans()
rbbl.apply(routine_foo)
written_code = fortran_writer(routine_foo.ancestor(Container))
print(written_code)
Copy link
Member

Choose a reason for hiding this comment

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

Please rm the print

Copy link
Member

Choose a reason for hiding this comment

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

This one's still here?


"""
_ERROR_MSG = (
"Psyclone(ReplaceReferenceByLiteral): only "
Copy link
Member

Choose a reason for hiding this comment

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

For consistency with other transformations, please change this to "ReplaceReferenceByLiteralTrans: only..."

Copy link
Member

Choose a reason for hiding this comment

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

Almost, see my earlier comments about simplifying by using self.name.

Copy link
Member

@arporter arporter left a comment

Choose a reason for hiding this comment

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

Looking good, thanks Hugo. I think it's a good idea to add the warnings to the generated code. In my comment about outer scopes, I was thinking we could just create the mapping for all symbols in scope (by recursing up through parent symbol tables), while ensuring that we don't conform to scoping rules (i.e. the value associated with the innermost scope takes precedence). However, it's a small point and this PR is probably already sufficient as it is.
Just a few minor things to tidy up.
I'll fire off the integration tests now.
As a reminder - please leave it to me to 'resolve' converstations as that makes it much easier to check everything :-)

@arporter
Copy link
Member

I've created #2879 to run the integration tests (because you can't do it for a PR from a fork).

@arporter
Copy link
Member

Integration tests were green :-)

@arporter
Copy link
Member

Hi @hbrunie, I can't remember: did you say this was ready for review now? (If you could set the label on the PR that really helps me see what I need to do next.)

@hbrunie
Copy link
Collaborator Author

hbrunie commented Feb 14, 2025

Hi @hbrunie, I can't remember: did you say this was ready for review now? (If you could set the label on the PR that really helps me see what I need to do next.)

Yes sorry, I do it now :-).

Copy link
Member

@arporter arporter left a comment

Choose a reason for hiding this comment

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

Thanks Hugo. Very, very nearly there now. Just a little bit more tidying and then this is done.

assert "integer, dimension(10,a) :: array" in written_code
assert "call foo(2 + 3)" in written_code


@pytest.mark.xfail
Copy link
Member

Choose a reason for hiding this comment

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

Thanks for adding this. We've found (from painful experience) that marking a whole test as 'xfail' often means that it can fail for a reason we don't expect and we don't notice. Therefore, please could you alter it by putting the 'xfail' inside the test. Have a look at e.g. test_apply_gocean_kern in syir/transformations/inline_trans_test.py. Also, please add a reason to the xfail (as is done in that example).

if param_table.get(sym_name):
message = (
"Psyclone(ReplaceReferenceByLiteralTrans):"
+ f" Symbol already found {sym_name}."
f"{ReplaceReferenceByLiteralTrans._ERROR_MSG_START}"
Copy link
Member

Choose a reason for hiding this comment

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

You can use self.name here instead of this _ERROR_MSG_START - that will give the name of the Transformation.

message = (
ReplaceReferenceByLiteralTrans._ERROR_MSG
+ f"{sym_name} is assigned "
ReplaceReferenceByLiteralTrans._ERROR_MSG_ONLY_INITVAL
Copy link
Member

Choose a reason for hiding this comment

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

self.name here too.

:param param_table: map of parameters to Literal values.

:return: the new shape with any references to constants replaced by
their Literal values.
Copy link
Member

Choose a reason for hiding this comment

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

This continued line needs to be indented.

rbbl = ReplaceReferenceByLiteralTrans()
rbbl.apply(routine_foo)
written_code = fortran_writer(routine_foo.ancestor(Container))
print(written_code)
Copy link
Member

Choose a reason for hiding this comment

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

This one's still here?


"""
_ERROR_MSG = (
"Psyclone(ReplaceReferenceByLiteral): only "
Copy link
Member

Choose a reason for hiding this comment

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

Almost, see my earlier comments about simplifying by using self.name.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PSyIR Core PSyIR functionality reviewed with actions
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants