From ed5f297a1c76e1e12da427355b6cc184f93175f7 Mon Sep 17 00:00:00 2001 From: Jonathan Davies Date: Fri, 7 Nov 2025 08:13:55 +0000 Subject: [PATCH 1/2] wip --- src/coreclr/jit/lower.cpp | 68 ++- .../InstructionCombining/CastRightShift.cs | 404 ++++++++++++++++++ .../CastRightShift.csproj | 17 + 3 files changed, 471 insertions(+), 18 deletions(-) create mode 100644 src/tests/JIT/opt/InstructionCombining/CastRightShift.cs create mode 100644 src/tests/JIT/opt/InstructionCombining/CastRightShift.csproj diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 25e5db40c20c6c..e7fa2c1241f07e 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -8407,29 +8407,61 @@ void Lowering::LowerShift(GenTreeOp* shift) ContainCheckShiftRotate(shift); #ifdef TARGET_ARM64 - // Try to recognize ubfiz/sbfiz idiom in LSH(CAST(X), CNS) tree - if (comp->opts.OptimizationEnabled() && shift->OperIs(GT_LSH) && shift->gtGetOp1()->OperIs(GT_CAST) && - shift->gtGetOp2()->IsCnsIntOrI() && !shift->isContained()) + GenTree* op1 = shift->gtGetOp1(); + GenTree* op2 = shift->gtGetOp2(); + + if (comp->opts.OptimizationEnabled() && op1->OperIs(GT_CAST) && op2->IsCnsIntOrI()) { - GenTreeIntCon* cns = shift->gtGetOp2()->AsIntCon(); - GenTreeCast* cast = shift->gtGetOp1()->AsCast(); + // Try to recognize ubfiz/sbfiz idiom in LSH(CAST(X), CNS) tree + if (shift->OperIs(GT_LSH) && !shift->isContained()) + { + GenTreeIntCon* cns = op2->AsIntCon(); + GenTreeCast* cast = op1->AsCast(); + + if (!cast->isContained() && !cast->IsRegOptional() && !cast->gtOverflow() && + // Smaller CastOp is most likely an IND(X) node which is lowered to a zero-extend load + cast->CastOp()->TypeIs(TYP_LONG, TYP_INT)) + { + // Cast is either "TYP_LONG <- TYP_INT" or "TYP_INT <- %SMALL_INT% <- TYP_INT" (signed or unsigned) + unsigned dstBits = genTypeSize(cast) * BITS_PER_BYTE; + unsigned srcBits = varTypeIsSmall(cast->CastToType()) ? genTypeSize(cast->CastToType()) * BITS_PER_BYTE + : genTypeSize(cast->CastOp()) * BITS_PER_BYTE; + + // It has to be an upcast and CNS must be in [1..srcBits) range + if ((srcBits < dstBits) && (cns->IconValue() > 0) && (cns->IconValue() < srcBits)) + { + JITDUMP("Recognized ubfix/sbfix pattern in LSH(CAST, CNS). Changing op to GT_BFIZ"); + shift->ChangeOper(GT_BFIZ); + cast->CastOp()->ClearContained(); // Uncontain any memory operands. + MakeSrcContained(shift, cast); + } + } + } - if (!cast->isContained() && !cast->IsRegOptional() && !cast->gtOverflow() && - // Smaller CastOp is most likely an IND(X) node which is lowered to a zero-extend load - cast->CastOp()->TypeIs(TYP_LONG, TYP_INT)) + // Try to recognize right shift with a CAST node that is equivilent to mov #0 + if (shift->OperIs(GT_RSH, GT_RSZ)) { - // Cast is either "TYP_LONG <- TYP_INT" or "TYP_INT <- %SMALL_INT% <- TYP_INT" (signed or unsigned) - unsigned dstBits = genTypeSize(cast) * BITS_PER_BYTE; - unsigned srcBits = varTypeIsSmall(cast->CastToType()) ? genTypeSize(cast->CastToType()) * BITS_PER_BYTE - : genTypeSize(cast->CastOp()) * BITS_PER_BYTE; + GenTreeCast* cast = op1->AsCast(); + GenTreeIntCon* cns = op2->AsIntCon(); - // It has to be an upcast and CNS must be in [1..srcBits) range - if ((srcBits < dstBits) && (cns->IconValue() > 0) && (cns->IconValue() < srcBits)) + if (!cast->isContained() && !cast->IsRegOptional() && !cast->gtOverflow() && + cast->CastOp()->TypeIs(TYP_INT)) { - JITDUMP("Recognized ubfix/sbfix pattern in LSH(CAST, CNS). Changing op to GT_BFIZ"); - shift->ChangeOper(GT_BFIZ); - cast->CastOp()->ClearContained(); // Uncontain any memory operands. - MakeSrcContained(shift, cast); + unsigned srcBits = genTypeSize(cast->CastToType()) * BITS_PER_BYTE; + if (cns->IconValue() >= srcBits) + { + GenTree* zero = comp->gtNewIconNode(0, TYP_INT); + LIR::Use use; + if (BlockRange().TryGetUse(shift, &use)) + { + use.ReplaceWith(zero); + } + BlockRange().InsertBefore(shift, zero); + BlockRange().Remove(op1->gtGetOp1()); + BlockRange().Remove(op1); + BlockRange().Remove(op2); + BlockRange().Remove(shift); + } } } } diff --git a/src/tests/JIT/opt/InstructionCombining/CastRightShift.cs b/src/tests/JIT/opt/InstructionCombining/CastRightShift.cs new file mode 100644 index 00000000000000..28b1550078beb8 --- /dev/null +++ b/src/tests/JIT/opt/InstructionCombining/CastRightShift.cs @@ -0,0 +1,404 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using Xunit; + +namespace TestCastRightShift +{ + public class Program + { + [MethodImpl(MethodImplOptions.NoInlining)] + [Fact] + public static int CheckCastRightShift() + { + bool fail = false; + + { + var r = CastASR7_byte_int(255); + if (r == 0) { Console.WriteLine($"CastASR7_byte_int(255) = {r} should be non-zero"); fail = true; } + } + + { + var r = CastASR8_byte_int(255); + if (r != 0) { Console.WriteLine($"CastASR8_byte_int(255) = {r} should be 0"); fail = true; } + } + + { + var r = CastLSR7_byte_uint(255); + if (r != 1U) { Console.WriteLine($"CastLSR7_byte_uint(255) = {r} should be 1"); fail = true; } + } + + { + var r = CastLSR8_byte_uint(255); + if (r != 0U) { Console.WriteLine($"CastLSR8_byte_uint(255) = {r} should be 0"); fail = true; } + } + + { + var r = CastASR7_byte_long(255); + if (r == 0L) { Console.WriteLine($"CastASR7_byte_long(255) = {r} should be non-zero"); fail = true; } + } + + { + var r = CastASR8_byte_long(255); + if (r != 0L) { Console.WriteLine($"CastASR8_byte_long(255) = {r} should be 0"); fail = true; } + } + + { + var r = CastLSR7_byte_ulong(255); + if (r == 0UL) { Console.WriteLine($"CastLSR7_byte_ulong(255) = {r} should be non-zero"); fail = true; } + } + + { + var r = CastLSR8_byte_ulong(255); + if (r != 0UL) { Console.WriteLine($"CastLSR8_byte_ulong(255) = {r} should be 0"); fail = true; } + } + + { + var r = CastASR7_sbyte_int(-127); + if (r == 0) { Console.WriteLine($"CastASR7_sbyte_int(-127) = {r} should be non-zero"); fail = true; } + } + + // Console.WriteLine($"{-127 >> 6}"); + // Console.WriteLine($"{-127 >> 7}"); + + { + var x = foo6(-127); + Console.WriteLine($"foo6(-127) = {x}"); + } + + { + var x = foo7(-127); + Console.WriteLine($"foo7(-127) = {x}"); + } + + { + var x = foo8(-127); + Console.WriteLine($"foo8(-127) = {x}"); + } + + { + var x = CastASR6_sbyte_int(-127); + Console.WriteLine($"CastASR6_sbyte_int(-127) = {x}"); + } + + { + var x = CastASR7_sbyte_int(-127); + Console.WriteLine($"CastASR7_sbyte_int(-127) = {x}"); + } + + { + var x = CastASR8_sbyte_int(-127); + Console.WriteLine($"CastASR8_sbyte_int(-127) = {x}"); + } + + { + var r = CastASR8_sbyte_int(-127); + if (r != 0) { Console.WriteLine($"CastASR8_sbyte_int(-127) = {r} should be 0"); fail = true; } + } + + { + var r = CastASR7_sbyte_long(-127); + if (r == 0L) { Console.WriteLine($"CastASR7_sbyte_long(-127) = {r} should be non-zero"); fail = true; } + } + + { + var r = CastASR8_sbyte_long(-127); + if (r != 0L) { Console.WriteLine($"CastASR8_sbyte_long(-127) = {r} should be 0"); fail = true; } + } + + { + var r = CastASR15_ushort_int(65535); + if (r == 0) { Console.WriteLine($"CastASR15_ushort_int(65535) = {r} should be non-zero"); fail = true; } + } + + { + var r = CastASR16_ushort_int(65535); + if (r != 0) { Console.WriteLine($"CastASR16_ushort_int(65535) = {r} should be 0"); fail = true; } + } + + { + var r = CastLSR15_ushort_uint(65535); + if (r == 0U) { Console.WriteLine($"CastLSR15_ushort_uint(65535) = {r} should be non-zero"); fail = true; } + } + + { + var r = CastLSR16_ushort_uint(65535); + if (r != 0U) { Console.WriteLine($"CastLSR16_ushort_uint(65535) = {r} should be 0"); fail = true; } + } + + { + var r = CastASR15_ushort_long(65535); + if (r == 0L) { Console.WriteLine($"CastASR15_ushort_long(65535) = {r} should be non-zero"); fail = true; } + } + + { + var r = CastASR16_ushort_long(65535); + if (r != 0L) { Console.WriteLine($"CastASR16_ushort_long(65535) = {r} should be 0"); fail = true; } + } + + { + var r = CastLSR15_ushort_ulong(65535); + if (r == 0UL) { Console.WriteLine($"CastLSR15_ushort_ulong(65535) = {r} should be non-zero"); fail = true; } + } + + { + var r = CastLSR16_ushort_ulong(65535); + if (r != 0UL) { Console.WriteLine($"CastLSR16_ushort_ulong(65535) = {r} should be 0"); fail = true; } + } + + { + var r = CastASR15_short_int(-1); + if (r == 0) { Console.WriteLine($"CastASR15_short_int(-1) = {r} should be non-zero"); fail = true; } + } + + { + var r = CastASR16_short_int(-1); + if (r != 0) { Console.WriteLine($"CastASR16_short_int(-1) = {r} should be 0"); fail = true; } + } + + { + var r = CastASR15_short_long(-1); + if (r == 0L) { Console.WriteLine($"CastASR15_short_long(-1) = {r} should be non-zero"); fail = true; } + } + + { + var r = CastASR16_short_long(-1); + if (r != 0L) { Console.WriteLine($"CastASR16_short_long(-1) = {r} should be 0"); fail = true; } + } + + if (fail) + { + return 101; + } + return 100; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int CastASR7_byte_int(int x) + { + //ARM64-FULL-LINE: uxtb {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: asr {{w[0-9]+}}, {{w[0-9]+}}, #7 + return (byte)x >> 7; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int CastASR8_byte_int(int x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, wzr + return (byte)x >> 8; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static uint CastLSR7_byte_uint(int x) + { + //ARM64-FULL-LINE: uxtb {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: lsr {{w[0-9]+}}, {{w[0-9]+}}, #7 + return (uint)(byte)x >> 7; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static uint CastLSR8_byte_uint(int x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, wzr + return (uint)(byte)x >> 8; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static long CastASR7_byte_long(int x) + { + //ARM64-FULL-LINE: uxtb {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: asr {{w[0-9]+}}, {{w[0-9]+}}, #7 + //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} + return (byte)x >> 7; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static long CastASR8_byte_long(int x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, wzr + //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} + return (byte)x >> 8; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static ulong CastLSR7_byte_ulong(int x) + { + //ARM64-FULL-LINE: uxtb {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: mov {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: lsr {{x[0-9]+}}, {{x[0-9]+}}, #7 + return (ulong)(byte)x >> 7; + } + + // This produces the following tree section with 2 CASTs + // We should check all the CASTs and then check that the lsr value + // is greater than or equal to smallest src bits. In this case + // we could change to mov w0, wzr. + // * RSZ long + // +--* CAST long <- ulong + // | \--* CAST int <- ubyte <- int + // | \--* LCL_VAR int + [MethodImpl(MethodImplOptions.NoInlining)] + static ulong CastLSR8_byte_ulong(int x) + { + //ARM64-FULL-LINE: uxtb {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: mov {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: lsr {{x[0-9]+}}, {{x[0-9]+}}, #8 + return (ulong)(byte)x >> 8; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int CastASR6_sbyte_int(int x) + { + return (sbyte)x >> 6; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int CastASR7_sbyte_int(int x) + { + //ARM64-FULL-LINE: sxtb {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: asr {{w[0-9]+}}, {{w[0-9]+}}, #7 + return (sbyte)x >> 7; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int foo6(int x) + { + return x >> 6; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int foo7(int x) + { + return x >> 7; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int foo8(int x) + { + return x >> 8; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int CastASR8_sbyte_int(int x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, wzr + return (sbyte)x >> 8; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static long CastASR7_sbyte_long(int x) + { + //ARM64-FULL-LINE: sxtb {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: asr {{w[0-9]+}}, {{w[0-9]+}}, #7 + //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} + return (sbyte)x >> 7; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static long CastASR8_sbyte_long(int x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, wzr + //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} + return (sbyte)x >> 8; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int CastASR15_ushort_int(int x) + { + //ARM64-FULL-LINE: uxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: asr {{w[0-9]+}}, {{w[0-9]+}}, #15 + return (ushort)x >> 15; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int CastASR16_ushort_int(int x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, wzr + return (ushort)x >> 16; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static uint CastLSR15_ushort_uint(int x) + { + //ARM64-FULL-LINE: uxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: lsr {{w[0-9]+}}, {{w[0-9]+}}, #15 + return (uint)(ushort)x >> 15; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static uint CastLSR16_ushort_uint(int x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, wzr + return (uint)(ushort)x >> 16; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static long CastASR15_ushort_long(int x) + { + //ARM64-FULL-LINE: uxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: asr {{w[0-9]+}}, {{w[0-9]+}}, #15 + //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} + return (ushort)x >> 15; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static long CastASR16_ushort_long(int x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, wzr + //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} + return (ushort)x >> 16; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static ulong CastLSR15_ushort_ulong(int x) + { + //ARM64-FULL-LINE: uxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: mov {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: lsr {{x[0-9]+}}, {{x[0-9]+}}, #15 + return (ulong)(ushort)x >> 15; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static ulong CastLSR16_ushort_ulong(int x) + { + //ARM64-FULL-LINE: uxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: mov {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: lsr {{x[0-9]+}}, {{x[0-9]+}}, #16 + return (ulong)(ushort)x >> 16; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int CastASR15_short_int(int x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: asr {{w[0-9]+}}, {{w[0-9]+}}, #15 + return (short)x >> 15; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int CastASR16_short_int(int x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, wzr + return (short)x >> 16; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static long CastASR15_short_long(int x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: asr {{w[0-9]+}}, {{w[0-9]+}}, #15 + //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} + return (short)x >> 15; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static long CastASR16_short_long(int x) + { + //ARM64-FULL-LINE: mov {{w[0-9]+}}, wzr + //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} + return (short)x >> 16; + } + } +} diff --git a/src/tests/JIT/opt/InstructionCombining/CastRightShift.csproj b/src/tests/JIT/opt/InstructionCombining/CastRightShift.csproj new file mode 100644 index 00000000000000..7303d3cfafd9c9 --- /dev/null +++ b/src/tests/JIT/opt/InstructionCombining/CastRightShift.csproj @@ -0,0 +1,17 @@ + + + + true + + + None + True + + + + true + + + + + From 9670dddf80840833572b5d65e9174c092e77dd66 Mon Sep 17 00:00:00 2001 From: Jonathan Davies Date: Tue, 11 Nov 2025 14:52:29 +0000 Subject: [PATCH 2/2] Only unsigned --- src/coreclr/jit/lower.cpp | 2 +- .../InstructionCombining/CastRightShift.cs | 164 ++++++------------ 2 files changed, 57 insertions(+), 109 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index e7fa2c1241f07e..11c14b65a399f7 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -8445,7 +8445,7 @@ void Lowering::LowerShift(GenTreeOp* shift) GenTreeIntCon* cns = op2->AsIntCon(); if (!cast->isContained() && !cast->IsRegOptional() && !cast->gtOverflow() && - cast->CastOp()->TypeIs(TYP_INT)) + cast->CastOp()->TypeIs(TYP_INT) && varTypeIsUnsigned(cast->CastToType())) { unsigned srcBits = genTypeSize(cast->CastToType()) * BITS_PER_BYTE; if (cns->IconValue() >= srcBits) diff --git a/src/tests/JIT/opt/InstructionCombining/CastRightShift.cs b/src/tests/JIT/opt/InstructionCombining/CastRightShift.cs index 28b1550078beb8..a6548453f32d33 100644 --- a/src/tests/JIT/opt/InstructionCombining/CastRightShift.cs +++ b/src/tests/JIT/opt/InstructionCombining/CastRightShift.cs @@ -15,157 +15,125 @@ public static int CheckCastRightShift() { bool fail = false; - { - var r = CastASR7_byte_int(255); - if (r == 0) { Console.WriteLine($"CastASR7_byte_int(255) = {r} should be non-zero"); fail = true; } - } - - { - var r = CastASR8_byte_int(255); - if (r != 0) { Console.WriteLine($"CastASR8_byte_int(255) = {r} should be 0"); fail = true; } - } + if (CastASR7_byte_int(255) == 0) { - var r = CastLSR7_byte_uint(255); - if (r != 1U) { Console.WriteLine($"CastLSR7_byte_uint(255) = {r} should be 1"); fail = true; } + fail = true; } + if (CastASR8_byte_int(255) != 0) { - var r = CastLSR8_byte_uint(255); - if (r != 0U) { Console.WriteLine($"CastLSR8_byte_uint(255) = {r} should be 0"); fail = true; } + fail = true; } + if (CastLSR7_byte_uint(255) != 1) { - var r = CastASR7_byte_long(255); - if (r == 0L) { Console.WriteLine($"CastASR7_byte_long(255) = {r} should be non-zero"); fail = true; } + fail = true; } + if (CastLSR8_byte_uint(255) != 0) { - var r = CastASR8_byte_long(255); - if (r != 0L) { Console.WriteLine($"CastASR8_byte_long(255) = {r} should be 0"); fail = true; } + fail = true; } + if (CastASR7_byte_long(255) == 0) { - var r = CastLSR7_byte_ulong(255); - if (r == 0UL) { Console.WriteLine($"CastLSR7_byte_ulong(255) = {r} should be non-zero"); fail = true; } + fail = true; } + if (CastASR8_byte_long(255) != 0) { - var r = CastLSR8_byte_ulong(255); - if (r != 0UL) { Console.WriteLine($"CastLSR8_byte_ulong(255) = {r} should be 0"); fail = true; } + fail = true; } + if (CastLSR7_byte_ulong(255) == 0) { - var r = CastASR7_sbyte_int(-127); - if (r == 0) { Console.WriteLine($"CastASR7_sbyte_int(-127) = {r} should be non-zero"); fail = true; } + fail = true; } - // Console.WriteLine($"{-127 >> 6}"); - // Console.WriteLine($"{-127 >> 7}"); - + if (CastLSR8_byte_ulong(255) != 0) { - var x = foo6(-127); - Console.WriteLine($"foo6(-127) = {x}"); + fail = true; } + if (CastASR7_sbyte_int(-127) != -1) { - var x = foo7(-127); - Console.WriteLine($"foo7(-127) = {x}"); + fail = true; } + if (CastASR8_sbyte_int(-127) != -1) { - var x = foo8(-127); - Console.WriteLine($"foo8(-127) = {x}"); + fail = true; } + if (CastASR7_sbyte_long(-127) != -1) { - var x = CastASR6_sbyte_int(-127); - Console.WriteLine($"CastASR6_sbyte_int(-127) = {x}"); + fail = true; } + if (CastASR8_sbyte_long(-127) != -1) { - var x = CastASR7_sbyte_int(-127); - Console.WriteLine($"CastASR7_sbyte_int(-127) = {x}"); + fail = true; } + if (CastASR15_ushort_int(65535) == 0) { - var x = CastASR8_sbyte_int(-127); - Console.WriteLine($"CastASR8_sbyte_int(-127) = {x}"); + fail = true; } + if (CastASR16_ushort_int(65535) != 0) { - var r = CastASR8_sbyte_int(-127); - if (r != 0) { Console.WriteLine($"CastASR8_sbyte_int(-127) = {r} should be 0"); fail = true; } + fail = true; } + if (CastLSR15_ushort_uint(65535) == 0) { - var r = CastASR7_sbyte_long(-127); - if (r == 0L) { Console.WriteLine($"CastASR7_sbyte_long(-127) = {r} should be non-zero"); fail = true; } + fail = true; } + if (CastLSR16_ushort_uint(65535) != 0) { - var r = CastASR8_sbyte_long(-127); - if (r != 0L) { Console.WriteLine($"CastASR8_sbyte_long(-127) = {r} should be 0"); fail = true; } + fail = true; } + if (CastASR15_ushort_long(65535) == 0) { - var r = CastASR15_ushort_int(65535); - if (r == 0) { Console.WriteLine($"CastASR15_ushort_int(65535) = {r} should be non-zero"); fail = true; } + fail = true; } + if (CastASR16_ushort_long(65535) != 0) { - var r = CastASR16_ushort_int(65535); - if (r != 0) { Console.WriteLine($"CastASR16_ushort_int(65535) = {r} should be 0"); fail = true; } + fail = true; } + if (CastLSR15_ushort_ulong(65535) == 0) { - var r = CastLSR15_ushort_uint(65535); - if (r == 0U) { Console.WriteLine($"CastLSR15_ushort_uint(65535) = {r} should be non-zero"); fail = true; } + fail = true; } + if (CastLSR16_ushort_ulong(65535) != 0) { - var r = CastLSR16_ushort_uint(65535); - if (r != 0U) { Console.WriteLine($"CastLSR16_ushort_uint(65535) = {r} should be 0"); fail = true; } + fail = true; } + if (CastASR15_short_int(-1) != -1) { - var r = CastASR15_ushort_long(65535); - if (r == 0L) { Console.WriteLine($"CastASR15_ushort_long(65535) = {r} should be non-zero"); fail = true; } + fail = true; } + if (CastASR16_short_int(-1) != -1) { - var r = CastASR16_ushort_long(65535); - if (r != 0L) { Console.WriteLine($"CastASR16_ushort_long(65535) = {r} should be 0"); fail = true; } + fail = true; } + if (CastASR15_short_long(-1) != -1) { - var r = CastLSR15_ushort_ulong(65535); - if (r == 0UL) { Console.WriteLine($"CastLSR15_ushort_ulong(65535) = {r} should be non-zero"); fail = true; } + fail = true; } + if (CastASR16_short_long(-1) != -1) { - var r = CastLSR16_ushort_ulong(65535); - if (r != 0UL) { Console.WriteLine($"CastLSR16_ushort_ulong(65535) = {r} should be 0"); fail = true; } - } - - { - var r = CastASR15_short_int(-1); - if (r == 0) { Console.WriteLine($"CastASR15_short_int(-1) = {r} should be non-zero"); fail = true; } - } - - { - var r = CastASR16_short_int(-1); - if (r != 0) { Console.WriteLine($"CastASR16_short_int(-1) = {r} should be 0"); fail = true; } - } - - { - var r = CastASR15_short_long(-1); - if (r == 0L) { Console.WriteLine($"CastASR15_short_long(-1) = {r} should be non-zero"); fail = true; } - } - - { - var r = CastASR16_short_long(-1); - if (r != 0L) { Console.WriteLine($"CastASR16_short_long(-1) = {r} should be 0"); fail = true; } + fail = true; } if (fail) @@ -248,12 +216,6 @@ static ulong CastLSR8_byte_ulong(int x) return (ulong)(byte)x >> 8; } - [MethodImpl(MethodImplOptions.NoInlining)] - static int CastASR6_sbyte_int(int x) - { - return (sbyte)x >> 6; - } - [MethodImpl(MethodImplOptions.NoInlining)] static int CastASR7_sbyte_int(int x) { @@ -262,28 +224,11 @@ static int CastASR7_sbyte_int(int x) return (sbyte)x >> 7; } - [MethodImpl(MethodImplOptions.NoInlining)] - static int foo6(int x) - { - return x >> 6; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - static int foo7(int x) - { - return x >> 7; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - static int foo8(int x) - { - return x >> 8; - } - [MethodImpl(MethodImplOptions.NoInlining)] static int CastASR8_sbyte_int(int x) { - //ARM64-FULL-LINE: mov {{w[0-9]+}}, wzr + //ARM64-FULL-LINE: sxtb {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: asr {{w[0-9]+}}, {{w[0-9]+}}, #8 return (sbyte)x >> 8; } @@ -299,7 +244,8 @@ static long CastASR7_sbyte_long(int x) [MethodImpl(MethodImplOptions.NoInlining)] static long CastASR8_sbyte_long(int x) { - //ARM64-FULL-LINE: mov {{w[0-9]+}}, wzr + //ARM64-FULL-LINE: sxtb {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: asr {{w[0-9]+}}, {{w[0-9]+}}, #8 //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} return (sbyte)x >> 8; } @@ -380,7 +326,8 @@ static int CastASR15_short_int(int x) [MethodImpl(MethodImplOptions.NoInlining)] static int CastASR16_short_int(int x) { - //ARM64-FULL-LINE: mov {{w[0-9]+}}, wzr + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: asr {{w[0-9]+}}, {{w[0-9]+}}, #16 return (short)x >> 16; } @@ -396,7 +343,8 @@ static long CastASR15_short_long(int x) [MethodImpl(MethodImplOptions.NoInlining)] static long CastASR16_short_long(int x) { - //ARM64-FULL-LINE: mov {{w[0-9]+}}, wzr + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: asr {{w[0-9]+}}, {{w[0-9]+}}, #16 //ARM64-FULL-LINE: sxtw {{x[0-9]+}}, {{w[0-9]+}} return (short)x >> 16; }