From: Egor Chesakov Date: Tue, 9 Oct 2018 18:37:02 +0000 (-0700) Subject: [arm64] Fix GitHub 20211 Issue (#20240) X-Git-Tag: accepted/tizen/unified/20190422.045933~1046 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8aebd79e8cc3820875457471a543a5fc7cbe0cc4;p=platform%2Fupstream%2Fcoreclr.git [arm64] Fix GitHub 20211 Issue (#20240) Bug with lowering SIMDIntrinsicGetItem on ARM64 when INS_mov (move w/o sign-extension) was used to copy signed value from Vn.b[i] (or Vn.h[i]) to general register Wd (or Xd) instead of INS_smov (move with sign-extension). --- diff --git a/src/jit/codegenarm64.cpp b/src/jit/codegenarm64.cpp index cd169d9..3870f2d 100644 --- a/src/jit/codegenarm64.cpp +++ b/src/jit/codegenarm64.cpp @@ -4601,8 +4601,28 @@ void CodeGen::genSIMDIntrinsicGetItem(GenTreeSIMD* simdNode) assert(op1->isUsedFromReg()); regNumber srcReg = op1->gtRegNum; - // mov targetReg, srcReg[#index] - getEmitter()->emitIns_R_R_I(INS_mov, baseTypeSize, targetReg, srcReg, index); + instruction ins; + if (varTypeIsFloating(baseType)) + { + assert(genIsValidFloatReg(targetReg)); + // dup targetReg, srcReg[#index] + ins = INS_dup; + } + else + { + assert(genIsValidIntReg(targetReg)); + if (varTypeIsUnsigned(baseType) || (baseTypeSize == EA_8BYTE)) + { + // umov targetReg, srcReg[#index] + ins = INS_umov; + } + else + { + // smov targetReg, srcReg[#index] + ins = INS_smov; + } + } + getEmitter()->emitIns_R_R_I(ins, baseTypeSize, targetReg, srcReg, index); } } } diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_20211/GitHub_20211.cs b/tests/src/JIT/Regression/JitBlue/GitHub_20211/GitHub_20211.cs new file mode 100644 index 0000000..66ead46 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_20211/GitHub_20211.cs @@ -0,0 +1,252 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +// GitHub 20211: bug with lowering SIMDIntrinsicGetItem on ARM64 +// when INS_mov (move w/o sign-extension) was used to copy signed value +// from Vn.b[i] (or Vn.h[i]) to general register Wd (or Xd) instead of +// INS_smov (move with sign-extension). + +namespace GitHub_20211 +{ + class Program + { + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe sbyte SquareRootAt0(Vector arg) + { + return (sbyte)Math.Sqrt(arg[0]); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe byte SquareRootAt0(Vector arg) + { + return (byte)Math.Sqrt(arg[0]); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe short SquareRootAt0(Vector arg) + { + return (short)Math.Sqrt(arg[0]); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe ushort SquareRootAt0(Vector arg) + { + return (ushort)Math.Sqrt(arg[0]); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe int SquareRootAt0(Vector arg) + { + return (int)Math.Sqrt(arg[0]); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe uint SquareRootAt0(Vector arg) + { + return (uint)Math.Sqrt(arg[0]); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe long SquareRootAt0(Vector arg) + { + return (long)Math.Sqrt(arg[0]); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe ulong SquareRootAt0(Vector arg) + { + return (ulong)Math.Sqrt(arg[0]); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe float SquareRootAt0(Vector arg) + { + return (float)Math.Sqrt(arg[0]); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe double SquareRootAt0(Vector arg) + { + return (double)Math.Sqrt(arg[0]); + } + + enum Result { Pass, Fail } + + struct TestRunner + { + void TestSquareRootAt0(sbyte arg0) + { + Vector arg = new Vector(arg0); + sbyte actual = SquareRootAt0(arg); + sbyte expected = (sbyte)Math.Sqrt(arg0); + + if (actual != expected) + { + Console.WriteLine($"Fail: sbyte (actual={actual}, expected={expected})"); + result = Result.Fail; + } + } + + void TestSquareRootAt0(byte arg0) + { + Vector arg = new Vector(arg0); + byte actual = SquareRootAt0(arg); + byte expected = (byte)Math.Sqrt(arg0); + + if (actual != expected) + { + Console.WriteLine($"Fail: byte (actual={actual}, expected={expected})"); + result = Result.Fail; + } + } + + void TestSquareRootAt0(short arg0) + { + Vector arg = new Vector(arg0); + short actual = SquareRootAt0(arg); + short expected = (short)Math.Sqrt(arg0); + + if (actual != expected) + { + Console.WriteLine($"Fail: short (actual={actual}, expected={expected})"); + result = Result.Fail; + } + } + + void TestSquareRootAt0(ushort arg0) + { + Vector arg = new Vector(arg0); + ushort actual = SquareRootAt0(arg); + ushort expected = (ushort)Math.Sqrt(arg0); + + if (actual != expected) + { + Console.WriteLine($"Fail: ushort (actual={actual}, expected={expected})"); + result = Result.Fail; + } + } + + void TestSquareRootAt0(int arg0) + { + Vector arg = new Vector(arg0); + int actual = SquareRootAt0(arg); + int expected = (int)Math.Sqrt(arg0); + + if (actual != expected) + { + Console.WriteLine($"Fail: int (actual={actual}, expected={expected})"); + result = Result.Fail; + } + } + + void TestSquareRootAt0(uint arg0) + { + Vector arg = new Vector(arg0); + uint actual = SquareRootAt0(arg); + uint expected = (uint)Math.Sqrt(arg0); + + if (actual != expected) + { + Console.WriteLine($"Fail: uint (actual={actual}, expected={expected})"); + result = Result.Fail; + } + } + + void TestSquareRootAt0(long arg0) + { + Vector arg = new Vector(arg0); + long actual = SquareRootAt0(arg); + long expected = (long)Math.Sqrt(arg0); + + if (actual != expected) + { + Console.WriteLine($"Fail: long (actual={actual}, expected={expected})"); + result = Result.Fail; + } + } + + void TestSquareRootAt0(ulong arg0) + { + Vector arg = new Vector(arg0); + ulong actual = SquareRootAt0(arg); + ulong expected = (ulong)Math.Sqrt(arg0); + + if (actual != expected) + { + Console.WriteLine($"Fail: ulong (actual={actual}, expected={expected})"); + result = Result.Fail; + } + } + + void TestSquareRootAt0(float arg0) + { + Vector arg = new Vector(arg0); + float actual = SquareRootAt0(arg); + float expected = (float)Math.Sqrt(arg0); + + if (actual != expected) + { + Console.WriteLine($"Fail: float (actual={actual}, expected={expected})"); + result = Result.Fail; + } + } + + void TestSquareRootAt0(double arg0) + { + Vector arg = new Vector(arg0); + double actual = SquareRootAt0(arg); + double expected = (double)Math.Sqrt(arg0); + + if (actual != expected) + { + Console.WriteLine($"Fail: double (actual={actual}, expected={expected})"); + result = Result.Fail; + } + } + + Result result; + + public Result Run() + { + result = Result.Pass; + + TestSquareRootAt0((sbyte)-1); + TestSquareRootAt0((short)-1); + TestSquareRootAt0((int)-1); + TestSquareRootAt0((long)-1); + + TestSquareRootAt0((sbyte)1); + TestSquareRootAt0((byte)1); + TestSquareRootAt0((short)1); + TestSquareRootAt0((ushort)1); + TestSquareRootAt0((int)1); + TestSquareRootAt0((uint)1); + TestSquareRootAt0((long)1); + TestSquareRootAt0((ulong)1); + + TestSquareRootAt0((float)4); + TestSquareRootAt0((double)4); + + return result; + } + } + + static int Main(string[] args) + { + if (new TestRunner().Run() == Result.Pass) + { + Console.WriteLine("Pass"); + return 100; + } + else + { + return 0; + } + } + } +} diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_20211/GitHub_20211.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_20211/GitHub_20211.csproj new file mode 100644 index 0000000..301c10f --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_20211/GitHub_20211.csproj @@ -0,0 +1,35 @@ + + + + + Debug + AnyCPU + $(MSBuildProjectName) + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + + + + + + + False + + + + None + True + + + + + + + + + + diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_20211/GitHub_20211.tt b/tests/src/JIT/Regression/JitBlue/GitHub_20211/GitHub_20211.tt new file mode 100644 index 0000000..3d8e2eb --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_20211/GitHub_20211.tt @@ -0,0 +1,98 @@ +<#@ template debug="false" hostspecific="true" language="C#" #> +<#@ output extension=".cs" #> +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +// GitHub 20211: bug with lowering SIMDIntrinsicGetItem on ARM64 +// when INS_mov (move w/o sign-extension) was used to copy signed value +// from Vn.b[i] (or Vn.h[i]) to general register Wd (or Xd) instead of +// INS_smov (move with sign-extension). + +namespace GitHub_20211 +{ + class Program + { +<# + string[] typeNames = { "sbyte", "byte", "short", "ushort", "int", "uint", "long", "ulong", "float", "double" }; + foreach (string typeName in typeNames) + { +#> + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe <#= typeName #> SquareRootAt0(Vector<<#= typeName #>> arg) + { + return (<#= typeName #>)Math.Sqrt(arg[0]); + } + +<# + } +#> + enum Result { Pass, Fail } + + struct TestRunner + { +<# + foreach (string typeName in typeNames) + { +#> + void TestSquareRootAt0(<#= typeName #> arg0) + { + Vector<<#= typeName #>> arg = new Vector<<#= typeName #>>(arg0); + <#= typeName #> actual = SquareRootAt0(arg); + <#= typeName #> expected = (<#= typeName #>)Math.Sqrt(arg0); + + if (actual != expected) + { + Console.WriteLine($"Fail: <#= typeName #> (actual={actual}, expected={expected})"); + result = Result.Fail; + } + } + +<# + } +#> + Result result; + + public Result Run() + { + result = Result.Pass; + + TestSquareRootAt0((sbyte)-1); + TestSquareRootAt0((short)-1); + TestSquareRootAt0((int)-1); + TestSquareRootAt0((long)-1); + + TestSquareRootAt0((sbyte)1); + TestSquareRootAt0((byte)1); + TestSquareRootAt0((short)1); + TestSquareRootAt0((ushort)1); + TestSquareRootAt0((int)1); + TestSquareRootAt0((uint)1); + TestSquareRootAt0((long)1); + TestSquareRootAt0((ulong)1); + + TestSquareRootAt0((float)4); + TestSquareRootAt0((double)4); + + return result; + } + } + + static int Main(string[] args) + { + if (new TestRunner().Run() == Result.Pass) + { + Console.WriteLine("Pass"); + return 100; + } + else + { + return 0; + } + } + } +}