From bfc5ebc14a1e249fce8dab095361e322ef349180 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Thu, 4 Nov 2021 11:51:29 +0300 Subject: [PATCH] [arm64] JIT: Recognize sbfiz/ubfiz idioms (#61045) --- src/coreclr/jit/codegen.h | 1 + src/coreclr/jit/codegenarm64.cpp | 26 + src/coreclr/jit/codegenarmarch.cpp | 12 +- src/coreclr/jit/gtlist.h | 3 + src/coreclr/jit/lower.cpp | 29 + src/coreclr/jit/lsraarm64.cpp | 6 + .../opt/InstructionCombining/UbfizSbfiz.cs | 722 ++++++++++++++++++ .../InstructionCombining/UbfizSbfiz.csproj | 12 + 8 files changed, 807 insertions(+), 4 deletions(-) create mode 100644 src/tests/JIT/opt/InstructionCombining/UbfizSbfiz.cs create mode 100644 src/tests/JIT/opt/InstructionCombining/UbfizSbfiz.csproj diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h index c6b789f86f3cb..e403b7f7bf176 100644 --- a/src/coreclr/jit/codegen.h +++ b/src/coreclr/jit/codegen.h @@ -1248,6 +1248,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX void genCodeForJumpTrue(GenTreeOp* jtrue); #ifdef TARGET_ARM64 void genCodeForJumpCompare(GenTreeOp* tree); + void genCodeForBfiz(GenTreeOp* tree); #endif // TARGET_ARM64 #if defined(FEATURE_EH_FUNCLETS) diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index d68da1a1e2a9b..ac1c7cc091a24 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -9564,4 +9564,30 @@ void CodeGen::instGen_MemoryBarrier(BarrierKind barrierKind) } } +//------------------------------------------------------------------------ +// genCodeForBfiz: Generates the code sequence for a GenTree node that +// represents a bitfield insert in zero with sign/zero extension. +// +// Arguments: +// tree - the bitfield insert in zero node. +// +void CodeGen::genCodeForBfiz(GenTreeOp* tree) +{ + assert(tree->OperIs(GT_BFIZ)); + + emitAttr size = emitActualTypeSize(tree); + unsigned shiftBy = (unsigned)tree->gtGetOp2()->AsIntCon()->IconValue(); + unsigned shiftByImm = shiftBy & (emitter::getBitWidth(size) - 1); + GenTreeCast* cast = tree->gtGetOp1()->AsCast(); + GenTree* castOp = cast->CastOp(); + + genConsumeRegs(castOp); + unsigned srcBits = varTypeIsSmall(cast->CastToType()) ? genTypeSize(cast->CastToType()) * BITS_PER_BYTE + : genTypeSize(castOp) * BITS_PER_BYTE; + const bool isUnsigned = cast->IsUnsigned() || varTypeIsUnsigned(cast->CastToType()); + GetEmitter()->emitIns_R_R_I_I(isUnsigned ? INS_ubfiz : INS_sbfiz, size, tree->GetRegNum(), castOp->GetRegNum(), + (int)shiftByImm, (int)srcBits); + genProduceReg(tree); +} + #endif // TARGET_ARM64 diff --git a/src/coreclr/jit/codegenarmarch.cpp b/src/coreclr/jit/codegenarmarch.cpp index 469a145f12dbc..672ce34efa363 100644 --- a/src/coreclr/jit/codegenarmarch.cpp +++ b/src/coreclr/jit/codegenarmarch.cpp @@ -312,6 +312,10 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) case GT_SWAP: genCodeForSwap(treeNode->AsOp()); break; + + case GT_BFIZ: + genCodeForBfiz(treeNode->AsOp()); + break; #endif // TARGET_ARM64 case GT_JMP: @@ -1614,8 +1618,9 @@ void CodeGen::genCodeForShift(GenTree* tree) genTreeOps oper = tree->OperGet(); instruction ins = genGetInsForOper(oper, targetType); emitAttr size = emitActualTypeSize(tree); + regNumber dstReg = tree->GetRegNum(); - assert(tree->GetRegNum() != REG_NA); + assert(dstReg != REG_NA); genConsumeOperands(tree->AsOp()); @@ -1623,14 +1628,13 @@ void CodeGen::genCodeForShift(GenTree* tree) GenTree* shiftBy = tree->gtGetOp2(); if (!shiftBy->IsCnsIntOrI()) { - GetEmitter()->emitIns_R_R_R(ins, size, tree->GetRegNum(), operand->GetRegNum(), shiftBy->GetRegNum()); + GetEmitter()->emitIns_R_R_R(ins, size, dstReg, operand->GetRegNum(), shiftBy->GetRegNum()); } else { unsigned immWidth = emitter::getBitWidth(size); // For ARM64, immWidth will be set to 32 or 64 unsigned shiftByImm = (unsigned)shiftBy->AsIntCon()->gtIconVal & (immWidth - 1); - - GetEmitter()->emitIns_R_R_I(ins, size, tree->GetRegNum(), operand->GetRegNum(), shiftByImm); + GetEmitter()->emitIns_R_R_I(ins, size, dstReg, operand->GetRegNum(), shiftByImm); } genProduceReg(tree); diff --git a/src/coreclr/jit/gtlist.h b/src/coreclr/jit/gtlist.h index aa6f990e7e721..0bfdc8a8d998e 100644 --- a/src/coreclr/jit/gtlist.h +++ b/src/coreclr/jit/gtlist.h @@ -282,6 +282,9 @@ GTNODE(PHI_ARG , GenTreePhiArg ,0,(GTK_LEAF|GTK_LOCAL)) // phi GTNODE(JMPTABLE , GenTree ,0, (GTK_LEAF|GTK_NOCONTAIN)) // Generates the jump table for switches GTNODE(SWITCH_TABLE , GenTreeOp ,0, (GTK_BINOP|GTK_NOVALUE)) // Jump Table based switch construct +#ifdef TARGET_ARM64 +GTNODE(BFIZ, GenTreeBfiz ,0, GTK_BINOP) // Bitfield Insert in Zero +#endif //----------------------------------------------------------------------------- // Nodes used only within the code generator: diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 2c9ed01a1ebeb..c525c59cfa062 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -5753,6 +5753,35 @@ void Lowering::LowerShift(GenTreeOp* shift) shift->gtOp2->ClearContained(); } 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()) + { + GenTreeIntCon* cns = shift->gtGetOp2()->AsIntCon(); + GenTreeCast* cast = shift->gtGetOp1()->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; + assert(!cast->CastOp()->isContained()); + + // It has to be an upcast and CNS must be in [1..srcBits) range + if ((srcBits < dstBits) && ((UINT32)cns->IconValue() < srcBits)) + { + JITDUMP("Recognized ubfix/sbfix pattern in LSH(CAST, CNS). Changing op to GT_BFIZ"); + shift->ChangeOper(GT_BFIZ); + MakeSrcContained(shift, cast); + } + } + } +#endif } void Lowering::WidenSIMD12IfNecessary(GenTreeLclVarCommon* node) diff --git a/src/coreclr/jit/lsraarm64.cpp b/src/coreclr/jit/lsraarm64.cpp index b7acad960d45e..d59c8e913b02e 100644 --- a/src/coreclr/jit/lsraarm64.cpp +++ b/src/coreclr/jit/lsraarm64.cpp @@ -279,6 +279,12 @@ int LinearScan::BuildNode(GenTree* tree) BuildDef(tree); break; + case GT_BFIZ: + assert(tree->gtGetOp1()->OperIs(GT_CAST)); + srcCount = BuildOperandUses(tree->gtGetOp1()->gtGetOp1()); + BuildDef(tree); + break; + case GT_RETURNTRAP: // this just turns into a compare of its child with an int // + a conditional call diff --git a/src/tests/JIT/opt/InstructionCombining/UbfizSbfiz.cs b/src/tests/JIT/opt/InstructionCombining/UbfizSbfiz.cs new file mode 100644 index 0000000000000..33cba49a0ab4a --- /dev/null +++ b/src/tests/JIT/opt/InstructionCombining/UbfizSbfiz.cs @@ -0,0 +1,722 @@ +// 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; + +public class Program +{ + public const int ShiftBy = 5; + + [MethodImpl(MethodImplOptions.NoInlining)] + public static T ToVar(T t) => t; + + public static void AssertTrue(bool cond, [CallerLineNumber] int line = 0) + { + if (!cond) + throw new InvalidOperationException($"Test failed at line {line}."); + } + + // Tests for https://github.com/dotnet/runtime/pull/61045 optimization + public static int Main() + { + unchecked + { + long[] testData = + { + -1, -2, -3, -8, -128, -129, -254, -255, -256, + 0, 1, 2, 3, 8, 128, 129, 254, 255, 256, + short.MinValue + 1, short.MinValue, short.MinValue + 1, + short.MaxValue + 1, short.MaxValue, short.MaxValue + 1, + int.MinValue + 1, int.MinValue, int.MinValue + 1, + int.MaxValue + 1, int.MaxValue, int.MaxValue + 1, + long.MinValue + 1, long.MinValue, long.MinValue + 1, + long.MaxValue + 1, long.MaxValue, long.MaxValue + 1, + ushort.MaxValue, uint.MaxValue, (long)ulong.MaxValue + }; + + foreach (long t in testData) + { + AssertTrue(Tests_byte.Test_byte_to_byte((byte)t)); + AssertTrue(Tests_byte.Test_byte_to_sbyte((byte)t)); + AssertTrue(Tests_byte.Test_byte_to_ushort((byte)t)); + AssertTrue(Tests_byte.Test_byte_to_short((byte)t)); + AssertTrue(Tests_byte.Test_byte_to_uint((byte)t)); + AssertTrue(Tests_byte.Test_byte_to_int((byte)t)); + AssertTrue(Tests_byte.Test_byte_to_ulong((byte)t)); + AssertTrue(Tests_byte.Test_byte_to_long((byte)t)); + + AssertTrue(Tests_sbyte.Test_sbyte_to_byte((sbyte)t)); + AssertTrue(Tests_sbyte.Test_sbyte_to_sbyte((sbyte)t)); + AssertTrue(Tests_sbyte.Test_sbyte_to_ushort((sbyte)t)); + AssertTrue(Tests_sbyte.Test_sbyte_to_short((sbyte)t)); + AssertTrue(Tests_sbyte.Test_sbyte_to_uint((sbyte)t)); + AssertTrue(Tests_sbyte.Test_sbyte_to_int((sbyte)t)); + AssertTrue(Tests_sbyte.Test_sbyte_to_ulong((sbyte)t)); + AssertTrue(Tests_sbyte.Test_sbyte_to_long((sbyte)t)); + + AssertTrue(Tests_ushort.Test_ushort_to_byte((ushort)t)); + AssertTrue(Tests_ushort.Test_ushort_to_sbyte((ushort)t)); + AssertTrue(Tests_ushort.Test_ushort_to_ushort((ushort)t)); + AssertTrue(Tests_ushort.Test_ushort_to_short((ushort)t)); + AssertTrue(Tests_ushort.Test_ushort_to_uint((ushort)t)); + AssertTrue(Tests_ushort.Test_ushort_to_int((ushort)t)); + AssertTrue(Tests_ushort.Test_ushort_to_ulong((ushort)t)); + AssertTrue(Tests_ushort.Test_ushort_to_long((ushort)t)); + + AssertTrue(Tests_short.Test_short_to_byte((short)t)); + AssertTrue(Tests_short.Test_short_to_sbyte((short)t)); + AssertTrue(Tests_short.Test_short_to_ushort((short)t)); + AssertTrue(Tests_short.Test_short_to_short((short)t)); + AssertTrue(Tests_short.Test_short_to_uint((short)t)); + AssertTrue(Tests_short.Test_short_to_int((short)t)); + AssertTrue(Tests_short.Test_short_to_ulong((short)t)); + AssertTrue(Tests_short.Test_short_to_long((short)t)); + + AssertTrue(Tests_uint.Test_uint_to_byte((uint)t)); + AssertTrue(Tests_uint.Test_uint_to_sbyte((uint)t)); + AssertTrue(Tests_uint.Test_uint_to_ushort((uint)t)); + AssertTrue(Tests_uint.Test_uint_to_short((uint)t)); + AssertTrue(Tests_uint.Test_uint_to_uint((uint)t)); + AssertTrue(Tests_uint.Test_uint_to_int((uint)t)); + AssertTrue(Tests_uint.Test_uint_to_ulong((uint)t)); + AssertTrue(Tests_uint.Test_uint_to_long((uint)t)); + + AssertTrue(Tests_int.Test_int_to_byte((int)t)); + AssertTrue(Tests_int.Test_int_to_sbyte((int)t)); + AssertTrue(Tests_int.Test_int_to_ushort((int)t)); + AssertTrue(Tests_int.Test_int_to_short((int)t)); + AssertTrue(Tests_int.Test_int_to_uint((int)t)); + AssertTrue(Tests_int.Test_int_to_int((int)t)); + AssertTrue(Tests_int.Test_int_to_ulong((int)t)); + AssertTrue(Tests_int.Test_int_to_long((int)t)); + + AssertTrue(Tests_ulong.Test_ulong_to_byte((ulong)t)); + AssertTrue(Tests_ulong.Test_ulong_to_sbyte((ulong)t)); + AssertTrue(Tests_ulong.Test_ulong_to_ushort((ulong)t)); + AssertTrue(Tests_ulong.Test_ulong_to_short((ulong)t)); + AssertTrue(Tests_ulong.Test_ulong_to_uint((ulong)t)); + AssertTrue(Tests_ulong.Test_ulong_to_int((ulong)t)); + AssertTrue(Tests_ulong.Test_ulong_to_ulong((ulong)t)); + AssertTrue(Tests_ulong.Test_ulong_to_long((ulong)t)); + + AssertTrue(Tests_long.Test_long_to_byte(t)); + AssertTrue(Tests_long.Test_long_to_sbyte(t)); + AssertTrue(Tests_long.Test_long_to_ushort(t)); + AssertTrue(Tests_long.Test_long_to_short(t)); + AssertTrue(Tests_long.Test_long_to_uint(t)); + AssertTrue(Tests_long.Test_long_to_int(t)); + AssertTrue(Tests_long.Test_long_to_ulong(t)); + AssertTrue(Tests_long.Test_long_to_long(t)); + } + } + return 100; + } +} + +public class Tests_byte +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_byte_to_byte(byte x) + { + unchecked + { + return (byte)(x << Program.ShiftBy) == + (byte)(Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_byte_to_sbyte(byte x) + { + unchecked + { + return (sbyte)((sbyte)x << Program.ShiftBy) == + (sbyte)((sbyte)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_byte_to_ushort(byte x) + { + unchecked + { + return (ushort)(x << Program.ShiftBy) == + (ushort)(Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_byte_to_short(byte x) + { + unchecked + { + return (short)(x << Program.ShiftBy) == + (short)(Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_byte_to_uint(byte x) + { + return (uint)x << Program.ShiftBy == + (uint)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_byte_to_int(byte x) + { + return x << Program.ShiftBy == + Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_byte_to_ulong(byte x) + { + return (ulong)x << Program.ShiftBy == + (ulong)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_byte_to_long(byte x) + { + return (long)x << Program.ShiftBy == + (long)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } +} + +public class Tests_sbyte +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_sbyte_to_byte(sbyte x) + { + unchecked + { + return (byte)((byte)x << Program.ShiftBy) == + (byte)((byte)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_sbyte_to_sbyte(sbyte x) + { + unchecked + { + return (sbyte)(x << Program.ShiftBy) == + (sbyte)(Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_sbyte_to_ushort(sbyte x) + { + unchecked + { + return (ushort)((ushort)x << Program.ShiftBy) == + (ushort)((ushort)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_sbyte_to_short(sbyte x) + { + unchecked + { + return (short)(x << Program.ShiftBy) == + (short)(Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_sbyte_to_uint(sbyte x) + { + unchecked + { + return (uint)x << Program.ShiftBy == + (uint)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_sbyte_to_int(sbyte x) + { + return x << Program.ShiftBy == + Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_sbyte_to_ulong(sbyte x) + { + unchecked + { + return (ulong)x << Program.ShiftBy == + (ulong)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_sbyte_to_long(sbyte x) + { + return (long)x << Program.ShiftBy == + (long)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } +} + +public class Tests_ushort +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_ushort_to_byte(ushort x) + { + unchecked + { + return (byte)((byte)x << Program.ShiftBy) == + (byte)((byte)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_ushort_to_sbyte(ushort x) + { + unchecked + { + return (sbyte)((sbyte)x << Program.ShiftBy) == + (sbyte)((sbyte)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_ushort_to_ushort(ushort x) + { + unchecked + { + return (ushort)(x << Program.ShiftBy) == + (ushort)(Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_ushort_to_short(ushort x) + { + unchecked + { + return (short)((short)x << Program.ShiftBy) == + (short)((short)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_ushort_to_uint(ushort x) + { + return (uint)x << Program.ShiftBy == + (uint)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_ushort_to_int(ushort x) + { + return x << Program.ShiftBy == + Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_ushort_to_ulong(ushort x) + { + return (ulong)x << Program.ShiftBy == + (ulong)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_ushort_to_long(ushort x) + { + return (long)x << Program.ShiftBy == + (long)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } +} + +public class Tests_short +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_short_to_byte(short x) + { + unchecked + { + return (byte)((byte)x << Program.ShiftBy) == + (byte)((byte)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_short_to_sbyte(short x) + { + unchecked + { + return (sbyte)((sbyte)x << Program.ShiftBy) == + (sbyte)((sbyte)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_short_to_ushort(short x) + { + unchecked + { + return (ushort)((ushort)x << Program.ShiftBy) == + (ushort)((ushort)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_short_to_short(short x) + { + unchecked + { + return (short)(x << Program.ShiftBy) == + (short)(Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_short_to_uint(short x) + { + unchecked + { + return (uint)x << Program.ShiftBy == + (uint)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_short_to_int(short x) + { + return x << Program.ShiftBy == + Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_short_to_ulong(short x) + { + unchecked + { + return (ulong)x << Program.ShiftBy == + (ulong)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_short_to_long(short x) + { + return (long)x << Program.ShiftBy == + (long)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } +} + +public class Tests_uint +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_uint_to_byte(uint x) + { + unchecked + { + return (byte)((byte)x << Program.ShiftBy) == + (byte)((byte)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_uint_to_sbyte(uint x) + { + unchecked + { + return (sbyte)((sbyte)x << Program.ShiftBy) == + (sbyte)((sbyte)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_uint_to_ushort(uint x) + { + unchecked + { + return (ushort)((ushort)x << Program.ShiftBy) == + (ushort)((ushort)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_uint_to_short(uint x) + { + unchecked + { + return (short)((short)x << Program.ShiftBy) == + (short)((short)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_uint_to_uint(uint x) + { + return x << Program.ShiftBy == + Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_uint_to_int(uint x) + { + unchecked + { + return (int)x << Program.ShiftBy == + (int)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_uint_to_ulong(uint x) + { + return (ulong)x << Program.ShiftBy == + (ulong)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_uint_to_long(uint x) + { + return (long)x << Program.ShiftBy == + (long)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } +} + +public class Tests_int +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_int_to_byte(int x) + { + unchecked + { + return (byte)((byte)x << Program.ShiftBy) == + (byte)((byte)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_int_to_sbyte(int x) + { + unchecked + { + return (sbyte)((sbyte)x << Program.ShiftBy) == + (sbyte)((sbyte)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_int_to_ushort(int x) + { + unchecked + { + return (ushort)((ushort)x << Program.ShiftBy) == + (ushort)((ushort)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_int_to_short(int x) + { + unchecked + { + return (short)((short)x << Program.ShiftBy) == + (short)((short)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_int_to_uint(int x) + { + unchecked + { + return (uint)x << Program.ShiftBy == + (uint)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_int_to_int(int x) + { + return x << Program.ShiftBy == + Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_int_to_ulong(int x) + { + unchecked + { + return (ulong)x << Program.ShiftBy == + (ulong)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_int_to_long(int x) + { + return (long)x << Program.ShiftBy == + (long)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } +} + +public class Tests_ulong +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_ulong_to_byte(ulong x) + { + unchecked + { + return (byte)((byte)x << Program.ShiftBy) == + (byte)((byte)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_ulong_to_sbyte(ulong x) + { + unchecked + { + return (sbyte)((sbyte)x << Program.ShiftBy) == + (sbyte)((sbyte)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_ulong_to_ushort(ulong x) + { + unchecked + { + return (ushort)((ushort)x << Program.ShiftBy) == + (ushort)((ushort)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_ulong_to_short(ulong x) + { + unchecked + { + return (short)((short)x << Program.ShiftBy) == + (short)((short)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_ulong_to_uint(ulong x) + { + unchecked + { + return (uint)x << Program.ShiftBy == + (uint)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_ulong_to_int(ulong x) + { + unchecked + { + return (int)x << Program.ShiftBy == + (int)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_ulong_to_ulong(ulong x) + { + return x << Program.ShiftBy == + Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_ulong_to_long(ulong x) + { + unchecked + { + return (long)x << Program.ShiftBy == + (long)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + } +} + +public class Tests_long +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_long_to_byte(long x) + { + unchecked + { + return (byte)((byte)x << Program.ShiftBy) == + (byte)((byte)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_long_to_sbyte(long x) + { + unchecked + { + return (sbyte)((sbyte)x << Program.ShiftBy) == + (sbyte)((sbyte)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_long_to_ushort(long x) + { + unchecked + { + return (ushort)((ushort)x << Program.ShiftBy) == + (ushort)((ushort)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_long_to_short(long x) + { + unchecked + { + return (short)((short)x << Program.ShiftBy) == + (short)((short)Program.ToVar(x) << Program.ToVar(Program.ShiftBy)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_long_to_uint(long x) + { + unchecked + { + return (uint)x << Program.ShiftBy == + (uint)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_long_to_int(long x) + { + unchecked + { + return (int)x << Program.ShiftBy == + (int)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_long_to_ulong(long x) + { + unchecked + { + return (ulong)x << Program.ShiftBy == + (ulong)Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool Test_long_to_long(long x) + { + return x << Program.ShiftBy == + Program.ToVar(x) << Program.ToVar(Program.ShiftBy); + } +} \ No newline at end of file diff --git a/src/tests/JIT/opt/InstructionCombining/UbfizSbfiz.csproj b/src/tests/JIT/opt/InstructionCombining/UbfizSbfiz.csproj new file mode 100644 index 0000000000000..ae422e19fd397 --- /dev/null +++ b/src/tests/JIT/opt/InstructionCombining/UbfizSbfiz.csproj @@ -0,0 +1,12 @@ + + + Exe + + + None + True + + + + +