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

Remove unsafe bool casts #111024

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft

Conversation

xtqqczze
Copy link
Contributor

@xtqqczze xtqqczze commented Jan 2, 2025

Contributes to #94941.

@xtqqczze
Copy link
Contributor Author

xtqqczze commented Jan 2, 2025

@MihuBot

@@ -1075,17 +1075,15 @@ public static explicit operator float(Half value)
// Extract exponent bits of value (BiasedExponent is not for here as it performs unnecessary shift)
uint offsetExponent = bitValueInProcess & HalfExponentMask;
// ~0u when value is subnormal, 0 otherwise
uint subnormalMask = (uint)-Unsafe.BitCast<bool, byte>(offsetExponent == 0u);
// ~0u when value is either Infinity or NaN, 0 otherwise
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this comment is incorrect

@xtqqczze
Copy link
Contributor Author

xtqqczze commented Jan 2, 2025

@tannergooding Is this beneficial? 2 bytes higher in code size, but 0.75 lower PerfScore.

 ; Assembly listing for method System.Half:op_Explicit(float):System.Half (FullOpts)
+       xor      ecx, ecx
+       mov      edx, -1
        vucomiss xmm0, xmm0
-       setp     cl
-       movzx    rcx, cl
-       dec      ecx
+       cmovnp   ecx, edx

Related: #61761 (comment)

// TODO: Replace with log2ToPow10[BitOperations.Log2(value)] once https://github.com/dotnet/runtime/issues/79257 is fixed
uint index = Unsafe.Add(ref MemoryMarshal.GetReference(log2ToPow10), BitOperations.Log2(value));
nint elementOffset = Unsafe.Add(ref MemoryMarshal.GetReference(log2ToPow10), BitOperations.Log2(value));
Copy link
Member

@EgorBo EgorBo Jan 2, 2025

Choose a reason for hiding this comment

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

why nint isn't a sign rather than zero extension. Also, this looks like a hack that JIT should do, is it really needed? I know we do it in other places, but ideally it should be handled by JIT (and we move into that direction)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's a zero-extension from byte. We could use nuint instead, with some extra casts, which in any case would have no impact on code generation.

Copy link
Member

Choose a reason for hiding this comment

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

have you checked that it comes with codegen improvements? if not (or it's not clear whether it brings any benefits) let's revert it. We don't want to pollute our codebase with hacks which often becomes unnecessary eventually.

Copy link
Member

Choose a reason for hiding this comment

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

or at least remove the comment

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Using early-extension does provide a code generation improvement, e.g.

; Assembly listing for method System.Int128:TryFormat(System.Span`1[ushort],byref,System.ReadOnlySpan`1[ushort],System.IFormatProvider):ubyte:this (FullOpts)
        mov      rdx, 0xD1FFAB1E      ; static handle
        movzx    rdi, byte  ptr [rsi+rdx]
-       mov      esi, edi
-       mov      rdx, 0xD1FFAB1E      ; static handle
-       cmp      rax, qword ptr [rdx+8*rsi]
+       mov      rsi, 0xD1FFAB1E      ; static handle
+       cmp      rax, qword ptr [rsi+8*rdi]

But it is not dependant on using nint vs nuint.

Copy link
Member

@EgorBo EgorBo left a comment

Choose a reason for hiding this comment

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

LGTM otherwise, thanks!. Wonder if we have more such bool <--> int unsafe conversions

@xtqqczze
Copy link
Contributor Author

xtqqczze commented Jan 3, 2025

LGTM otherwise, thanks!. Wonder if we have more such bool <--> int unsafe conversions

These were the only conversions I found searching for:

  • Unsafe.As<bool
  • Unsafe.BitCast<bool
  • *(byte*)&
  • *(sbyte*)&

@@ -24,8 +24,9 @@ public static int CountDigits(ulong value)
];
Debug.Assert(log2ToPow10.Length == 64);

// We use 'nint' because it gives us a free early zero-extension to 64 bits when running on a 64-bit platform.
Copy link
Contributor Author

@xtqqczze xtqqczze Jan 3, 2025

Choose a reason for hiding this comment

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

Suggested change
// We use 'nint' because it gives us a free early zero-extension to 64 bits when running on a 64-bit platform.
// We use a native-sized integer
// because it gives us a free early zero-extension to 64 bits when running on a 64-bit platform.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
community-contribution Indicates that the PR has been added by a community member needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants