JIT: Optimize movzx after setcc (#66245)
authorEgor Bogatov <egorbo@gmail.com>
Mon, 7 Mar 2022 23:22:14 +0000 (02:22 +0300)
committerGitHub <noreply@github.com>
Mon, 7 Mar 2022 23:22:14 +0000 (02:22 +0300)
src/coreclr/jit/codegenxarch.cpp
src/coreclr/jit/gentree.cpp
src/coreclr/jit/gentree.h

index e2dad3d..ce948c0 100644 (file)
@@ -6294,6 +6294,19 @@ void CodeGen::genCompareFloat(GenTree* treeNode)
     ins     = (op1Type == TYP_FLOAT) ? INS_ucomiss : INS_ucomisd;
     cmpAttr = emitTypeSize(op1Type);
 
+    var_types targetType = treeNode->TypeGet();
+
+    // Clear target reg in advance via "xor reg,reg" to avoid movzx after SETCC
+    if ((targetReg != REG_NA) && (op1->GetRegNum() != targetReg) && (op2->GetRegNum() != targetReg) &&
+        !varTypeIsByte(targetType))
+    {
+        regMaskTP targetRegMask = genRegMask(targetReg);
+        if (((op1->gtGetContainedRegMask() | op2->gtGetContainedRegMask()) & targetRegMask) == 0)
+        {
+            instGen_Set_Reg_To_Zero(emitTypeSize(TYP_I_IMPL), targetReg);
+            targetType = TYP_BOOL; // just a tip for inst_SETCC that movzx is not needed
+        }
+    }
     GetEmitter()->emitInsBinary(ins, cmpAttr, op1, op2);
 
     // Are we evaluating this into a register?
@@ -6309,7 +6322,7 @@ void CodeGen::genCompareFloat(GenTree* treeNode)
             condition = GenCondition(GenCondition::P);
         }
 
-        inst_SETCC(condition, treeNode->TypeGet(), targetReg);
+        inst_SETCC(condition, targetType, targetReg);
         genProduceReg(tree);
     }
 }
@@ -6438,6 +6451,8 @@ void CodeGen::genCompareInt(GenTree* treeNode)
     // Sign jump optimization should only be set the following check
     assert((tree->gtFlags & GTF_RELOP_SJUMP_OPT) == 0);
 
+    var_types targetType = tree->TypeGet();
+
     if (canReuseFlags && emit->AreFlagsSetToZeroCmp(op1->GetRegNum(), emitTypeSize(type), tree->OperGet()))
     {
         JITDUMP("Not emitting compare due to flags being already set\n");
@@ -6449,13 +6464,24 @@ void CodeGen::genCompareInt(GenTree* treeNode)
     }
     else
     {
+        // Clear target reg in advance via "xor reg,reg" to avoid movzx after SETCC
+        if ((targetReg != REG_NA) && (op1->GetRegNum() != targetReg) && (op2->GetRegNum() != targetReg) &&
+            !varTypeIsByte(targetType))
+        {
+            regMaskTP targetRegMask = genRegMask(targetReg);
+            if (((op1->gtGetContainedRegMask() | op2->gtGetContainedRegMask()) & targetRegMask) == 0)
+            {
+                instGen_Set_Reg_To_Zero(emitTypeSize(TYP_I_IMPL), targetReg);
+                targetType = TYP_BOOL; // just a tip for inst_SETCC that movzx is not needed
+            }
+        }
         emit->emitInsBinary(ins, emitTypeSize(type), op1, op2);
     }
 
     // Are we evaluating this into a register?
     if (targetReg != REG_NA)
     {
-        inst_SETCC(GenCondition::FromIntegralRelop(tree), tree->TypeGet(), targetReg);
+        inst_SETCC(GenCondition::FromIntegralRelop(tree), targetType, targetReg);
         genProduceReg(tree);
     }
 }
index 8350e7a..640ee36 100644 (file)
@@ -863,6 +863,31 @@ unsigned GenTree::GetMultiRegCount(Compiler* comp) const
 }
 
 //---------------------------------------------------------------
+// gtGetContainedRegMask: Get the reg mask of the node including
+//    contained nodes (recursive).
+//
+// Arguments:
+//    None
+//
+// Return Value:
+//    Reg Mask of GenTree node.
+//
+regMaskTP GenTree::gtGetContainedRegMask()
+{
+    if (!isContained())
+    {
+        return gtGetRegMask();
+    }
+
+    regMaskTP mask = 0;
+    for (GenTree* operand : Operands())
+    {
+        mask |= operand->gtGetContainedRegMask();
+    }
+    return mask;
+}
+
+//---------------------------------------------------------------
 // gtGetRegMask: Get the reg mask of the node.
 //
 // Arguments:
index d86d891..af58071 100644 (file)
@@ -990,6 +990,7 @@ public:
     int GetRegisterDstCount(Compiler* compiler) const;
 
     regMaskTP gtGetRegMask() const;
+    regMaskTP gtGetContainedRegMask();
 
     GenTreeFlags gtFlags;