Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Updating jit/valuenum to properly handle the single-precision versions of the math intrinsics.#9363

Merged
tannergooding merged 3 commits into
dotnet:masterfrom
tannergooding:math-intrinsics
Feb 23, 2017
Merged

Updating jit/valuenum to properly handle the single-precision versions of the math intrinsics.#9363
tannergooding merged 3 commits into
dotnet:masterfrom
tannergooding:math-intrinsics

Conversation

@tannergooding
Copy link
Copy Markdown
Member

@tannergooding
Copy link
Copy Markdown
Member Author

FYI. @JosephTremoulet

Comment thread src/jit/valuenum.cpp Outdated
{
assert(IsVNConstant(argVN));
var_types argVNtyp = TypeOfVN(argVN);
assert(varTypeIsFloating(argVNtyp));
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

ValueNumStore::GetConstantDouble currently returns for both float and double constants. This means in some cases we are upcasting, executing some code, and then downcasting back to float.

After the reworking of EvalMathFuncUnary there are still a couple of places where this is happening (a simple search for GetConstantDouble in this file will show them). These calls could probably be rewritten to no longer up/down cast, but I would like some input before I do that work.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Yeah... in fact, it looks like we're already (without this change) constant-folding the single-precision intrinsics, just doing it by widening to double and evaluating and truncating back down, is that right? The language in the spec certainly seems to give us the liberty to do that (I.12.1.3). I'm inclined to say that we should either go ahead and make this change for all constant-folding on fp ops or not make this change, to keep things consistent.

I'm not sure whether it's best to continue folding at double precision or to switch to single. I'd think we'd want to minimize differences between optimized and unoptimized code's results, and I think the unoptimized code would end up happening at whatever precision our back-end uses for singles, which maybe has a greater chance of matching the C++ compiler's handling of float than of double, which would argue for continuing this change... but I'm no floating-point expert. Maybe someone else wants to chime in. @sivarv? @CarolEidt?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah... in fact, it looks like we're already (without this change) constant-folding the single-precision intrinsics, just doing it by widening to double and evaluating and truncating back down, is that right?

Yes, which can result in lower performance and different computed results for the new System.MathF functions.

The language in the spec certainly seems to give us the liberty to do that (I.12.1.3).

I believe that most consumers of the single-precision functions would rather have the speed than the additional precision (including any additional precision retained by upcasting, computing, and downcasting).

I'd think we'd want to minimize differences between optimized and unoptimized code's results

I agree, and my understanding is that 'internal representation' is a platform agnostic way of saying whatever form the CPU accepts (so 80-bits when using the x87 FPU, for example). I think that using the C type names (float and double), calling the appropriate versions of the functions (sqrtf and sqrt, respectively), and then letting the native runtime handle the internal implementation details is the best way to go here.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@tannergooding, your reasoning sounds good to me; I'd say go ahead with this and the other instances.

Copy link
Copy Markdown

@JosephTremoulet JosephTremoulet left a comment

Choose a reason for hiding this comment

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

@dotnet/jit-contrib

Comment thread src/jit/valuenum.cpp Outdated

float result = 0;

switch (argVNtyp)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

argVNTyp is only used in an assert and in a single-case switch with an unreached default case, which effectively asserts the same thing again. I'd suggest getting rid of argVNTyp (use TypeOfVN(argVN) in the assertion) and simplifying away the switch.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed.

Comment thread src/jit/valuenum.cpp Outdated
assert(typ == TypeOfVN(arg0VN));

// If the math intrinsic is not implemented by target-specific instructions, such as implemented
// by user calls, then don't do constant folding on it. This minimizes precision loss.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ISTM this comment was explaining why && Compiler::IsTargetIntrinsic(gtMathFN) was included in the now-outer conditional; please move it back out.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed

Comment thread src/jit/valuenum.cpp Outdated
assert(typ == TypeOfVN(arg0VN));

// If the math intrinsic is not implemented by target-specific instructions, such as implemented
// by user calls, then don't do constant folding on it. This minimizes precision loss.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ditto re: comment placement

Comment thread src/jit/valuenum.cpp Outdated

return VNForIntCon(int(res));
int res = 0;
if (gtMathFN == CORINFO_INTRINSIC_Round)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This if and the unreached() in its else branch are redundant with the assertion 3 lines above. I'd probably let the assertion do the talking (maybe add a comment that Round is the only intrinsic with fp args and a non-fp result) and get rid of the if/else.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed.

Comment thread src/jit/valuenum.cpp Outdated
{
assert(IsVNConstant(argVN));
var_types argVNtyp = TypeOfVN(argVN);
assert(varTypeIsFloating(argVNtyp));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Yeah... in fact, it looks like we're already (without this change) constant-folding the single-precision intrinsics, just doing it by widening to double and evaluating and truncating back down, is that right? The language in the spec certainly seems to give us the liberty to do that (I.12.1.3). I'm inclined to say that we should either go ahead and make this change for all constant-folding on fp ops or not make this change, to keep things consistent.

I'm not sure whether it's best to continue folding at double precision or to switch to single. I'd think we'd want to minimize differences between optimized and unoptimized code's results, and I think the unoptimized code would end up happening at whatever precision our back-end uses for singles, which maybe has a greater chance of matching the C++ compiler's handling of float than of double, which would argue for continuing this change... but I'm no floating-point expert. Maybe someone else wants to chime in. @sivarv? @CarolEidt?

@tannergooding
Copy link
Copy Markdown
Member Author

Updated to handle all but one case where we are upcasting float to double when performing evaluations.

The remaining case is in Compiler::fgValueNumberTreeConst where it downcasts:

tree->gtVNPair.SetBoth(vnStore->VNForFloatCon((float)tree->gtDblCon.gtDconVal));

I'm taking a closer look at the code in question there to see if that is feasible to include here as well.

@tannergooding
Copy link
Copy Markdown
Member Author

@JosephTremoulet, this should be good for a final review pass now.

Copy link
Copy Markdown

@JosephTremoulet JosephTremoulet left a comment

Choose a reason for hiding this comment

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

LGTM, thanks for taking care of this.

@tannergooding
Copy link
Copy Markdown
Member Author

@JosephTremoulet, thanks. Do I need any further sign-off here before merging?

@JosephTremoulet
Copy link
Copy Markdown

Do I need any further sign-off here before merging?

No, go ahead.

@tannergooding tannergooding merged commit 116752f into dotnet:master Feb 23, 2017
@karelz karelz modified the milestone: 2.0.0 Aug 28, 2017
@tannergooding tannergooding deleted the math-intrinsics branch January 17, 2018 01:54
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
…sics

Updating jit/valuenum to properly handle the single-precision versions of the math intrinsics.

Commit migrated from dotnet/coreclr@116752f
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provide the appropriate intrinsic implementations for specific single-precision math functions

4 participants