Skip to content

Commit 3f5df2f

Browse files
arm64: Fix negs compare to minus int.MinValue (#121380)
1 parent 916e90d commit 3f5df2f

File tree

4 files changed

+65
-40
lines changed

4 files changed

+65
-40
lines changed

src/coreclr/jit/gentree.cpp

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19919,11 +19919,6 @@ bool GenTree::IsArrayAddr(GenTreeArrAddr** pArrAddr)
1991919919
//
1992019920
bool GenTree::SupportsSettingZeroFlag()
1992119921
{
19922-
if (SupportsSettingResultFlags())
19923-
{
19924-
return true;
19925-
}
19926-
1992719922
#if defined(TARGET_XARCH)
1992819923
if (OperIs(GT_LSH, GT_RSH, GT_RSZ, GT_ROL, GT_ROR))
1992919924
{
@@ -19942,42 +19937,18 @@ bool GenTree::SupportsSettingZeroFlag()
1994219937
return true;
1994319938
}
1994419939
#endif
19945-
#endif
19946-
19947-
return false;
19948-
}
19949-
19950-
//------------------------------------------------------------------------
19951-
// SupportsSettingResultFlags: Returns true if this is an arithmetic operation
19952-
// whose codegen supports setting the carry, overflow, zero and sign flags based
19953-
// on the result of the operation.
19954-
//
19955-
// Return Value:
19956-
// True if so. A false return does not imply that codegen for the node will
19957-
// not trash the result flags.
19958-
//
19959-
// Remarks:
19960-
// For example, for GT (AND x y) 0, arm64 can emit instructions that
19961-
// directly set the flags after the 'AND' and thus no comparison is needed.
19962-
//
19963-
// The backend expects any node for which the flags will be consumed to be
19964-
// marked with GTF_SET_FLAGS.
19965-
//
19966-
bool GenTree::SupportsSettingResultFlags()
19967-
{
19968-
#if defined(TARGET_ARM64)
19940+
#elif defined(TARGET_ARM64)
1996919941
if (OperIs(GT_AND, GT_AND_NOT))
1997019942
{
1997119943
return true;
1997219944
}
1997319945

19974-
// We do not support setting result flags if neg has a contained mul
19946+
// We do not support setting zero flag for madd/msub.
1997519947
if (OperIs(GT_NEG) && (!gtGetOp1()->OperIs(GT_MUL) || !gtGetOp1()->isContained()))
1997619948
{
1997719949
return true;
1997819950
}
1997919951

19980-
// We do not support setting result flags for madd/msub.
1998119952
if (OperIs(GT_ADD, GT_SUB) && (!gtGetOp2()->OperIs(GT_MUL) || !gtGetOp2()->isContained()))
1998219953
{
1998319954
return true;
@@ -19987,6 +19958,19 @@ bool GenTree::SupportsSettingResultFlags()
1998719958
return false;
1998819959
}
1998919960

19961+
//------------------------------------------------------------------------
19962+
// SupportsSettingFlagsAsCompareToZero: Returns true if we support setting
19963+
// flags for compare to zero operations.
19964+
//
19965+
bool GenTree::SupportsSettingFlagsAsCompareToZero()
19966+
{
19967+
#if defined(TARGET_ARMARCH)
19968+
return OperIs(GT_AND, GT_AND_NOT);
19969+
#else
19970+
return false;
19971+
#endif
19972+
}
19973+
1999019974
//------------------------------------------------------------------------
1999119975
// Create: Create or retrieve a field sequence for the given field handle.
1999219976
//

src/coreclr/jit/gentree.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2061,7 +2061,7 @@ struct GenTree
20612061

20622062
bool SupportsSettingZeroFlag();
20632063

2064-
bool SupportsSettingResultFlags();
2064+
bool SupportsSettingFlagsAsCompareToZero();
20652065

20662066
// These are only used for dumping.
20672067
// The GetRegNum() is only valid in LIR, but the dumping methods are not easily

src/coreclr/jit/lower.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4441,11 +4441,10 @@ GenTree* Lowering::OptimizeConstCompare(GenTree* cmp)
44414441
}
44424442

44434443
// Optimize EQ/NE/GT/GE/LT/LE(op_that_sets_zf, 0) into op_that_sets_zf with GTF_SET_FLAGS + SETCC.
4444-
// For GT/GE/LT/LE don't allow ADD/SUB, runtime has to check for overflow.
44454444
LIR::Use use;
44464445
if (((cmp->OperIs(GT_EQ, GT_NE) && op2->IsIntegralConst(0) && op1->SupportsSettingZeroFlag()) ||
4447-
(cmp->OperIs(GT_GT, GT_GE, GT_LT, GT_LE) && op2->IsIntegralConst(0) && !op1->OperIs(GT_ADD, GT_SUB) &&
4448-
op1->SupportsSettingResultFlags())) &&
4446+
(cmp->OperIs(GT_GT, GT_GE, GT_LT, GT_LE) && op2->IsIntegralConst(0) &&
4447+
op1->SupportsSettingFlagsAsCompareToZero())) &&
44494448
BlockRange().TryGetUse(cmp, &use) && IsProfitableToSetZeroFlag(op1))
44504449
{
44514450
op1->gtFlags |= GTF_SET_FLAGS;

src/tests/JIT/opt/InstructionCombining/Neg.cs

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,16 @@ public static int CheckNeg()
115115
fail = true;
116116
}
117117

118+
if (NegsGreaterThanIntMinValue())
119+
{
120+
fail = true;
121+
}
122+
123+
if (NegsGreaterThanLongMinValue())
124+
{
125+
fail = true;
126+
}
127+
118128
if (fail)
119129
{
120130
return 101;
@@ -266,33 +276,65 @@ static bool NegsBinOpSingleLine(int a, int b)
266276
//ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}, LSL #1
267277
return (-(a >> 1) != 0) | (-(b << 1) != 0);
268278
}
269-
279+
270280
[MethodImpl(MethodImplOptions.NoInlining)]
271281
static bool NegsGreaterThan(int a)
272282
{
273-
//ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}
283+
//ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}}
284+
//ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0
274285
return -a > 0;
275286
}
276287

277288
[MethodImpl(MethodImplOptions.NoInlining)]
278289
static bool NegsGreaterThanEq(int a)
279290
{
280-
//ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}
291+
//ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}}
292+
//ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0
281293
return -a >= 0;
282294
}
283295

284296
[MethodImpl(MethodImplOptions.NoInlining)]
285297
static bool NegsLessThan(int a)
286298
{
287-
//ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}
299+
//ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}}
300+
//ARM64-FULL-LINE: lsr {{w[0-9]+}}, {{w[0-9]+}}, #31
288301
return -a < 0;
289302
}
290303

291304
[MethodImpl(MethodImplOptions.NoInlining)]
292305
static bool NegsLessThanEq(int a)
293306
{
294-
//ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}
307+
//ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}}
308+
//ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0
295309
return -a <= 0;
296310
}
311+
312+
[MethodImpl(MethodImplOptions.NoInlining)]
313+
static bool NegsGreaterThanIntMinValue()
314+
{
315+
//ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}}
316+
//ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0
317+
return -IntMinValue() > 0;
318+
}
319+
320+
[MethodImpl(MethodImplOptions.NoInlining)]
321+
static bool NegsGreaterThanLongMinValue()
322+
{
323+
//ARM64-FULL-LINE: neg {{x[0-9]+}}, {{x[0-9]+}}
324+
//ARM64-FULL-LINE: cmp {{x[0-9]+}}, #0
325+
return -LongMinValue() > 0;
326+
}
327+
328+
[MethodImpl(MethodImplOptions.NoInlining)]
329+
static int IntMinValue()
330+
{
331+
return int.MinValue;
332+
}
333+
334+
[MethodImpl(MethodImplOptions.NoInlining)]
335+
static long LongMinValue()
336+
{
337+
return long.MinValue;
338+
}
297339
}
298340
}

0 commit comments

Comments
 (0)