@@ -142,16 +142,6 @@ GenTree* Lowering::LowerNode(GenTree* node)
142142 ContainCheckBinary (node->AsOp ());
143143 break ;
144144
145- #ifdef _TARGET_XARCH_
146- case GT_NEG:
147- // Codegen of this tree node sets ZF and SF flags.
148- if (!varTypeIsFloating (node))
149- {
150- node->gtFlags |= GTF_ZSF_SET;
151- }
152- break ;
153- #endif // _TARGET_XARCH_
154-
155145 case GT_MUL:
156146 case GT_MULHI:
157147#if defined(_TARGET_X86_) && !defined(LEGACY_BACKEND)
@@ -189,8 +179,7 @@ GenTree* Lowering::LowerNode(GenTree* node)
189179 case GT_TEST_NE:
190180 case GT_CMP:
191181 case GT_JCMP:
192- LowerCompare (node);
193- break ;
182+ return LowerCompare (node);
194183
195184 case GT_JTRUE:
196185 ContainCheckJTrue (node->AsOp ());
@@ -2148,6 +2137,9 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree* callTarget
21482137// Arguments:
21492138// cmp - the compare node
21502139//
2140+ // Return Value:
2141+ // The next node to lower.
2142+ //
21512143// Notes:
21522144// - Decomposes long comparisons that feed a GT_JTRUE (32 bit specific).
21532145// - Decomposes long comparisons that produce a value (X86 specific).
@@ -2156,8 +2148,11 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree* callTarget
21562148// - Transform cmp(and(x, y), 0) into test(x, y) (XARCH/Arm64 specific but could
21572149// be used for ARM as well if support for GT_TEST_EQ/GT_TEST_NE is added).
21582150// - Transform TEST(x, LSH(1, y)) into BT(x, y) (XARCH specific)
2151+ // - Transform RELOP(OP, 0) into SETCC(OP) or JCC(OP) if OP can set the
2152+ // condition flags appropriately (XARCH/ARM64 specific but could be extended
2153+ // to ARM32 as well if ARM32 codegen supports GTF_SET_FLAGS).
21592154
2160- void Lowering::LowerCompare (GenTree* cmp)
2155+ GenTree* Lowering::LowerCompare (GenTree* cmp)
21612156{
21622157#ifndef _TARGET_64BIT_
21632158 if (cmp->gtGetOp1 ()->TypeGet () == TYP_LONG)
@@ -2363,7 +2358,7 @@ void Lowering::LowerCompare(GenTree* cmp)
23632358 cmp->AsCC ()->gtCondition = condition;
23642359 }
23652360
2366- return ;
2361+ return cmp-> gtNext ;
23672362 }
23682363#endif
23692364
@@ -2567,11 +2562,10 @@ void Lowering::LowerCompare(GenTree* cmp)
25672562 }
25682563 }
25692564 }
2570- #endif // defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
25712565
2572- #ifdef _TARGET_XARCH_
25732566 if (cmp->OperIs (GT_TEST_EQ, GT_TEST_NE))
25742567 {
2568+ #ifdef _TARGET_XARCH_
25752569 //
25762570 // Transform TEST_EQ|NE(x, LSH(1, y)) into BT(x, y) when possible. Using BT
25772571 // results in smaller and faster code. It also doesn't have special register
@@ -2614,10 +2608,76 @@ void Lowering::LowerCompare(GenTree* cmp)
26142608
26152609 cc->gtFlags |= GTF_USE_FLAGS | GTF_UNSIGNED;
26162610
2617- return ;
2611+ return cmp->gtNext ;
2612+ }
2613+ #endif // _TARGET_XARCH_
2614+ }
2615+ #ifdef _TARGET_XARCH_
2616+ else if (cmp->OperIs (GT_EQ, GT_NE))
2617+ #else // _TARGET_ARM64_
2618+ else
2619+ #endif
2620+ {
2621+ GenTree* op1 = cmp->gtGetOp1 ();
2622+ GenTree* op2 = cmp->gtGetOp2 ();
2623+
2624+ // TODO-CQ: right now the below peep is inexpensive and gets the benefit in most
2625+ // cases because in majority of cases op1, op2 and cmp would be in that order in
2626+ // execution. In general we should be able to check that all the nodes that come
2627+ // after op1 do not modify the flags so that it is safe to avoid generating a
2628+ // test instruction.
2629+
2630+ if (op2->IsIntegralConst (0 ) && (op1->gtNext == op2) && (op2->gtNext == cmp) &&
2631+ #ifdef _TARGET_XARCH_
2632+ op1->OperIs (GT_AND, GT_OR, GT_XOR, GT_ADD, GT_SUB, GT_NEG))
2633+ #else // _TARGET_ARM64_
2634+ op1->OperIs (GT_AND, GT_ADD, GT_SUB))
2635+ #endif
2636+ {
2637+ op1->gtFlags |= GTF_SET_FLAGS;
2638+ op1->SetUnusedValue ();
2639+
2640+ BlockRange ().Remove (op2);
2641+
2642+ GenTree* next = cmp->gtNext ;
2643+ GenTree* cc;
2644+ genTreeOps ccOp;
2645+ LIR::Use cmpUse;
2646+
2647+ // Fast check for the common case - relop used by a JTRUE that immediately follows it.
2648+ if ((next != nullptr ) && next->OperIs (GT_JTRUE) && (next->gtGetOp1 () == cmp))
2649+ {
2650+ cc = next;
2651+ ccOp = GT_JCC;
2652+ next = nullptr ;
2653+ BlockRange ().Remove (cmp);
2654+ }
2655+ else if (BlockRange ().TryGetUse (cmp, &cmpUse) && cmpUse.User ()->OperIs (GT_JTRUE))
2656+ {
2657+ cc = cmpUse.User ();
2658+ ccOp = GT_JCC;
2659+ next = nullptr ;
2660+ BlockRange ().Remove (cmp);
2661+ }
2662+ else // The relop is not used by a JTRUE or it is not used at all.
2663+ {
2664+ // Transform the relop node it into a SETCC. If it's not used we could remove
2665+ // it completely but that means doing more work to handle a rare case.
2666+ cc = cmp;
2667+ ccOp = GT_SETCC;
2668+ }
2669+
2670+ genTreeOps condition = cmp->OperGet ();
2671+ cc->ChangeOper (ccOp);
2672+ cc->AsCC ()->gtCondition = condition;
2673+ cc->gtFlags |= GTF_USE_FLAGS | (cmp->gtFlags & GTF_UNSIGNED);
2674+
2675+ return next;
26182676 }
26192677 }
2678+ #endif // defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
26202679
2680+ #ifdef _TARGET_XARCH_
26212681 if (cmp->gtGetOp1 ()->TypeGet () == cmp->gtGetOp2 ()->TypeGet ())
26222682 {
26232683 if (varTypeIsSmall (cmp->gtGetOp1 ()->TypeGet ()) && varTypeIsUnsigned (cmp->gtGetOp1 ()->TypeGet ()))
@@ -2635,6 +2695,7 @@ void Lowering::LowerCompare(GenTree* cmp)
26352695 }
26362696#endif // _TARGET_XARCH_
26372697 ContainCheckCompare (cmp->AsOp ());
2698+ return cmp->gtNext ;
26382699}
26392700
26402701// Lower "jmp <method>" tail call to insert PInvoke method epilog if required.
@@ -5377,16 +5438,6 @@ void Lowering::ContainCheckNode(GenTree* node)
53775438 ContainCheckBinary (node->AsOp ());
53785439 break ;
53795440
5380- #ifdef _TARGET_XARCH_
5381- case GT_NEG:
5382- // Codegen of this tree node sets ZF and SF flags.
5383- if (!varTypeIsFloating (node))
5384- {
5385- node->gtFlags |= GTF_ZSF_SET;
5386- }
5387- break ;
5388- #endif // _TARGET_XARCH_
5389-
53905441#if defined(_TARGET_X86_)
53915442 case GT_MUL_LONG:
53925443#endif
0 commit comments