Skip to content

Avoid checking HasValue in nullable comparison for non-default constants#60405

Closed
astroC86 wants to merge 3 commits intodotnet:mainfrom
astroC86:optimize-hasvalue
Closed

Avoid checking HasValue in nullable comparison for non-default constants#60405
astroC86 wants to merge 3 commits intodotnet:mainfrom
astroC86:optimize-hasvalue

Conversation

@astroC86
Copy link
Copy Markdown
Contributor

@astroC86 astroC86 commented Mar 26, 2022

Fixes #52629

@RikkiGibson for review

  • User defined operators were not considered. (I can try to move the new logic into TrivialLiftedComparisonOperatorOptimizations so it's shared between user-defined operators and built-in operators)

@astroC86 astroC86 requested a review from a team as a code owner March 26, 2022 22:30
@ghost ghost added Community The pull request was submitted by a contributor who is not a Microsoft employee. Area-Compilers labels Mar 26, 2022
@RikkiGibson RikkiGibson self-assigned this Mar 27, 2022
@Youssef1313
Copy link
Copy Markdown
Member

Maybe we don't need anything for user-defined operators? @RikkiGibson can you confirm?

compVerifier.VerifyIL("C.M2(int?)", @"
{
// Code size 23 (0x17)
// Code size 15 (0xf)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Given the behavior of M1 versus M2 in this test, perhaps we should file an item separately for optimizing out unnecessary 'HasValue' checks in patterns.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I opened #60413

Comment on lines 991 to 992
// result = (tempx.GetValueOrDefault() OP tempy.GetValueOrDefault()) &
// (tempx.HasValue OP tempy.HasValue)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Unrelated to the changes. @RikkiGibson Do you know why this is a bitwise AND instead of logical AND? Wouldn't that evaluate both sides and be slower? or there are other aspects I'm not aware of?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think because we're just reading two fields here, it's faster to always do both reads than to branch on the value of the left operand.

var canOmitHasValueCheck = yNonNull is { ConstantValue.IsDefaultValue: false } || xNonNull is { ConstantValue.IsDefaultValue: false };

// result = (tempx.GetValueOrDefault() OP tempy.GetValueOrDefault()) &
// (tempx.HasValue OP tempy.HasValue)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

OP

This doesn't look right for a general case.

}
}
";
CompileAndVerify(code).VerifyDiagnostics().VerifyIL("C.M", @"
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Mar 28, 2022

Choose a reason for hiding this comment

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

CompileAndVerify(code)

I think we should verify runtime behavior as well. Execute the code and test result of M with:

  • null input
  • 42
  • not 42
  • 0

}
}
";
CompileAndVerify(code).VerifyDiagnostics().VerifyIL("C.M", @"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

CompileAndVerify(code)

Same comment here about verifying runtime behavior. It is probably applicable to other tests in this file as well.

}
");
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

}

I do not see any tests with a constant on the left, but it looks like the implementation is supposed to affect scenarios like that too.

method: null,
constrainedToTypeOpt: null);
BoundExpression binaryExpression;
if (canOmitHasValueCheck)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

canOmitHasValueCheck

Is this logic correct for <, <=, >, >= operators? I think we need to add tests for all comparison operators that can come through here.

@AlekseyTs
Copy link
Copy Markdown
Contributor

        BinaryOperatorKind kind,

Consider adding an assert at the beginning of the function to check what operators we expect to handle.


Refers to: src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs:894 in 92b4df7. [](commit_id = 92b4df7, deletion_comment = False)

@AlekseyTs
Copy link
Copy Markdown
Contributor

Done with review pass (commit 3)

@RikkiGibson
Copy link
Copy Markdown
Member

Hi @astroC86, please let us know if there's any way we can assist with the PR.

@jaredpar
Copy link
Copy Markdown
Member

Closing stale PR

@jaredpar jaredpar closed this Mar 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Compilers Community The pull request was submitted by a contributor who is not a Microsoft employee.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Avoid checking HasValue in nullable comparison to non-default constants

5 participants