Skip to content

Constant Propagation Transform#515

Draft
Andrew-Beggs-ECMWF wants to merge 28 commits intoecmwf-ifs:mainfrom
Andrew-Beggs-ECMWF:naab-const-prop-transform
Draft

Constant Propagation Transform#515
Andrew-Beggs-ECMWF wants to merge 28 commits intoecmwf-ifs:mainfrom
Andrew-Beggs-ECMWF:naab-const-prop-transform

Conversation

@Andrew-Beggs-ECMWF
Copy link
Contributor

@Andrew-Beggs-ECMWF Andrew-Beggs-ECMWF commented Mar 18, 2025

Putting here for visibility and getting the CI to run. Still WIP (including this description).

Adds:

  1. Constant Propagation Analysis
  • ConstantPropagationAnalysis
  1. Constant Propagation Transformation
  • ConstantPropagationTransformer

Changes:

  1. Analysers now inherit from the abstract AbstractDataflowAnalysis
  • This is instead of there only being analyse_dataflow, which is now under DataFlowAnalysis
  • Introduces a standardise format for analysers

Todo:

  • Write todos

This commit adds AbstractDFA and the concrete implementation of LiveVariableAnalysis. LiveVariableAnalysis replaces DataFlowAnalysis, and is simply a rename from the user's perspective. Internally, everything has been brought under one class (with the use of inner classes) and makes use of AbstractDFA.

The goal is that other forms of DFA will follow and use this pattern as a common interface.
This is to better reflect existing patterns & functionality.
# Conflicts:
#	loki/transformations/extract/outline.py
ConstantPropagationAnalysis.py -> constant_propagation_analysis
AbstractDFA.py -> abstract_dfa.py
DataFlowAnalysis.py -> data_flow_analysis.py
The following loop may never be taken. However previously `a` would have been propagated, resulting in an erroneous print of 5 - instead of the correct 0.

`a = 0
do i = 1, randomInteger
  a = 5
end do

print *, a`
`_pop_array_accesses` will now be able to cope with arrays that have non-literal indices and shapes. This is done by partially matching the access and pop any candidates from the consts map.

E.g. foo(1,bar,3) matches foo(1,2,3) and foo(1,1,3) in the map [foo(1,2,3), foo(1,1,3), foo(1,1,1)]
Loki can now better tell if a loop is taken at least once, might be taken, or is never taken and can update the const map accordingly.
This does two things:
  1. Fix statically known never taken bodies not being propagated
  2. Hoist loop independent variables
Sorry for the mega commit. I wanted to get the tests stable before clogging up my git log.
Copy link
Collaborator

@reuterbal reuterbal left a comment

Choose a reason for hiding this comment

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

Thanks, at first glance this looks promising! I like the refactoring ideas around the dataflow analysis.

I've left a first few comments on stylistic choices, but I haven't looked in detail at the implementation, yet. Since this PR mixes refactoring the dataflow analysis with a new transformation, could we maybe split the contributions and have first a separate PR with the DFA refactoring that only applies the plumbing without any new features? That would help with the review because right now it's hard to see what's new and what's just moved around.

self.get_detacher().visit(module_or_routine.body)

@contextmanager
def dataflow_analysis_attached(self, module_or_routine):
Copy link
Collaborator

Choose a reason for hiding this comment

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

I understand the rationale for embedding this inside the class to directly relate to the implementation of the specific DFA class. However, I'd prefer to also keep the current API with a class-free contextmanager. This could instead receive an optional argument dfa=None or so, which by default will use the previous DFA implementation:

@contextmanager
def dataflow_analysis_attached(self, module_or_routine, dfa=None):
    if dfa is None:
        from loki.analyse.dataflow_analysis import DataflowAnalysis # pylint: disable=no-toplevel-import
        dfa = DataFlowAnalysis()
    dfa.attach_dataflow_analysis(module_or_routine)
    yield
    dfa.detach_dataflow_analysis(module_or_routine)

"""

from loki.analyse.analyse_dataflow import * # noqa
from loki.analyse.data_flow_analysis import * # noqa
Copy link
Collaborator

Choose a reason for hiding this comment

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

Missing import:

Suggested change
from loki.analyse.data_flow_analysis import * # noqa
from loki.analyse.constant_propagation_analysis import * # noqa
from loki.analyse.data_flow_analysis import * # noqa


__all__ = ['AbstractDataflowAnalysis']

class AbstractDataflowAnalysis(Transformer, ABC):
Copy link
Collaborator

Choose a reason for hiding this comment

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

A few docstrings would be useful here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's call this dataflow_analysis, to be consistent with the naming elsewhere.

'loop_carried_dependencies'
]

class DataFlowAnalysis(AbstractDataflowAnalysis):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, please use DataflowAnalysis to be consistent with baseclass and use elsewhere.


__all__ = ['AbstractDataflowAnalysis']

class AbstractDataflowAnalysis(Transformer, ABC):
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not following why this needs to inherit from Transformer, given that the actual transformers are _Attacher and _Detacher and inheriting themselves.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants