[GR-43361] [GR-50205] Whole-Program Sparse Conditional Constant Propagation #9821
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR implements Whole-Program Sparse Conditional Constant Propagation (WP-SCCP) as an extensions of the points-to analysis in Native Image.
In a short summary, this PR adds predicate edges to the typeflow graph and introduces new flows for representing simple operations on primitive values, e.g.
PrimitiveFilterTypeFlow
. For scalability, primitives are modelled by a very simple lattice with Empty, Constant values and Any, seePrimitiveTypeState
for details. No sets or intervals yet.WP SCCP is hidden behind flags
-H:+TrackPrimitiveValues
and-H:+UsePredicates
, which will be disabled by default, but we plan to enable them in near future.Most Notable Changes
PointstoOptions.TrackPrimitiveValues
is extended with new types of flows.PointstoOptions.UsePredicates
is introduced, but disabled by default (depends onTrackPrimitiveValues
).-H:+TrackPrimitiveValues
and-H:+UsePredicates
. The rest of the description applies only when you enable these two flags, otherwise there should be no observable differences in terms of how the analysis behaves.TypeFlow
nodes are now separated into two categories: local and global. Local is the default, and global ones, e.g.AllInstantiatedTypeFlow
, implement a markerGlobalFlow
interface.TypeFlow
nodes are disabled by default, i.e. they can receive updates from their dependencies, but they do not propagate anything further until they are enabled.predicate
edge is introduced into the typeflow graph.predicate
edge.ConditionalFlow
for aConditionalNode
.AnyPrimitiveSourceTypeFlow
, which, once enabled, cause immediate saturation of all their enabled usages.Evaluation
When benchmarking the enterprise non-pgo configuration, we have observed a reduction in binary size across all our benchmarks without impacting the build time. The same should apply for the other configurations.
Potential Risks
I divide the risks into internal and external from the point of view of the analysis.
Internal
The biggest internal risk are concurrency issues, which could result in non-deterministic builds and transient gate failures. The analysis is massively parallel and it is quite easy to introduce a data race or an atomicity violation resulting in a missed update. To mitigate this risk, I've run the whole gate infrastructure multiple times (apologies to the CI team), went through all the key methods manually and currently I am experimenting with noise insertion, but that of course does not fully prove an absence of these bugs, since they can manifest rarely.
Other risks are potential increase in analysis time and/or memory consumption, which is answered in the evaluation.
External
Missing Information
The biggest external risk is missing information about fields or methods that behave in a way the analysis cannot understand without explicit configuration. Missing
UnknownPrimitiveField
andUnknownObjectField
annotations or forgetting to mark a method asopaqueReturn
fall into this category.However, another dependency can be seen for example in the
TruffleFeature.beforeAnalysis
which marks a set of methods as root and assume that the rest of Truffle will be always reachable (so in a way depends on an imprecision of the analysis) orTruffleBaseFeature.registerUnsafeAccess
which does an optimization that is aguably not completely correct, but the issue cannot manifest in anything except from artificial little Truffle images that end up not running any Truffle language.Overall, the SVM code has to be analysis-aware and always provide correct information about all 'opaque' usages and ideally also verify that the analysis results make sense (e.g.
TruffleFeature
could perform some check ensuring all the classes are truly reachable, turn the implicit assumption into an explicit one). I'd like to note that this statement was true before the changes in the PR, but the increased precision and the propagation of primitive values make it even more important.Compiler Optimizations
Another external risk is the impact of this PR on compiler optimizations. Applying the results of the analysis reduces the amount of reachable methods and has an impact on the structure and size of the ones that remain reachable (more constant folding and pruning of unreachable branches). These changes can results e.g. in different inlining decisions.
Review
For the review, it is probably best to go as follows:
Extensions
Some ideas that can and possibly will be done in a follow up:
MethodTypeFlowBuilder.registerUsedElements
. For example fields load and stores should be quite straightforward. Constants might be a bit harder, but I have an approach for them as well.