From 66295ddc2f6ae42967155f66366006f0c79494a1 Mon Sep 17 00:00:00 2001 From: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> Date: Fri, 23 Sep 2022 19:59:37 +0300 Subject: [PATCH] Do not remove certain casts with contained operands (#74602) On ARM64, we turn the "EQ(CAST(x), 0)" into "TEST_EQ(x, 0xFF)", to avoid materializing the cast. However, this breaks recognition of the "cb[n]z" idiom. If "x" ends up in a register, that's ok - we're essentially exchanging relop for a cast. If, however, it was contained, it is better to leave it alone: ``` - ldr w0, [fp,#0x18] - tst w0, #255 - bne G_M25131_IG10 - ;; size=12 bbWeight=1 PerfScore 3.50 + ldrb w0, [fp,#0x18] + cbnz w0, G_M25131_IG10 + ;; size=8 bbWeight=1 PerfScore 3.00 ``` --- src/coreclr/jit/lower.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 7c9327a397811..e3fb7569473c2 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -2789,14 +2789,13 @@ GenTree* Lowering::OptimizeConstCompare(GenTree* cmp) // doing so would produce incorrect results (e.g. RSZ, RSH). // // The below list of handled opers is conservative but enough to handle the most common - // situations. In particular this include CALL, sometimes the JIT unnecessarily widens - // the result of bool returning calls. + // situations. // bool removeCast = #ifdef TARGET_ARM64 - (op2Value == 0) && cmp->OperIs(GT_EQ, GT_NE, GT_GT) && + (op2Value == 0) && cmp->OperIs(GT_EQ, GT_NE, GT_GT) && !castOp->isContained() && #endif - (castOp->OperIs(GT_CALL, GT_LCL_VAR) || castOp->OperIs(GT_OR, GT_XOR, GT_AND) + (castOp->OperIs(GT_LCL_VAR, GT_CALL, GT_OR, GT_XOR, GT_AND) #ifdef TARGET_XARCH || IsContainableMemoryOp(castOp) #endif