mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
52b617a6dd
These are the elementary steps of the DataLayoutAnalysis (that is still to be defined), along with a manager to handle them, their dependencies, their executions and their invalidations. In principle, this design could have been implemented inheriting from `llvm::Pass` and `llvm::legacy::PassManager` (or `llvm::PassInfoMixin` and `llvm::PMDataManager` for the new step manager). However, LLVM's passes and managers provide far more complex features than we need for now, so I decided to keep it simple and roll our own for now. We could potentially switch to LLVM stuff later if we need their power. Some examples of features we don't need for now are: - capability to pass results from a pass to another that depends on it - capability to dynamically compute pass dependencies - capability to dynamically invalidate passes If some of these become necessary in future, it's a sign that it might be time to switch to an LLVM-based design The design is structured as follows. 1) Adding `Step`s to the `StepManager` The `StepManager` owns the `Step`s, that can be added via the `addStep` method. Whenever a new `Step` is added, four properties are checked: - that all its dependencies have already been added before it; - that non of its dependencies have been invalidated by the insertion of another step that invalidate them. - that it does not depend on itself - that it does not invalidate itself If any of these conditions fail, the `Step` is not added successfully. Whenever a new `Step` A is added and it invalidates any `Step` B, the last instance of B added to the `StepManager` before A (if present) is marked as invalidated. If one wants to add a new `Step` C that depends on B, it will be necessary to explicitly add a new instance of A (say A*) before adding C. Otherwise, there will be no guarantee that an instance of A executes before C without being invalidated. These conditions on invalidations are restrictive but the allow to specify the dependencies and invalidations that we need for now. If it turns out we need more complex dependencies and invalidations we should explore implementing the LLVM-based design. 2) Executing the added `Step`s After adding the `Step`s to the `StepManger`, they can be executed all together with the `dla::StepManger::run()` method. This method runs all the steps in the order they were added by the user with calls to `addStep`. The fact that `addStep` strictly ensures that dependencies and invalidations are respected, guarantees that the execution always works in the order of `Step`s specified by the user. It also means that there is no need to check and propagate invalidations across dependencies between the execution of the `Step`s, because there is the guarantee that if a `Step` A invalidates `Step` B, another instance of B will be executed later if some `Step` C needs it, or if the user has added it explicitly. When the `dla::StepManager::run()` method returns, all the `Step`s that were successfully added to the manager have finished running. 3) Implementing a `Step` Each `Step` has a virtual `runOnTypeSystem` method, that executes the `Step` and returns true if some change was made, false otherwise. `TypeSystem` for now is just a forward declaration and all the implementations of `runOnTypeSystem` simply return true.