Skip to content

Commit 5fc165a

Browse files
arm64: Optimise GT/GE/LT/LE comparisons to constant zero (#119758)
1 parent e7c8c1b commit 5fc165a

File tree

9 files changed

+530
-50
lines changed

9 files changed

+530
-50
lines changed

src/coreclr/jit/gentree.cpp

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19878,6 +19878,11 @@ bool GenTree::IsArrayAddr(GenTreeArrAddr** pArrAddr)
1987819878
//
1987919879
bool GenTree::SupportsSettingZeroFlag()
1988019880
{
19881+
if (SupportsSettingResultFlags())
19882+
{
19883+
return true;
19884+
}
19885+
1988119886
#if defined(TARGET_XARCH)
1988219887
if (OperIs(GT_LSH, GT_RSH, GT_RSZ, GT_ROL, GT_ROR))
1988319888
{
@@ -19896,18 +19901,42 @@ bool GenTree::SupportsSettingZeroFlag()
1989619901
return true;
1989719902
}
1989819903
#endif
19899-
#elif defined(TARGET_ARM64)
19904+
#endif
19905+
19906+
return false;
19907+
}
19908+
19909+
//------------------------------------------------------------------------
19910+
// SupportsSettingResultFlags: Returns true if this is an arithmetic operation
19911+
// whose codegen supports setting the carry, overflow, zero and sign flags based
19912+
// on the result of the operation.
19913+
//
19914+
// Return Value:
19915+
// True if so. A false return does not imply that codegen for the node will
19916+
// not trash the result flags.
19917+
//
19918+
// Remarks:
19919+
// For example, for GT (AND x y) 0, arm64 can emit instructions that
19920+
// directly set the flags after the 'AND' and thus no comparison is needed.
19921+
//
19922+
// The backend expects any node for which the flags will be consumed to be
19923+
// marked with GTF_SET_FLAGS.
19924+
//
19925+
bool GenTree::SupportsSettingResultFlags()
19926+
{
19927+
#if defined(TARGET_ARM64)
1990019928
if (OperIs(GT_AND, GT_AND_NOT))
1990119929
{
1990219930
return true;
1990319931
}
1990419932

19905-
// We do not support setting zero flag for madd/msub.
19933+
// We do not support setting result flags if neg has a contained mul
1990619934
if (OperIs(GT_NEG) && (!gtGetOp1()->OperIs(GT_MUL) || !gtGetOp1()->isContained()))
1990719935
{
1990819936
return true;
1990919937
}
1991019938

19939+
// We do not support setting result flags for madd/msub.
1991119940
if (OperIs(GT_ADD, GT_SUB) && (!gtGetOp2()->OperIs(GT_MUL) || !gtGetOp2()->isContained()))
1991219941
{
1991319942
return true;

src/coreclr/jit/gentree.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2070,6 +2070,8 @@ struct GenTree
20702070

20712071
bool SupportsSettingZeroFlag();
20722072

2073+
bool SupportsSettingResultFlags();
2074+
20732075
// These are only used for dumping.
20742076
// The GetRegNum() is only valid in LIR, but the dumping methods are not easily
20752077
// modified to check this.

src/coreclr/jit/lower.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4439,9 +4439,12 @@ GenTree* Lowering::OptimizeConstCompare(GenTree* cmp)
44394439
}
44404440
}
44414441

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

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

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,106 @@ public static int CheckAdd()
135135
fail = true;
136136
}
137137

138+
if (AddGtZero(-3, 4) != 1)
139+
{
140+
fail = true;
141+
}
142+
143+
if (AddGtZero(3, -3) != 0)
144+
{
145+
fail = true;
146+
}
147+
148+
if (AddGtZero(-5, -10) != 0)
149+
{
150+
fail = true;
151+
}
152+
153+
if (AddGtZero(int.MaxValue, 1) != 0)
154+
{
155+
fail = true;
156+
}
157+
158+
if (AddGtZero(int.MinValue, -1) != 1)
159+
{
160+
fail = true;
161+
}
162+
163+
if (AddGeZero(1, 1) != 1)
164+
{
165+
fail = true;
166+
}
167+
168+
if (AddGeZero(0, 0) != 1)
169+
{
170+
fail = true;
171+
}
172+
173+
if (AddGeZero(-1, -1) != 0)
174+
{
175+
fail = true;
176+
}
177+
178+
if (AddGeZero(int.MaxValue, 1) != 0)
179+
{
180+
fail = true;
181+
}
182+
183+
if (AddGeZero(int.MinValue, -1) != 1)
184+
{
185+
fail = true;
186+
}
187+
188+
if (AddLtZero(1, 1) != 0)
189+
{
190+
fail = true;
191+
}
192+
193+
if (AddLtZero(0, 0) != 0)
194+
{
195+
fail = true;
196+
}
197+
198+
if (AddLtZero(-1, -1) != 1)
199+
{
200+
fail = true;
201+
}
202+
203+
if (AddLtZero(int.MaxValue, 1) != 1)
204+
{
205+
fail = true;
206+
}
207+
208+
if (AddLtZero(int.MinValue, -1) != 0)
209+
{
210+
fail = true;
211+
}
212+
213+
if (AddLeZero(1, 1) != 0)
214+
{
215+
fail = true;
216+
}
217+
218+
if (AddLeZero(0, 0) != 1)
219+
{
220+
fail = true;
221+
}
222+
223+
if (AddLeZero(-1, -1) != 1)
224+
{
225+
fail = true;
226+
}
227+
228+
if (AddLeZero(int.MaxValue, 1) != 1)
229+
{
230+
fail = true;
231+
}
232+
233+
if (AddLeZero(int.MinValue, -1) != 0)
234+
{
235+
fail = true;
236+
}
237+
138238
if (fail)
139239
{
140240
return 101;
@@ -336,5 +436,48 @@ static bool AddsBinOpSingleLine(int a, int b, int c, int d)
336436
//ARM64-FULL-LINE: adds {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}
337437
return (a + b == 0) | (c + d == 0);
338438
}
439+
440+
[MethodImpl(MethodImplOptions.NoInlining)]
441+
static int AddGtZero(int a, int b) {
442+
//ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}
443+
//ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0
444+
//ARM64-FULL-LINE: cset {{x[0-9]+}}, gt
445+
if (a + b > 0) {
446+
return 1;
447+
}
448+
return 0;
449+
}
450+
451+
[MethodImpl(MethodImplOptions.NoInlining)]
452+
static int AddGeZero(int a, int b) {
453+
//ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}
454+
//ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0
455+
//ARM64-FULL-LINE: cset {{x[0-9]+}}, ge
456+
if (a + b >= 0) {
457+
return 1;
458+
}
459+
return 0;
460+
}
461+
462+
[MethodImpl(MethodImplOptions.NoInlining)]
463+
static int AddLtZero(int a, int b) {
464+
//ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}
465+
//ARM64-FULL-LINE: lsr {{w[0-9]+}}, {{w[0-9]+}}, #31
466+
if (a + b < 0) {
467+
return 1;
468+
}
469+
return 0;
470+
}
471+
472+
[MethodImpl(MethodImplOptions.NoInlining)]
473+
static int AddLeZero(int a, int b) {
474+
//ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}
475+
//ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0
476+
//ARM64-FULL-LINE: cset {{x[0-9]+}}, le
477+
if (a + b <= 0) {
478+
return 1;
479+
}
480+
return 0;
481+
}
339482
}
340483
}

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

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,26 @@ public static int CheckAnd()
105105
fail = true;
106106
}
107107

108+
if (!AndsGreaterThan(3, 2))
109+
{
110+
fail = true;
111+
}
112+
113+
if (!AndsGreaterThanEq(5, 8))
114+
{
115+
fail = true;
116+
}
117+
118+
if (!AndsLessThan(-8, -4))
119+
{
120+
fail = true;
121+
}
122+
123+
if (!AndsLessThanEq(5, 2))
124+
{
125+
fail = true;
126+
}
127+
108128
if (fail)
109129
{
110130
return 101;
@@ -264,5 +284,33 @@ static bool AndsBinOpSingleLine(uint a, uint b, uint c, uint d)
264284
//ARM64-FULL-LINE: tst {{w[0-9]+}}, {{w[0-9]+}}
265285
return ((a & b) == 0) | ((c & d) == 0);
266286
}
287+
288+
[MethodImpl(MethodImplOptions.NoInlining)]
289+
static bool AndsGreaterThan(int a, int b)
290+
{
291+
//ARM64-FULL-LINE: ands w0, {{w[0-9]+}}, {{w[0-9]+}}
292+
return (a & b) > 0;
293+
}
294+
295+
[MethodImpl(MethodImplOptions.NoInlining)]
296+
static bool AndsGreaterThanEq(int a, int b)
297+
{
298+
//ARM64-FULL-LINE: ands w0, {{w[0-9]+}}, {{w[0-9]+}}
299+
return (a & b) >= 0;
300+
}
301+
302+
[MethodImpl(MethodImplOptions.NoInlining)]
303+
static bool AndsLessThan(int a, int b)
304+
{
305+
//ARM64-FULL-LINE: ands w0, {{w[0-9]+}}, {{w[0-9]+}}
306+
return (a & b) < 0;
307+
}
308+
309+
[MethodImpl(MethodImplOptions.NoInlining)]
310+
static bool AndsLessThanEq(int a, int b)
311+
{
312+
//ARM64-FULL-LINE: ands w0, {{w[0-9]+}}, {{w[0-9]+}}
313+
return (a & b) <= 0;
314+
}
267315
}
268316
}

0 commit comments

Comments
 (0)