-
Notifications
You must be signed in to change notification settings - Fork 29
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
(Towards #2271, closes #2278) Generalise reference_accesses() and use to tidy KernelModuleInlineTrans. #2825
base: master
Are you sure you want to change the base?
Conversation
I need to add explicit unit tests for the new |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #2825 +/- ##
==========================================
- Coverage 99.88% 99.88% -0.01%
==========================================
Files 357 357
Lines 49823 49896 +73
==========================================
+ Hits 49767 49839 +72
- Misses 56 57 +1 ☔ View full report in Codecov by Sentry. |
This PR enhances the functionality of Ready for review. One for @hiker or @sergisiso. |
(I've triggered the integration tests.) |
Taking this back as both the NEMOv4 and LFRic integration tests failed :-( |
LFRic ('with all transformations') test fails with:
and the NEMO v.4 OpenACC kernels test fails at the final link stage:
I think the latter often means we've put OpenACC around a function call but the function itself hasn't been marked-up for GPU compilation? |
In LFRic, we have an in-lined kernel that calls our PSyclone-generated routine but that routine hasn't been inlined:
Presumably, the symbol isn't being spotted by the transformation? |
The issue seems to be that Some suggestions: SYMBOLIC, STATIC, COMPILE_TIME What do @hiker and @sergisiso think? |
I don't like SYMBOLIC, as any other reference is also symbolic. I could live with STATIC and COMPILE_TIME but I don't know if they are descriptive enough (and it is similar to some of the symbol interfaces which can make it confusing). Why don't we simply call them: CALL / CALLED Note that before we discussed a new AccessType that would apply for things that Fortran calls inquire/inquiry e.g. lbound(ref), size(ref, 2), ..., I would keep this separate and call these "ref" AccessType INQUIRE. |
I like, Given that we are discussing access modes: while I am aware that I have added it, I wonder if we should keep READINC as access pattern. It seems to be very LFRic-specific? From a dependency point of view ... do we even need |
GungHo now builds and runs (OpenACC) :-) |
Integration tests were green this time. Really ready for review now. |
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 for starting the work on this issue @arporter , it will be a great improvement if we solve/do better on this (I see #2271 is marked as "towards" could you clarify what will be missing?). That said I have a some concerns with the current implementation:
- The main one is that this PR classifies kinds, datatypesymbols, ... as READs. I think this will create incorrect code in places that we use the VAI: data movement directives, openmp infer_shared_attributes, extraction driver, ... as these will appear in the list of variables when they should not (and we probably miss tests properly checking this). You added exceptions for the extraction driver, but I think the same will be needed everywhere that uses VAI, which makes me think that instead of the exceptions it would be easier to mark them as AccessType.TYPE_INFO/INQUIRY in this PR already, as I believe it will solve/clean up a few things. It could also allow to remove the options and COLLECT-ARRAY-SHAPE-READS.
- I am not sure the UNKNOWN AccessType is considered as worst-case scenario in most cases, which probably means we could come up with cases the make anything using VAI fail.
- Finally, not for this PR but VAI/signatures do not deal well with nested scopes, I think we need some xfails/references to
reference_accesses
does not support nested scopes #2424 in the places that this happens.
See more details inline
# The RoutineSymbol has a CALL access. | ||
sig, indices_list = self.routine.get_signature_and_indices() | ||
var_accesses.add_access(sig, AccessType.CALL, self.routine) | ||
# Any symbols referenced in any index expressions are READ. |
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.
Maybe # Continue processing references in any index expression
As they are not all reads, e.g. there may be another CALL, even with and output argument which would be WRITE
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.
Same in a similar comment below which was already here
|
||
def __str__(self): | ||
'''Convert to a string representation, returning just the | ||
enum (e.g. 'WRITE').. | ||
:return: API name for this string. | ||
:rtype: str |
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 know in the past we didn't do it for __str__
but maybe now we can use the -> str
typehint for the sake of helping IDEs.
:returns: Corresponding AccessType enum. | ||
:Raises: ValueError if access_string is not a valid access type. | ||
:rtype: :py:class:`psyclone.core.access_type.AccessType` |
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.
Maybe just -> AccessType
if this is a valid typehint?
:Raises: ValueError if access_string is not a valid access type. | ||
:rtype: :py:class:`psyclone.core.access_type.AccessType` | ||
|
||
:raises: ValueError if access_string is not a valid access type. |
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.
The second semicolon is in the wrong place
vai = VariablesAccessInfo(kernel_schedule) | ||
table = kernel_schedule.symbol_table | ||
for sig in vai.all_signatures: | ||
symbol = table.lookup(sig.var_name, otherwise=None) |
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 like this new version, but note that this comes with the signatures limitations e.g. don't work with nested scopes:
- if the variable has a unique name
subroutine test()
do i = 1, 10 <- PSyIR declares "a" here
a(i) = 1
end do
end subroutine
and will fails with the TransformationError below.
- if the variable has a name clash
integer :: a
subroutine test()
do i = 1, 10 <- PSyIR declares "a" here
a(i) = 1
end do
end subroutine
it will fails with the "is declared in the same module scope".
Both cases are wrong and the subroutine could be inlined. Granted that this won't happen often because it requires inlining subroutines that have previously been transformed with psyclone so that a symbol was declared in a inner scope. But maybe we should document - add an xfail to #2424
@@ -448,12 +448,14 @@ def test_variables_access_info_domain_loop(): | |||
structure, so especially the loop variable is not defined) work as | |||
expected. | |||
''' | |||
_, invoke = get_invoke("25.1_kern_two_domain.f90", "lfric", idx=0) | |||
psy, invoke = get_invoke("25.1_kern_two_domain.f90", "lfric", idx=0) |
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.
Revert psy to _ as it is unused
assert ( | ||
"basis_w1_qr: READ, basis_w3_qr: READ, cell: READ+WRITE, " | ||
"diff_basis_w2_qr: READ, diff_basis_w3_qr: READ, f1_data: " | ||
"READ+WRITE, f2_data: READ, field_type: READ, i_def: READ, " |
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.
Is the comment outdated? Why is i_def here now but r_def should not?
subroutine my_sub | ||
use some_mod, only: my_grid | ||
integer :: i, j, k | ||
call my_grid(k)%update(i,j) |
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.
Maybe one of the indices should be another type-bound call with more indices, to check that it compounds properly.
reader = FortranStringReader(''' | ||
subroutine mytest | ||
myloop: DO i = 1, 10_i_def | ||
a = b + sqrt(c) + 1.0_r_def |
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.
As mentioned above, I would like to know what happens with "sqrt" (or any call), it is a signature?, is it readwrite or unkonwn?
@@ -192,7 +192,8 @@ def get_input_parameters(self, read_write_info, node_list, | |||
# parameter and does not need to be saved. Note that loop variables | |||
# have a WRITE before a READ access, so they will be ignored | |||
# automatically. | |||
if not variables_info[signature].is_written_first(): | |||
if (not variables_info[signature].is_written_first() and |
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.
First, instead of being "not" and adding the not is_called here, maybe this should be "is_read_first" and keep all the AccessType logic inside the method? It would also match what the docstring here says.
But in addition, I checked if "is_write_first" considers the UNKNON AccessType as a worst-case scenario for the first access (as I wondered this in a previous comment) and it does not. As this method are currently implemented they mean "is guaranteed to be read/write first?" but I think what we need here is "is potentially read/write first?" (but I am unsure I have not used the CallTreeUtils myself yet)
Maybe this is the typical issue with boolean methods that can be unknow, as we could add the is_read/write_first(unknown_as=True/False)
to make it explicit that also used in other places?
The trouble with adding |
… from VariablesAccessInfo
…s instead of marking everything READ
I found I needed some of this in #2716 (while improving KernelModuleInlineTrans) so I thought I'd best do it as a separate PR.