Updating isRMWRegOper, OperIsCommutative, and canBeContained to handle HWIntrinsic...
authorTanner Gooding <tagoo@outlook.com>
Wed, 7 Mar 2018 20:15:31 +0000 (12:15 -0800)
committerTanner Gooding <tagoo@outlook.com>
Thu, 8 Mar 2018 16:35:05 +0000 (08:35 -0800)
src/jit/compiler.h
src/jit/gentree.cpp
src/jit/gentree.h
src/jit/lsraxarch.cpp

index 7266c738e0e19b5c1b5d4129d22b4c4a0db6021c..0d5326a9a5a97f4f3685b66cbfd987133dd4fb8d 100644 (file)
@@ -1529,6 +1529,7 @@ class Compiler
     friend class TempDsc;
     friend class LIR;
     friend class ObjectAllocator;
+    friend struct GenTree;
 
 #ifndef _TARGET_64BIT_
     friend class DecomposeLongs;
index 9b8f88bd85a07373da76ddbe892c723c6764e696..99b64312bc22e9a4a62bbea70afb58b224f4694f 100644 (file)
@@ -16640,7 +16640,7 @@ bool GenTree::canBeContained() const
 
     // It is not possible for nodes that do not produce values or that are not containable values
     // to be contained.
-    if ((OperKind() & (GTK_NOVALUE | GTK_NOCONTAIN)) != 0)
+    if (((OperKind() & (GTK_NOVALUE | GTK_NOCONTAIN)) != 0) || (OperIsHWIntrinsic() && !isContainableHWIntrinsic()))
     {
         return false;
     }
@@ -17982,6 +17982,46 @@ bool GenTree::isCommutativeSIMDIntrinsic()
 #endif // FEATURE_SIMD
 
 #ifdef FEATURE_HW_INTRINSICS
+bool GenTree::isCommutativeHWIntrinsic() const
+{
+    assert(gtOper == GT_HWIntrinsic);
+
+#ifdef _TARGET_XARCH_
+    HWIntrinsicFlag flags = Compiler::flagsOfHWIntrinsic(AsHWIntrinsic()->gtHWIntrinsicId);
+    return ((flags & HW_Flag_Commutative) != 0);
+#else
+    return false;
+#endif // _TARGET_XARCH_
+}
+
+bool GenTree::isContainableHWIntrinsic() const
+{
+    assert(gtOper == GT_HWIntrinsic);
+
+#ifdef _TARGET_XARCH_
+    HWIntrinsicFlag flags = Compiler::flagsOfHWIntrinsic(AsHWIntrinsic()->gtHWIntrinsicId);
+    return ((flags & HW_Flag_NoContainment) == 0);
+#else
+    return false;
+#endif // _TARGET_XARCH_
+}
+
+bool GenTree::isRMWHWIntrinsic(Compiler* comp)
+{
+    assert(gtOper == GT_HWIntrinsic);
+    assert(comp != nullptr);
+
+#ifdef _TARGET_XARCH_
+    if (!comp->canUseVexEncoding())
+    {
+        HWIntrinsicFlag flags = Compiler::flagsOfHWIntrinsic(AsHWIntrinsic()->gtHWIntrinsicId);
+        return ((flags & HW_Flag_NoRMWSemantics) == 0);
+    }
+#endif // _TARGET_XARCH_
+
+    return false;
+}
+
 GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types      type,
                                                        NamedIntrinsic hwIntrinsicID,
                                                        var_types      baseType,
index 25d5a286fdcc6c08c8103304ccf97600e45ef193..35c215cf21ffef3fa9ee4ff7812354a2949499ad 100644 (file)
@@ -1471,6 +1471,27 @@ public:
     }
 #endif // FEATURE_SIMD
 
+#ifdef FEATURE_HW_INTRINSICS
+    bool isCommutativeHWIntrinsic() const;
+    bool isContainableHWIntrinsic() const;
+    bool isRMWHWIntrinsic(Compiler* comp);
+#else
+    bool isCommutativeHWIntrinsic() const
+    {
+        return false;
+    }
+
+    bool isContainableHWIntrinsic() const
+    {
+        return false;
+    }
+
+    bool isRMWHWIntrinsic(Compiler* comp)
+    {
+        return false;
+    }
+#endif // FEATURE_HW_INTRINSICS
+
     static bool OperIsCommutative(genTreeOps gtOper)
     {
         return (OperKind(gtOper) & GTK_COMMUTE) != 0;
@@ -1478,7 +1499,8 @@ public:
 
     bool OperIsCommutative()
     {
-        return OperIsCommutative(gtOper) || (OperIsSIMD(gtOper) && isCommutativeSIMDIntrinsic());
+        return OperIsCommutative(gtOper) || (OperIsSIMD(gtOper) && isCommutativeSIMDIntrinsic()) ||
+               (OperIsHWIntrinsic(gtOper) && isCommutativeHWIntrinsic());
     }
 
     static bool OperIsAssignment(genTreeOps gtOper)
index b0e95ae31fae96d1b6300584e943928aee2796af..a9f0207d8d4f8570b0978061ebd87cbadc9e2780 100644 (file)
@@ -821,6 +821,11 @@ bool LinearScan::isRMWRegOper(GenTree* tree)
         case GT_MUL:
             return (!tree->gtOp.gtOp2->isContainedIntOrIImmed() && !tree->gtOp.gtOp1->isContainedIntOrIImmed());
 
+#ifdef FEATURE_HW_INTRINSICS
+        case GT_HWIntrinsic:
+            return tree->isRMWHWIntrinsic(compiler);
+#endif // FEATURE_HW_INTRINSICS
+
         default:
             return true;
     }
@@ -2309,30 +2314,6 @@ void LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree)
         }
     }
 
-    if (!compiler->canUseVexEncoding())
-    {
-        // On machines without VEX support, we sometimes have to inject an intermediate
-        // `movaps targetReg, op1Reg` in order to maintain the correct behavior. This
-        // becomes a problem if `op2Reg == targetReg` since that means we will overwrite
-        // op2. In order to resolve this, we currently mark the second operand as delay free.
-
-        if ((flags & HW_Flag_NoRMWSemantics) == 0)
-        {
-            assert(category != HW_Category_MemoryLoad);
-            assert(category != HW_Category_MemoryStore);
-
-            assert((flags & HW_Flag_NoCodeGen) == 0);
-
-            if (info->srcCount >= 2)
-            {
-                assert(numArgs >= 2);
-                LocationInfoListNode* op2Info = useList.Begin()->Next();
-                op2Info->info.isDelayFree     = true;
-                info->hasDelayFreeSrc         = true;
-            }
-        }
-    }
-
     switch (intrinsicID)
     {
         case NI_SSE_CompareEqualOrderedScalar: