-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
[API Proposal]: An official way to determine whether the given value is JIT-time constant or not #98153
Comments
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch Issue DetailsBackground and motivation[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static bool IsConstant(int value)
=> Vector128.CreateScalarUnsafe(value - ~value).GetElement(1) != 0; L0000: vzeroupper
L0003: mov eax, ecx
L0005: not eax
L0007: sub ecx, eax
L0009: vmovd xmm0, ecx
L000d: vpextrd eax, xmm0, 1
L0013: test eax, eax
L0015: setne al
L0018: movzx eax, al
L001b: ret The code above currently allows me to guess whether the Such behavior is really useful when I deal with some SIMD optimization, as some instructions only take constant value. API Proposalnamespace System.Runtime.CompilerServices;
public static class Unsafe
{
public static bool IsConstant<T>(T value) where T : unmanaged;
} API Usage// The method takes `[ConstantExpected] int index` and `Vector512<ushort> zmm2` as parameter
if (Unsafe.IsConstant(index))
{
// some processing that needs the index to be a constant value
return zmm2.GetElement(index);
}
// some processing that don't need the index to be a constant value
return Avx512BW.PermuteVar32x16(zmm2, Vector512.CreateScalarUnsafe((ushort)index)).GetElement(0); Alternative Designs
RisksNone
|
Your API Usage example sounds like something JIT should optimize itself when index is constant without extra help? Do you have other examples where this could be useful? We already have an internal API for it called |
There are several cases where inlining the conditions for constant is fine as RyuJIT eliminates known conditional jumps, but executing multiple conditional jumps for variable cases would be tedious works for CPU.
Exposing something like |
Just my two cents: "is known constant" is a weird method name. I get what it's implying: not all constants are "known" when inlining occurs, but it's one you have to think about. Should an API be exposed, I'd vote for "is inlined constant". |
Tagging subscribers to this area: @dotnet/area-system-runtime-compilerservices Issue DetailsBackground and motivation[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static bool IsConstant(int value)
=> Vector128.CreateScalarUnsafe(value - ~value).GetElement(1) != 0; L0000: vzeroupper
L0003: mov eax, ecx
L0005: not eax
L0007: sub ecx, eax
L0009: vmovd xmm0, ecx
L000d: vpextrd eax, xmm0, 1
L0013: test eax, eax
L0015: setne al
L0018: movzx eax, al
L001b: ret The code above currently allows me to guess whether the Such behavior is really useful when I deal with some SIMD optimization, as some instructions only take constant value. API Proposalnamespace System.Runtime.CompilerServices;
public static class Unsafe
{
public static bool IsConstant<T>(T value) where T : unmanaged;
} API Usage// The method takes `[ConstantExpected] int index` and `Vector512<ushort> zmm2` as parameter
if (Unsafe.IsConstant(index))
{
// some processing that needs the index to be a constant value
return zmm2.GetElement(index);
}
// some processing that don't need the index to be a constant value
return Avx512BW.PermuteVar32x16(zmm2, Vector512.CreateScalarUnsafe((ushort)index)).GetElement(0); Alternative Designs
RisksNone
|
Moved to the right area, but noting this is As @EgorBo has pointed out, there are limitations with this and there are many things it won't catch or handle. That being said, it could still be useful in the same ways it's been useful to us in the BCL. @jkotas may also have opinions on this. |
We had this method as internal API to experiment with for number of years, it has proven to be difficult to use. It is used in 6 places total currently, and 2 of those are being deleted in #98186. |
Egor tried to optimize Memmove using this API in #83638, but it was too difficult to make it work. The intrinsic JIT expansion was implemented instead. |
Right, here is that fully managed unrolling (for String.Equals and String.StartsWith): https://github.com/dotnet/runtime/pull/64821/files
But it was a funny experiment 🙂 E.g.: |
I'd guess one reasonable use case would be for checking inputs in SIMD code that then dispatches either to fast paths with |
Going to close this based on the above. Getting targeted JIT improvements around inlining, constant propagation, and potentially DPGO, are likely to be better long goals; particularly given the extreme limitations that the API in question has. |
Background and motivation
The code above currently allows me to guess whether the
value
is a JIT-time constant in x86-64 environments.The
Vector128.CreateScalarUnsafe(value)
usually does the same thing withVector128.CreateScalar(value)
(which isvmovd xmm*, r*d
) which clears all upper elements with 0, but it doesVector128.Create(value)
which broadcasts thevalue
, when thevalue
is a constant.The
value - ~value
is guaranteed to be nonzero, as LLVM says, and it obviously differs byvalue
.By checking whether the second element is nonzero or not, it returns
true
when thevalue
is a constant,false
otherwise.Inlining the
IsConstant(constant)
simply boils down tomov eax, 1
as shown here.Such behavior is really useful when I deal with some SIMD optimization, as some instructions only take constant value.
It also helps me to replicate something like what System.Buffer.Memmove does for small constant lengths, without modifying the CoreCLR.
But it's an undefined behavior, and I'm not sure if it works with ARM-based processors, so I propose the APIs below for official support.
API Proposal
API Usage
Alternative Designs
IsConstant
to be.IsConstant
.Risks
None
The text was updated successfully, but these errors were encountered: