Skip to content

(Closes #3334 #1013) Permit only module-inlined Kernels to be transformed#3294

Open
arporter wants to merge 45 commits intomasterfrom
1823_transform_inlined_kerns_only
Open

(Closes #3334 #1013) Permit only module-inlined Kernels to be transformed#3294
arporter wants to merge 45 commits intomasterfrom
1823_transform_inlined_kerns_only

Conversation

@arporter
Copy link
Member

@arporter arporter commented Jan 21, 2026

Require that all kernel transformations act only on module-inlined Kernels.
Do away with the 'rename-and-write' functionality currently used for modified kernels.
We have to keep the -okern command-line flag as that is used when creating OpenCL versions of Kernels.

@arporter arporter self-assigned this Jan 21, 2026
@arporter arporter marked this pull request as draft January 21, 2026 17:11
@arporter
Copy link
Member Author

Possibly I need to store the RoutineSymbol associated with a Kernel within the Kernel class (c.f. Call.reference). That way, I can tell whether it has been module-inlined or not and can get rid of the special flag for that.

@arporter
Copy link
Member Author

arporter commented Jan 23, 2026

Note to self: I will need to remove the kernel_outputdir test fixture.

EDIT: can't do this because we do still output OpenCL versions of kernels in some tests.

@codecov
Copy link

codecov bot commented Jan 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.95%. Comparing base (97543bc) to head (0949296).
⚠️ Report is 15 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3294      +/-   ##
==========================================
- Coverage   99.95%   99.95%   -0.01%     
==========================================
  Files         384      385       +1     
  Lines       54225    54087     -138     
==========================================
- Hits        54203    54065     -138     
  Misses         22       22              

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

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@arporter
Copy link
Member Author

arporter commented Feb 4, 2026

Coverage is now all good but the LFRic extraction integration test failed :-(

@arporter
Copy link
Member Author

arporter commented Feb 4, 2026

In lfric/eg17/full_example_extract:

$ diff main_psy.f90 on_main/main_psy.f90 
4d3
<   use testkern_w0_kernel_mod, only : testkern_w0_code
74a74
>     use testkern_w0_kernel_mod, only : some_other_var, testkern_w0_code

so it appears the some_other_var import is missing on my branch.

@arporter
Copy link
Member Author

arporter commented Feb 4, 2026

This turned out to be due to the fact that I've moved the import of Kernel routines up into the Container and then the ExtractNode was falling foul of #1734

@arporter
Copy link
Member Author

Doc failure was a timeout on the NVIDIA web site. It works OK for me though.

Copy link
Collaborator

@sergisiso sergisiso left a comment

Choose a reason for hiding this comment

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

@arporter It's good to see this (even bigger) clean up.

I just have a some questions about why some lines were changed and it may be good to have a plan for when the KernelModuleInlineTrans is made generic (see inline).

Comment on lines -109 to -110
# Flag that the kernel has been modified
node.modified = True
Copy link
Collaborator

Choose a reason for hiding this comment

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

There is one more use in:

tutorial/practicals/LFRic/single_node/3_sequential/matvec_opt.py
67:            kernel.modified = True

Which made me realise this example will also need the ModuleInlining (and the kernel_schedule.walk(IntrinsicCall) is also broken because kernel.get_callees() returns a list now)
(also the Makefile commands have the --psykal-dsl lfric missing)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Grepping Matmul2CodeTrans, also examples/lfric/eg15/matvec_opt.py may be missing ModuleInling

Copy link
Member Author

Choose a reason for hiding this comment

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

I see from #1015 that this has been broken since 2020. Perhaps we should just remove this material in favour of @hiker's recent training material?

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, eg15 shows up a bit of a problem: there's nothing stopping a user getting the kernel schedule and then applying transformations to it themselves. However, those transformations will now have no effect as the modified PSyIR will never be written to file :-(

Copy link
Member Author

Choose a reason for hiding this comment

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

Anyway, I've now fixed-up the example and the tutorial.

use quadrature_xyoz_mod, only : quadrature_xyoz_proxy_type, \
quadrature_xyoz_type
use testkern_qr_mod, only : testkern_qr_code""" in output)
quadrature_xyoz_type""" in output)
Copy link
Collaborator

Choose a reason for hiding this comment

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

pylint says "superfluous-parens"

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed.


"""
if not isinstance(node, CodedKern):
return
Copy link
Collaborator

Choose a reason for hiding this comment

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

When I first saw that I though this is to let Builtins pass, but then I found somewhere that this is provided with a call_node as returns None. But then I realised there is nothing here specific to kernels. If this a transfomration is provided a call and its callee is being modified, the same check must be done. Maybe it's worth it doing this generic: class CalleeTransformationMixin and _check_callee_implementation_is_local ?

Then I would do this more strict and not return None for everything else, if somewhere a builtin is valid I would do:

if not isinstance(node, Builtin):
    node.check_callee_implementation_is_local(node)

What do you think?

(I have not look everywhere this is used, it could be good to check is applicable everywhere before doing the change)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh I also see that the KernelModuleInlineTrans that the error message suggest is only applicable to kernels. So maybe this can be left with a TODO together with the plans to make KernelModuleInlineTrans generic which we have discussed in the past (maybe we could repurpose #2683 to include this?)

(I would still rename the method to check_callee_implementation_is_local and make it stricter now)

Copy link
Member Author

Choose a reason for hiding this comment

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

Good points. I have generalised it, renamed it and moved it into psyir.transformations. In some places a Routine is valid so I've added checks for those.

Comment on lines 205 to 211
global_variables = set(sym.name for sym in
ksched.symbol_table.imported_symbols)
prec_sym_names = set(sym.name for sym in
ksched.symbol_table.precision_datasymbols)
non_prec_vars = global_variables.difference(prec_sym_names)
if non_prec_vars:
names = sorted(non_prec_vars)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why was this change needed?

Copy link
Member Author

Choose a reason for hiding this comment

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

SymbolTable.precision_datasymbols collects the Symbols referred to by the precision property (if any) of all Symbols in the table. This problem must have arisen because we have added new symbols that refer to a precision symbol from another table. I will investigate as it would be better if those references were updated.

Copy link
Member Author

Choose a reason for hiding this comment

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

Probably we're missing a call to update_symbols_using or similar.

Copy link
Member Author

Choose a reason for hiding this comment

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

I have 'fixed' this within KernelModuleInlineTrans but I'm still not happy - I suspect the problem is originating earlier so I will do some further investigation.

@pytest.mark.usefixtures("kernel_outputdir")
def test_kernelimportstoargumentstrans(monkeypatch):
def test_kernelimportstoargumentstrans(monkeypatch, fortran_writer):
''' Check the KernelImportsToArguments transformation with a single kernel
Copy link
Collaborator

Choose a reason for hiding this comment

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

The monkeypatch argument is unused now

assert isinstance(kschedule.symbol_table.lookup("xstart").interface,
ArgumentInterface)
assert isinstance(kschedule.symbol_table.lookup("xstop").interface,
assert isinstance(kschedule.symbol_table.lookup("xstop_1").interface,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why has this changed? I am a bit worried about this one because if the call had argument names, this would not match anymore.

Comment on lines +77 to +80
@pytest.fixture(name="mod_inline_trans")
def make_mod_inline_trans() -> KernelModuleInlineTrans:
'''Creates and returns a KernelModuleInlineTrans transformation.'''
return KernelModuleInlineTrans()
Copy link
Collaborator

Choose a reason for hiding this comment

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

This seems unnecessary

[-l {off,all,output}] [-p {invokes,routines,kernels}]
[-o OUTPUT_FILE] [-api DSL] [-oalg OUTPUT_ALGORITHM_FILE] [-opsy OUTPUT_PSY_FILE]
[-okern OUTPUT_KERNEL_PATH] [-dm] [-nodm]
[--kernel-renaming {multiple,single}]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Also clean these please:

doc/user_guide/transformations.rst
582:two different kernel-renaming schemes: "multiple" and "single"
583:(specified via the ``--kernel-renaming`` command-line flag). In the

doc/user_guide/getting_going.rst
179:                    [--kernel-renaming {multiple,single}]
223:      --kernel-renaming {multiple,single}

'''
:returns: whether or not this kernel is being module-inlined.
:rtype: bool
def module_inline(self) -> bool:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe another TODO for 2054 saying that it subclasses Call, this probably should live in the super class

kernel.symbol_table.swap(imported_var, updated_sym)

if updated_sym in kernel.symbol_table.precision_datasymbols:
if updated_sym.name.lower() in precision_sym_names:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why was this changed?

@arporter
Copy link
Member Author

Unfortunately, my change to ScopingNode.replace_symbols_using means that any local symbol that shadows an outer one gets replaced by the outer one. The problem I wanted to fix was where a local symbol depends on a symbol in an outer scope during a tree-copy operation. Child nodes are only attached into the new (copied) tree at the end of the copy operation - prior to that they can't see the parent scope. Therefore, only at this point can we update any references to symbols in the outer scope.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants