From 76b4b48489a249c037f15b5d1c66393c149151d8 Mon Sep 17 00:00:00 2001 From: Carol Eidt Date: Wed, 3 Jan 2018 17:45:07 -0800 Subject: [PATCH] Keep OBJ on mismatched struct assignment In a mismatched struct assignment, e.g. using Unsafe.As, we need to retain the OBJ(ADDR(lcl)) on the rhs of the assignment. Fix #15237 --- src/jit/morph.cpp | 2 +- .../JitBlue/GitHub_15237/GitHub_15237.cs | 148 +++++++++++++++++++++ .../JitBlue/GitHub_15237/GitHub_15237.csproj | 41 ++++++ 3 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_15237/GitHub_15237.cs create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_15237/GitHub_15237.csproj diff --git a/src/jit/morph.cpp b/src/jit/morph.cpp index 5e785f6..f85bafb 100644 --- a/src/jit/morph.cpp +++ b/src/jit/morph.cpp @@ -10208,7 +10208,7 @@ GenTree* Compiler::fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigne if (lclNode != nullptr) { LclVarDsc* varDsc = &(lvaTable[lclNode->gtLclNum]); - if (varTypeIsStruct(varDsc) && (varDsc->lvExactSize == blockWidth)) + if (varTypeIsStruct(varDsc) && (varDsc->lvType == asgType)) { #ifndef LEGACY_BACKEND effectiveVal = lclNode; diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_15237/GitHub_15237.cs b/tests/src/JIT/Regression/JitBlue/GitHub_15237/GitHub_15237.cs new file mode 100644 index 0000000..2e1b7a0 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_15237/GitHub_15237.cs @@ -0,0 +1,148 @@ +using System; +using System.Globalization; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace UnsafeTesting +{ + public class Program + { + static int Main(string[] args) + { + float UnsafeAs = LengthSquaredUnsafeAs(); + Console.WriteLine($"Unsafe.As : {UnsafeAs}"); + float UnsafeRead = LengthSquaredUnsafeRead(); + Console.WriteLine($"Unsafe.Read : {UnsafeRead}"); + float UnsafeReadUnaligned = LengthSquaredUnsafeReadUnaligned(); + Console.WriteLine($"Unsafe.ReadUnaligned: {UnsafeReadUnaligned}"); + float NoVectors = LengthSquaredUnsafeReadUnaligned(); + Console.WriteLine($"No Vectors : {NoVectors}"); + float ManualVectors = LengthSquaredUnsafeReadUnaligned(); + Console.WriteLine($"Manual Vectors : {ManualVectors}"); + if ((Math.Abs(UnsafeAs - ManualVectors) > Single.Epsilon) || + (Math.Abs(UnsafeRead - ManualVectors) > Single.Epsilon) || + (Math.Abs(UnsafeReadUnaligned - ManualVectors) > Single.Epsilon) || + (Math.Abs(NoVectors - ManualVectors) > Single.Epsilon)) + { + Console.WriteLine("FAIL"); + return -1; + } + else + { + Console.WriteLine("PASS"); + return 100; + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float LengthSquaredUnsafeAs() + { + QuaternionStruct start = new QuaternionStruct(8.5f, 9.4f, 1.2f, 1f); + + return start.LengthSquaredUnsafeAs(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float LengthSquaredUnsafeRead() + { + QuaternionStruct start = new QuaternionStruct(8.5f, 9.4f, 1.2f, 1f); + + return start.LengthSquaredUnsafeRead(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float LengthSquaredUnsafeReadUnaligned() + { + QuaternionStruct start = new QuaternionStruct(8.5f, 9.4f, 1.2f, 1f); + + return start.LengthSquaredUnsafeReadUnaligned(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float LengthSquaredNoVectors() + { + QuaternionStruct start = new QuaternionStruct(8.5f, 9.4f, 1.2f, 1f); + + return start.LengthSquaredNoVectors(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float LengthSquaredManualVectors() + { + QuaternionStruct start = new QuaternionStruct(8.5f, 9.4f, 1.2f, 1f); + + return start.LengthSquaredManualVectors(); + } + } + + public struct QuaternionStruct : IEquatable + { + public float X; + public float Y; + public float Z; + public float W; + + public QuaternionStruct(float x, float y, float z, float w) + { + this.X = x; + this.Y = y; + this.Z = z; + this.W = w; + } + + public float LengthSquaredManualVectors() => ToVector4(this).LengthSquared(); + + public float LengthSquaredUnsafeAs() + { + Vector4 q = Unsafe.As(ref this); + + return q.LengthSquared(); + } + + public unsafe float LengthSquaredUnsafeRead() + { + fixed (QuaternionStruct* p = &this) + { + Vector4 q = Unsafe.Read(p); + + return q.LengthSquared(); + } + } + + public float LengthSquaredUnsafeReadUnaligned() + { + Vector4 q = Unsafe.ReadUnaligned(ref Unsafe.As(ref this)); + + return q.LengthSquared(); + } + + public float LengthSquaredNoVectors() + { + return X * X + Y * Y + Z * Z + W * W; + } + + public bool Equals(QuaternionStruct other) + { + throw new NotImplementedException(); + } + + public override string ToString() + { + CultureInfo ci = CultureInfo.CurrentCulture; + + return $"{{X:{X.ToString(ci)} Y:{Y.ToString(ci)} Z:{Z.ToString(ci)} W:{W.ToString(ci)}}}"; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static QuaternionStruct FromVector4(Vector4 vector) + { + return new QuaternionStruct(vector.X, vector.Y, vector.Z, vector.W); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector4 ToVector4(QuaternionStruct quaternionStruct) + { + return new Vector4(quaternionStruct.X, quaternionStruct.Y, quaternionStruct.Z, quaternionStruct.W); + } + } +} diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_15237/GitHub_15237.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_15237/GitHub_15237.csproj new file mode 100644 index 0000000..1b7f8a7 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_15237/GitHub_15237.csproj @@ -0,0 +1,41 @@ + + + + + Debug + AnyCPU + $(MSBuildProjectName) + 2.0 + {76E69AA0-8C5A-4F76-8561-B8089FFA8D79} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + + + + + + + + + + False + + + + + True + True + + + + + + + + + + + $(JitPackagesConfigFileDirectory)benchmark\obj\project.assets.json + + -- 2.7.4