-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Adding some new functions to System.Math and System.MathF #20788
Changes from 3 commits
8cb0330
fb14c5e
11a3d1e
e527d7e
0a613b3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,6 +36,73 @@ public static float Abs(float x) | |
| return Math.Abs(x); | ||
| } | ||
|
|
||
| public static float BitDecrement(float x) | ||
| { | ||
| var bits = BitConverter.SingleToInt32Bits(x); | ||
|
|
||
| if ((bits & 0x7F800000) >= 0x7F800000) | ||
| { | ||
| // NaN returns NaN | ||
| // -Infinity returns -Infinity | ||
| // +Infinity returns float.MaxValue | ||
| return (bits == 0x7F800000) ? float.MaxValue : x; | ||
| } | ||
|
|
||
| if (bits == 0x00000000) | ||
| { | ||
| // +0.0 returns -float.Epsilon | ||
| return -float.Epsilon; | ||
| } | ||
|
|
||
| // Negative values need to be incremented | ||
| // Postiive values need to be decremented | ||
|
|
||
| bits += ((bits < 0) ? +1 : -1); | ||
| return BitConverter.Int32BitsToSingle(bits); | ||
| } | ||
|
|
||
| public static float BitIncrement(float x) | ||
| { | ||
| var bits = BitConverter.SingleToInt32Bits(x); | ||
|
|
||
| if ((bits & 0x7F800000) >= 0x7F800000) | ||
| { | ||
| // NaN returns NaN | ||
| // -Infinity returns float.MinValue | ||
| // +Infinity returns +Infinity | ||
| return (bits == unchecked((int)(0xFF800000))) ? float.MinValue : x; | ||
| } | ||
|
|
||
| if (bits == unchecked((int)(0x80000000))) | ||
| { | ||
| // -0.0 returns float.Epsilon | ||
| return float.Epsilon; | ||
| } | ||
|
|
||
| // Negative values need to be decremented | ||
| // Postiive values need to be incremented | ||
|
|
||
| bits += ((bits < 0) ? -1 : +1); | ||
| return BitConverter.Int32BitsToSingle(bits); | ||
| } | ||
|
|
||
| public static unsafe float CopySign(float x, float y) | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was looking at the codegen for this method: ; Assembly listing for method MathF:CopySign(float,float):float
; Emitting BLENDED_CODE for X64 CPU with AVX - Windows
; optimized code
; rsp based frame
; partially interruptible
; Final local variable assignments
;
; V00 arg0 [V00,T03] ( 4, 3.50) float -> mm0
; V01 arg1 [V01,T04] ( 3, 3 ) float -> mm1
; V02 loc0 [V02,T00] ( 3, 2.50) int -> rax
; V03 loc1 [V03,T01] ( 2, 2 ) int -> rdx
;# V04 OutArgs [V04 ] ( 1, 1 ) lclBlk ( 0) [rsp+0x00] "OutgoingArgSpace"
; V05 tmp1 [V05,T05] ( 2, 4 ) float -> [rsp+0x14] do-not-enreg[F] ld-addr-op "Inlining Arg"
; V06 tmp2 [V06,T06] ( 2, 4 ) float -> [rsp+0x10] do-not-enreg[F] ld-addr-op "Inlining Arg"
; V07 tmp3 [V07,T02] ( 2, 2 ) int -> [rsp+0x0C] do-not-enreg[F] ld-addr-op "Inlining Arg"
;
; Lcl frame size = 24
G_M7953_IG01:
sub rsp, 24
vzeroupper
G_M7953_IG02:
vmovss dword ptr [rsp+14H], xmm0
mov eax, dword ptr [rsp+14H]
vmovss dword ptr [rsp+10H], xmm1
mov edx, dword ptr [rsp+10H]
xor edx, eax
test edx, edx
jge SHORT G_M7953_IG04
xor eax, 0xD1FFAB1E
mov dword ptr [rsp+0CH], eax
vmovss xmm0, dword ptr [rsp+0CH]
G_M7953_IG03:
add rsp, 24
ret
G_M7953_IG04:
add rsp, 24
ret
; Total bytes of code 61, prolog size 7 for method MathF:CopySign(float,float):float
; ============================================================
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The following, which is produced from vmovss dword ptr [rsp+14H], xmm0
mov eax, dword ptr [rsp+14H]Could be: movd eax, xmm0
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The following, which is produced by xor edx, eax
test edx, edx
jge SHORT G_M7953_IG04Could be: xor edx, eax
jns SHORT G_M7953_IG04
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The following, which is produced from BitConverter.Int32BitsToSingle mov dword ptr [rsp+0CH], eax
vmovss xmm0, dword ptr [rsp+0CH]Could be: vmovd xmm0, eax
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This means we should be generating something closer to the following, if possible: G_M7953_IG01:
vmovd eax, xmm0
vmovd edx, xmm1
xor edx, eax
jns SHORT G_M7953_IG02
xor eax, 0xD1FFAB1E
vmovd xmm0, eax
G_M7953_IG02:
retThere was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Right, there is no transition penalty in VEX encoding, but we insert
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The architecture optimization manual seems to imply that there is no transition penalty when going from legacy 128-bit instructions to VEX-encoded 128-bit instructions (or vice-versa). Only when going from legacy 128-bit instructions to VEX-encoded 256-bit instructions (and that you avoid the penalty by using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I see. There is a penalty on Broadwell and prior when going from |
||
| { | ||
| var xbits = BitConverter.SingleToInt32Bits(x); | ||
| var ybits = BitConverter.SingleToInt32Bits(y); | ||
|
|
||
| // If the sign bits of x and y are not the same, | ||
| // flip the sign bit of x and return the new value; | ||
| // otherwise, just return x | ||
|
|
||
| if (((xbits ^ ybits) >> 31) != 0) | ||
| { | ||
| return BitConverter.Int32BitsToSingle(xbits ^ int.MinValue); | ||
| } | ||
|
|
||
| return x; | ||
| } | ||
|
|
||
| public static float IEEERemainder(float x, float y) | ||
| { | ||
| if (float.IsNaN(x)) | ||
|
|
@@ -118,12 +185,22 @@ public static float Max(float x, float y) | |
| return Math.Max(x, y); | ||
| } | ||
|
|
||
| public static float MaxMagnitude(float x, float y) | ||
| { | ||
| return Max(Abs(x), Abs(y)); | ||
| } | ||
|
|
||
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
| public static float Min(float x, float y) | ||
| { | ||
| return Math.Min(x, y); | ||
| } | ||
|
|
||
| public static float MinMagnitude(float x, float y) | ||
| { | ||
| return Min(Abs(x), Abs(y)); | ||
| } | ||
|
|
||
| [Intrinsic] | ||
| public static float Round(float x) | ||
| { | ||
|
|
@@ -214,22 +291,5 @@ public static unsafe float Truncate(float x) | |
| ModF(x, &x); | ||
| return x; | ||
| } | ||
|
|
||
| private static unsafe float CopySign(float x, float y) | ||
| { | ||
| var xbits = BitConverter.SingleToInt32Bits(x); | ||
| var ybits = BitConverter.SingleToInt32Bits(y); | ||
|
|
||
| // If the sign bits of x and y are not the same, | ||
| // flip the sign bit of x and return the new value; | ||
| // otherwise, just return x | ||
|
|
||
| if (((xbits ^ ybits) >> 31) != 0) | ||
| { | ||
| return BitConverter.Int32BitsToSingle(xbits ^ int.MinValue); | ||
| } | ||
|
|
||
| return x; | ||
| } | ||
| } | ||
| } | ||





Uh oh!
There was an error while loading. Please reload this page.