From d1d081194afab944b5d8c0a9f93f9b860c9de192 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Tue, 9 Jun 2026 03:26:59 +0200 Subject: [PATCH] JIT: Narrow long comparisons of sign-extended ints to int in VN Integer comparisons whose two TYP_LONG operands are both just sign-extended TYP_INT values (or int-fitting TYP_LONG constants) can be evaluated in TYP_INT instead. Sign-extension is monotonic for both the signed and the unsigned interpretation, so the comparison result is unchanged. Operating in TYP_INT is preferred because assertion prop and bounds-check optimizations only consume TYP_INT comparisons (optCreateJTrueBoundsAssertion bails on wider operands). For example `(nint)arr.Length > 100L` becomes `arr.Length > 100`, which then lets the bounds check on `arr[100]` be eliminated. This is done in EvalUsingMathIdentity by re-issuing the comparison through VNIgnoreIntToLongCast. VNIgnoreIntToLongCast is also extended to look through zero-extending int->long casts of never-negative sources (e.g. the common `(nuint)`/`(uint)arr.Length` widenings) and TYP_ULONG cast targets, since for a non-negative value zero- and sign-extension produce the same bits. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/jit/valuenum.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 885d32213eb867..7dd03cf2e8a93d 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -2052,9 +2052,13 @@ ValueNum ValueNumStore::VNIgnoreIntToLongCast(ValueNum vn) var_types castToType; bool srcIsUnsigned; GetCastOperFromVN(castInfoVN, &castToType, &srcIsUnsigned); - if ((castToType == TYP_LONG) && !srcIsUnsigned && TypeOfVN(srcVN) == TYP_INT) + if ((genActualType(castToType) == TYP_LONG) && (TypeOfVN(srcVN) == TYP_INT)) { - return srcVN; + // A zero-extending cast preserves the sign-extended value only when the source is non-negative. + if (!srcIsUnsigned || IsVNNeverNegative(srcVN)) + { + return srcVN; + } } } @@ -5273,6 +5277,18 @@ ValueNum ValueNumStore::EvalUsingMathIdentity(var_types typ, VNFunc func, ValueN return resultVN; // return the unsuccessful value } + // Narrow "(long)x (long)y" to an int comparison when both operands are just + // sign-extended ints; only TYP_INT comparisons feed assertion prop / bounds checks. + if (VNFuncIsComparison(func) && (TypeOfVN(arg0VN) == TYP_LONG) && (TypeOfVN(arg1VN) == TYP_LONG)) + { + ValueNum newArg0VN = VNIgnoreIntToLongCast(arg0VN); + ValueNum newArg1VN = VNIgnoreIntToLongCast(arg1VN); + if ((TypeOfVN(newArg0VN) == TYP_INT) && (TypeOfVN(newArg1VN) == TYP_INT)) + { + return VNForFunc(TYP_INT, func, newArg0VN, newArg1VN); + } + } + ValueNum cnsVN = NoVN; ValueNum opVN = NoVN;