Don't struct-promote opaque vectors
authorCarol Eidt <carol.eidt@microsoft.com>
Fri, 30 Nov 2018 23:02:00 +0000 (15:02 -0800)
committerCarol Eidt <carol.eidt@microsoft.com>
Sat, 1 Dec 2018 16:09:54 +0000 (08:09 -0800)
The hardware vector types: `Vector64<T>`, `Vector128<T>` and `Vector256<T>` are declared
as having one or more fields of `ulong`. However, the JIT shouldn't be promoting these
fields to local variables. It is almost never the right type, and the intrinsics in any
case are not designed to cooperate with promoted fields (i.e. an index of a `Vector<ulong>`
won't map to the promoted lclVar).

Most importantly, it causes all copies of the vector to be done as 64-bit integer loads
and stores.

Finally, it will be important, as we support vector ABIs, to distinguish the handling of
the fixed-size vectors (`Vector2`, `Vector3` and `Vector4`) which *are* considered to be
normal structs of N floats, from the opaque types which will be passed in vector registers.

Commit migrated from https://github.com/dotnet/coreclr/commit/f06134ed869442f28cb0ab47ef2372d539a7e5af

src/coreclr/src/jit/compiler.h
src/coreclr/src/jit/morph.cpp

index 986f0ab..1a381ab 100644 (file)
@@ -7640,6 +7640,17 @@ private:
         return NO_CLASS_HANDLE;
     }
 
+    // Returns true if this is a SIMD type that should be considered an opaque
+    // vector type (i.e. do not analyze or promote its fields).
+    // Note that all but the fixed vector types are opaque, even though they may
+    // actually be declared as having fields.
+    bool isOpaqueSIMDType(CORINFO_CLASS_HANDLE structHandle)
+    {
+        return ((m_simdHandleCache != nullptr) && (structHandle != m_simdHandleCache->SIMDVector2Handle) &&
+                (structHandle != m_simdHandleCache->SIMDVector3Handle) &&
+                (structHandle != m_simdHandleCache->SIMDVector4Handle));
+    }
+
     // Returns true if the tree corresponds to a TYP_SIMD lcl var.
     // Note that both SIMD vector args and locals are mared as lvSIMDType = true, but
     // type of an arg node is TYP_BYREF and a local node is TYP_SIMD or TYP_STRUCT.
@@ -7648,6 +7659,16 @@ private:
         return tree->OperIsLocal() && lvaTable[tree->AsLclVarCommon()->gtLclNum].lvSIMDType;
     }
 
+    // Returns true if the lclVar is an opaque SIMD type.
+    bool isOpaqueSIMDLclVar(LclVarDsc* varDsc)
+    {
+        if (!varDsc->lvSIMDType)
+        {
+            return false;
+        }
+        return isOpaqueSIMDType(varDsc->lvVerTypeInfo.GetClassHandle());
+    }
+
     // Returns true if the type of the tree is a byref of TYP_SIMD
     bool isAddrOfSIMDType(GenTree* tree)
     {
@@ -7987,6 +8008,11 @@ private:
         return lvaSIMDInitTempVarNum;
     }
 
+#else  // !FEATURE_SIMD
+    bool isOpaqueSIMDLclVar(LclVarDsc* varDsc)
+    {
+        return false;
+    }
 #endif // FEATURE_SIMD
 
 public:
index 20e378e..83704cb 100644 (file)
@@ -16973,7 +16973,7 @@ void Compiler::fgPromoteStructs()
 
         // If we have marked this as lvUsedInSIMDIntrinsic, then we do not want to promote
         // its fields.  Instead, we will attempt to enregister the entire struct.
-        if (varDsc->lvIsSIMDType() && varDsc->lvIsUsedInSIMDIntrinsic())
+        if (varDsc->lvIsSIMDType() && (varDsc->lvIsUsedInSIMDIntrinsic() || isOpaqueSIMDLclVar(varDsc)))
         {
             varDsc->lvRegStruct = true;
         }