Skip to content
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

Only compute if method returns a constant when needed #1734

Merged
merged 17 commits into from
Jan 11, 2021

Conversation

vitek-karas
Copy link
Member

This changes how the RemoveUnreachableBlocksStep computes if a method returns a constant or not. Previously we would go over all methods and detect those which return constants (and store only those in a dictionary). Then we would proceed with branch removal relying on this dictionary.

For a hello world console app this means we ran the detection of constants on almost 50K methods. On the other hand the dictionary stored only about 1.5K records (actually constant methods).

With this change the constant detection only runs on methods we need the result for later on. This means the dictionary stores records for all methods asked about (null value represents "We checked, and it's not constant").

For the same hello world console app we now run the detection only on ~5K methods (10x less). On the other hand we have records for all (5K -> 3x increase). So this trades CPU for memory.

The purpose of this change is not the CPU/memory tradeoff, it's to prepare the constant propagation to make it possible to call it on-demand per-method from MarkStep which will be needed once we switch over to the current lazy-loading of assemblies.

This is a just a first step in this process described by #1733.

Just store results for all methods (not just those with constant value). Will be needed once the const detection is done on-demand (to detect which methods were already processed).
Basically computation if method is constant is now always done on-demand.
For various reasons we can't propagate constant return values from many methods. Basically we only allow parameterless static methods - with some exceptions.

There's no point asking about constant return value for methods which won't be able to propagate the value further.
@vitek-karas vitek-karas added this to the .NET 6.0 milestone Jan 8, 2021
@vitek-karas vitek-karas requested a review from sbomer January 8, 2021 14:13
@vitek-karas vitek-karas self-assigned this Jan 8, 2021
@@ -17,81 +17,68 @@ namespace Mono.Linker.Steps
public class RemoveUnreachableBlocksStep : BaseStep
{
Dictionary<MethodDefinition, Instruction> constExprMethods;
int constExprMethodsAdded;
Copy link
Contributor

Choose a reason for hiding this comment

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

Cannot this be bool value?

Copy link
Member

@sbomer sbomer left a comment

Choose a reason for hiding this comment

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

LGTM modulo the case we discussed where a constant-returning method has conflicting substitutions

If method returns a constant value but substitutions overrides it to a different value - in some cases the constant propagation might end up using the value from the method body and not from the substitution.

This change fixes that
@vitek-karas
Copy link
Member Author

This change also "fixes" a bug - if the IPConstantPropagation feature was disabled, substitutions would still work for the first level of propagation. After this change, even the first level propagation requires the IPContantPropagation to be turned on.

Note that this has nothing to do with the replacement of the method bodies in substitutions, those work regardless of the options.

@vitek-karas vitek-karas merged commit 17db5ef into dotnet:master Jan 11, 2021
@vitek-karas vitek-karas deleted the ConstantMethodDetectionOnDemand branch January 11, 2021 12:35
vitek-karas added a commit to vitek-karas/linker that referenced this pull request Jan 13, 2021
In dotnet#1734 a change was made that substitutions are only considered for methods which are not instrinsic or no-inline. That is not how it should work, even intrinsic or no-inline methods should still allow substitutions and constant propagation from those.

What instrinsic and no-inline methods should not do is participate in constant propagation as intermediate methods (so methods which become constant because they're calling other constant methods).

In short substitutions effectively override the intrinsic/no-inline.

Added test cases.
vitek-karas added a commit that referenced this pull request Jan 13, 2021
In #1734 a change was made that substitutions are only considered for methods which are not intrinsic or no-inline. That is not how it should work, even intrinsic or no-inline methods should still allow substitutions and constant propagation from those.

What intrinsic and no-inline methods should not do is participate in constant propagation as intermediate methods (so methods which become constant because they're calling other constant methods).

In short substitutions effectively override the intrinsic/no-inline.

Added test cases.

Fixes #1747
agocke pushed a commit to dotnet/runtime that referenced this pull request Nov 16, 2022
…1734)

This changes how the `RemoveUnreachableBlocksStep` computes if a method returns a constant or not. Previously we would go over all methods and detect those which return constants (and store only those in a dictionary). Then we would proceed with branch removal relying on this dictionary.

For a hello world console app this means we ran the detection of constants on almost 50K methods. On the other hand the dictionary stored only about 1.5K records (actually constant methods).

With this change the constant detection only runs on methods we need the result for later on. This means the dictionary stores records for all methods asked about (`null` value represents "We checked, and it's not constant").

For the same hello world console app we now run the detection only on ~5K methods (10x less). On the other hand we have records for all (5K -> 3x increase). So this trades CPU for memory.

The purpose of this change is not the CPU/memory tradeoff, it's to prepare the constant propagation to make it possible to call it on-demand per-method from `MarkStep` which will be needed once we switch over to the current lazy-loading of assemblies.

Commit migrated from dotnet/linker@17db5ef
agocke pushed a commit to dotnet/runtime that referenced this pull request Nov 16, 2022
In dotnet/linker#1734 a change was made that substitutions are only considered for methods which are not intrinsic or no-inline. That is not how it should work, even intrinsic or no-inline methods should still allow substitutions and constant propagation from those.

What intrinsic and no-inline methods should not do is participate in constant propagation as intermediate methods (so methods which become constant because they're calling other constant methods).

In short substitutions effectively override the intrinsic/no-inline.

Added test cases.

Fixes dotnet/linker#1747

Commit migrated from dotnet/linker@fc8abef
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.

3 participants