From 3e6017a6333b8a191d8b16ef15968b3dade22d91 Mon Sep 17 00:00:00 2001
From: Julie Lee <63486087+JulieLeeMSFT@users.noreply.github.com>
Date: Tue, 22 Mar 2022 10:32:48 -0700
Subject: [PATCH 01/15] Emit shlx, sarx, shrx: resolve merge conflict in
emitxarch.cpp.
---
src/coreclr/jit/codegenxarch.cpp | 31 +++++++++++++++++++++++++++++++
src/coreclr/jit/emitxarch.cpp | 26 +++++++++++++++++++++++++-
src/coreclr/jit/instrsxarch.h | 3 +++
src/coreclr/jit/lsraxarch.cpp | 10 ++++++++++
4 files changed, 69 insertions(+), 1 deletion(-)
diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp
index f495acf2c07e67..40f456fdc89d44 100644
--- a/src/coreclr/jit/codegenxarch.cpp
+++ b/src/coreclr/jit/codegenxarch.cpp
@@ -4384,6 +4384,7 @@ void CodeGen::genCodeForShift(GenTree* tree)
int shiftByValue = (int)shiftBy->AsIntConCommon()->IconValue();
#if defined(TARGET_64BIT)
+
// Try to emit rorx if BMI2 is available instead of mov+rol
// it makes sense only for 64bit integers
if ((genActualType(targetType) == TYP_LONG) && (tree->GetRegNum() != operandReg) &&
@@ -4403,6 +4404,36 @@ void CodeGen::genCodeForShift(GenTree* tree)
inst_RV_SH(ins, size, tree->GetRegNum(), shiftByValue);
}
}
+#if defined(TARGET_64BIT)
+ else if (compiler->compOpportunisticallyDependsOn(InstructionSet_BMI2) && tree->OperIs(GT_LSH, GT_RSH, GT_RSZ))
+ {
+ // Try to emit shlx, sarx, shrx if BMI2 is available instead of mov+shl, mov+sar, mov+shr.
+ switch (tree->OperGet())
+ {
+ case GT_LSH:
+ ins = INS_shlx;
+ break;
+
+ case GT_RSH:
+ ins = INS_sarx;
+ break;
+
+ case GT_RSZ:
+ ins = INS_shrx;
+ break;
+
+ default:
+ unreached();
+ }
+
+ regNumber shiftByReg = shiftBy->GetRegNum();
+ emitAttr size = emitTypeSize(tree);
+
+ GetEmitter()->emitIns_R_R_R(ins, size, tree->GetRegNum(), operandReg, shiftByReg);
+ genProduceReg(tree);
+ return;
+ }
+#endif
else
{
// We must have the number of bits to shift stored in ECX, since we constrained this node to
diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp
index ebe6030a8d7093..e177c420dc164b 100644
--- a/src/coreclr/jit/emitxarch.cpp
+++ b/src/coreclr/jit/emitxarch.cpp
@@ -749,6 +749,9 @@ bool emitter::TakesRexWPrefix(instruction ins, emitAttr attr)
case INS_pdep:
case INS_pext:
case INS_rorx:
+ case INS_shlx:
+ case INS_sarx:
+ case INS_shrx:
return true;
default:
return false;
@@ -987,17 +990,25 @@ unsigned emitter::emitOutputRexOrVexPrefixIfNeeded(instruction ins, BYTE* dst, c
case INS_rorx:
case INS_pdep:
case INS_mulx:
+ case INS_shrx:
{
vexPrefix |= 0x03;
break;
}
case INS_pext:
+ case INS_sarx:
{
vexPrefix |= 0x02;
break;
}
+ case INS_shlx:
+ {
+ vexPrefix |= 0x01;
+ break;
+ }
+
default:
{
vexPrefix |= 0x00;
@@ -1484,6 +1495,9 @@ bool emitter::emitInsCanOnlyWriteSSE2OrAVXReg(instrDesc* id)
case INS_pextrw:
case INS_pextrw_sse41:
case INS_rorx:
+ case INS_shlx:
+ case INS_sarx:
+ case INS_shrx:
{
// These SSE instructions write to a general purpose integer register.
return false;
@@ -9519,7 +9533,7 @@ void emitter::emitDispIns(
assert(IsThreeOperandAVXInstruction(ins));
regNumber reg2 = id->idReg2();
regNumber reg3 = id->idReg3();
- if (ins == INS_bextr || ins == INS_bzhi)
+ if (ins == INS_bextr || ins == INS_bzhi || ins == INS_shrx || ins == INS_shlx || ins == INS_sarx)
{
// BMI bextr and bzhi encodes the reg2 in VEX.vvvv and reg3 in modRM,
// which is different from most of other instructions
@@ -10314,6 +10328,7 @@ BYTE* emitter::emitOutputAM(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc)
// For this format, moves do not support a third operand, so we only need to handle the binary ops.
if (TakesVexPrefix(ins))
{
+
if (IsDstDstSrcAVXInstruction(ins))
{
regNumber src1 = REG_NA;
@@ -16323,6 +16338,15 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
break;
}
+ case INS_shlx:
+ case INS_sarx:
+ case INS_shrx:
+ {
+ result.insLatency = PERFSCORE_LATENCY_1C;
+ result.insThroughput = PERFSCORE_THROUGHPUT_1C;
+ break;
+ }
+
default:
// unhandled instruction insFmt combination
perfScoreUnhandledInstruction(id, &result);
diff --git a/src/coreclr/jit/instrsxarch.h b/src/coreclr/jit/instrsxarch.h
index 5a626ce26e96ec..eb3fcc9ad626b4 100644
--- a/src/coreclr/jit/instrsxarch.h
+++ b/src/coreclr/jit/instrsxarch.h
@@ -605,6 +605,9 @@ INST3(pdep, "pdep", IUM_WR, BAD_CODE, BAD_CODE,
INST3(pext, "pext", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF5), INS_Flags_IsDstDstSrcAVXInstruction) // Parallel Bits Extract
INST3(bzhi, "bzhi", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF5), Resets_OF | Writes_SF | Writes_ZF | Undefined_AF | Undefined_PF | Writes_CF | INS_Flags_IsDstDstSrcAVXInstruction) // Zero High Bits Starting with Specified Bit Position
INST3(mulx, "mulx", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF6), INS_Flags_IsDstDstSrcAVXInstruction) // Unsigned Multiply Without Affecting Flags
+INST3(shlx, "shlx", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF7), INS_Flags_IsDstSrcSrcAVXInstruction) // Shift Logical Left Without Affecting Flags
+INST3(sarx, "sarx", IUM_WR, BAD_CODE, BAD_CODE, PACK4(0xF3, 0x0F, 0x38, 0xF7), INS_Flags_IsDstSrcSrcAVXInstruction) // Shift Arithmetic Right Without Affecting Flags
+INST3(shrx, "shrx", IUM_WR, BAD_CODE, BAD_CODE, PACK4(0xF2, 0x0F, 0x38, 0xF7), INS_Flags_IsDstSrcSrcAVXInstruction) // Shift Logical Right Without Affecting Flags
INST3(LAST_BMI_INSTRUCTION, "LAST_BMI_INSTRUCTION", IUM_WR, BAD_CODE, BAD_CODE, BAD_CODE, INS_FLAGS_None)
diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp
index 4f7cde2cc62f65..62719e5d32d6ad 100644
--- a/src/coreclr/jit/lsraxarch.cpp
+++ b/src/coreclr/jit/lsraxarch.cpp
@@ -925,6 +925,16 @@ int LinearScan::BuildShiftRotate(GenTree* tree)
{
assert(shiftBy->OperIsConst());
}
+#if defined(TARGET_64BIT)
+ else if (compiler->compOpportunisticallyDependsOn(InstructionSet_BMI2) && tree->OperIs(GT_LSH, GT_RSH, GT_RSZ) &&
+ !tree->isContained())
+ {
+ srcCount += BuildOperandUses(source, srcCandidates);
+ srcCount += BuildOperandUses(shiftBy, srcCandidates);
+ BuildDef(tree, dstCandidates);
+ return srcCount;
+ }
+#endif
else
{
srcCandidates = allRegs(TYP_INT) & ~RBM_RCX;
From 4a7b4043e558c70d8283b91a19db6560be62b900 Mon Sep 17 00:00:00 2001
From: Julie Lee <63486087+JulieLeeMSFT@users.noreply.github.com>
Date: Fri, 25 Mar 2022 12:13:36 -0700
Subject: [PATCH 02/15] Shrx: Swap operand and ShiftBy registers to swap rcx
and rdx in correct order.
---
src/coreclr/jit/codegenxarch.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp
index 40f456fdc89d44..e41c3c8fb558bb 100644
--- a/src/coreclr/jit/codegenxarch.cpp
+++ b/src/coreclr/jit/codegenxarch.cpp
@@ -4429,7 +4429,7 @@ void CodeGen::genCodeForShift(GenTree* tree)
regNumber shiftByReg = shiftBy->GetRegNum();
emitAttr size = emitTypeSize(tree);
- GetEmitter()->emitIns_R_R_R(ins, size, tree->GetRegNum(), operandReg, shiftByReg);
+ GetEmitter()->emitIns_R_R_R(ins, size, tree->GetRegNum(), shiftByReg, operandReg);
genProduceReg(tree);
return;
}
From 23395b38cf169d5bc5d5a3763e95a0cb8e18e7b1 Mon Sep 17 00:00:00 2001
From: Julie Lee <63486087+JulieLeeMSFT@users.noreply.github.com>
Date: Fri, 25 Mar 2022 17:27:24 -0700
Subject: [PATCH 03/15] Change only TYP_LONG to Shlx, Sarx and Shrx.
---
src/coreclr/jit/codegenxarch.cpp | 7 ++++---
src/coreclr/jit/emitxarch.cpp | 21 +++++++++++++++++++++
src/coreclr/jit/emitxarch.h | 3 +++
src/coreclr/jit/instrsxarch.h | 6 +++---
src/coreclr/jit/lowerxarch.cpp | 4 ++--
src/coreclr/jit/lsraxarch.cpp | 2 +-
6 files changed, 34 insertions(+), 9 deletions(-)
diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp
index e41c3c8fb558bb..a6966dbc25d29c 100644
--- a/src/coreclr/jit/codegenxarch.cpp
+++ b/src/coreclr/jit/codegenxarch.cpp
@@ -4341,7 +4341,7 @@ instruction CodeGen::genGetInsForOper(genTreeOps oper, var_types type)
// tree - the bit shift node (that specifies the type of bit shift to perform).
//
// Assumptions:
-// a) All GenTrees are register allocated.
+// a) All GenTrees are register allocated or source operand in tree->AsOp()->gtOp1 is contained memory address.
// b) The shift-by-amount in tree->AsOp()->gtOp2 is either a contained constant or
// it's a register-allocated expression. If it is in a register that is
// not RCX, it will be moved to RCX (so RCX better not be in use!).
@@ -4405,7 +4405,8 @@ void CodeGen::genCodeForShift(GenTree* tree)
}
}
#if defined(TARGET_64BIT)
- else if (compiler->compOpportunisticallyDependsOn(InstructionSet_BMI2) && tree->OperIs(GT_LSH, GT_RSH, GT_RSZ))
+ else if (compiler->compOpportunisticallyDependsOn(InstructionSet_BMI2) && tree->OperIs(GT_LSH, GT_RSH, GT_RSZ) &&
+ (genActualType(targetType) == TYP_LONG))
{
// Try to emit shlx, sarx, shrx if BMI2 is available instead of mov+shl, mov+sar, mov+shr.
switch (tree->OperGet())
@@ -4428,9 +4429,9 @@ void CodeGen::genCodeForShift(GenTree* tree)
regNumber shiftByReg = shiftBy->GetRegNum();
emitAttr size = emitTypeSize(tree);
-
GetEmitter()->emitIns_R_R_R(ins, size, tree->GetRegNum(), shiftByReg, operandReg);
genProduceReg(tree);
+
return;
}
#endif
diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp
index e177c420dc164b..c28847419d1120 100644
--- a/src/coreclr/jit/emitxarch.cpp
+++ b/src/coreclr/jit/emitxarch.cpp
@@ -5086,6 +5086,27 @@ void emitter::emitIns_R_R_A(instruction ins, emitAttr attr, regNumber reg1, regN
emitCurIGsize += sz;
}
+void emitter::emitIns_R_A_R(instruction ins, emitAttr attr, regNumber reg1, GenTreeIndir* indir, regNumber reg2)
+{
+ assert(IsSSEOrAVXInstruction(ins));
+ assert(IsThreeOperandAVXInstruction(ins));
+
+ ssize_t offs = indir->Offset();
+ instrDesc* id = emitNewInstrAmd(attr, offs);
+
+ id->idIns(ins);
+ id->idReg1(reg1);
+ id->idReg2(reg2);
+
+ emitHandleMemOp(indir, id, IF_RWR_RRD_ARD, ins);
+
+ UNATIVE_OFFSET sz = emitInsSizeAM(id, insCodeRM(ins));
+ id->idCodeSize(sz);
+
+ dispIns(id);
+ emitCurIGsize += sz;
+}
+
void emitter::emitIns_R_R_AR(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber base, int offs)
{
assert(IsSSEOrAVXInstruction(ins));
diff --git a/src/coreclr/jit/emitxarch.h b/src/coreclr/jit/emitxarch.h
index 3f1efdaac5e52b..552bf469f83154 100644
--- a/src/coreclr/jit/emitxarch.h
+++ b/src/coreclr/jit/emitxarch.h
@@ -347,6 +347,8 @@ void emitIns_R_S_I(instruction ins, emitAttr attr, regNumber reg1, int varx, int
void emitIns_R_R_A(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, GenTreeIndir* indir);
+void emitIns_R_A_R(instruction ins, emitAttr attr, regNumber reg1, GenTreeIndir* indir, regNumber reg2);
+
void emitIns_R_R_AR(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber base, int offs);
void emitIns_R_AR_R(instruction ins,
@@ -461,6 +463,7 @@ void emitIns_AX_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg,
void emitIns_SIMD_R_R_I(instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, int ival);
void emitIns_SIMD_R_R_A(instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, GenTreeIndir* indir);
+void emitIns_SIMD_R_A_R(instruction ins, emitAttr attr, regNumber targetReg, GenTreeIndir* indir, regNumber op2Reg);
void emitIns_SIMD_R_R_AR(
instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber base, int offset);
void emitIns_SIMD_R_R_C(
diff --git a/src/coreclr/jit/instrsxarch.h b/src/coreclr/jit/instrsxarch.h
index eb3fcc9ad626b4..06dd9ef0d2a505 100644
--- a/src/coreclr/jit/instrsxarch.h
+++ b/src/coreclr/jit/instrsxarch.h
@@ -605,9 +605,9 @@ INST3(pdep, "pdep", IUM_WR, BAD_CODE, BAD_CODE,
INST3(pext, "pext", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF5), INS_Flags_IsDstDstSrcAVXInstruction) // Parallel Bits Extract
INST3(bzhi, "bzhi", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF5), Resets_OF | Writes_SF | Writes_ZF | Undefined_AF | Undefined_PF | Writes_CF | INS_Flags_IsDstDstSrcAVXInstruction) // Zero High Bits Starting with Specified Bit Position
INST3(mulx, "mulx", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF6), INS_Flags_IsDstDstSrcAVXInstruction) // Unsigned Multiply Without Affecting Flags
-INST3(shlx, "shlx", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF7), INS_Flags_IsDstSrcSrcAVXInstruction) // Shift Logical Left Without Affecting Flags
-INST3(sarx, "sarx", IUM_WR, BAD_CODE, BAD_CODE, PACK4(0xF3, 0x0F, 0x38, 0xF7), INS_Flags_IsDstSrcSrcAVXInstruction) // Shift Arithmetic Right Without Affecting Flags
-INST3(shrx, "shrx", IUM_WR, BAD_CODE, BAD_CODE, PACK4(0xF2, 0x0F, 0x38, 0xF7), INS_Flags_IsDstSrcSrcAVXInstruction) // Shift Logical Right Without Affecting Flags
+INST3(shlx, "shlx", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF7), INS_Flags_IsDstDstSrcAVXInstruction) // Shift Logical Left Without Affecting Flags
+INST3(sarx, "sarx", IUM_WR, BAD_CODE, BAD_CODE, PACK4(0xF3, 0x0F, 0x38, 0xF7), INS_Flags_IsDstDstSrcAVXInstruction) // Shift Arithmetic Right Without Affecting Flags
+INST3(shrx, "shrx", IUM_WR, BAD_CODE, BAD_CODE, PACK4(0xF2, 0x0F, 0x38, 0xF7), INS_Flags_IsDstDstSrcAVXInstruction) // Shift Logical Right Without Affecting Flags
INST3(LAST_BMI_INSTRUCTION, "LAST_BMI_INSTRUCTION", IUM_WR, BAD_CODE, BAD_CODE, BAD_CODE, INS_FLAGS_None)
diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp
index ee94c6d9042ddf..7d919e463371ed 100644
--- a/src/coreclr/jit/lowerxarch.cpp
+++ b/src/coreclr/jit/lowerxarch.cpp
@@ -4843,14 +4843,14 @@ void Lowering::ContainCheckDivOrMod(GenTreeOp* node)
void Lowering::ContainCheckShiftRotate(GenTreeOp* node)
{
assert(node->OperIsShiftOrRotate());
-#ifdef TARGET_X86
+#if defined(TARGET_X86)
GenTree* source = node->gtOp1;
if (node->OperIsShiftLong())
{
assert(source->OperGet() == GT_LONG);
MakeSrcContained(node, source);
}
-#endif // !TARGET_X86
+#endif
GenTree* shiftBy = node->gtOp2;
if (IsContainableImmed(node, shiftBy) && (shiftBy->AsIntConCommon()->IconValue() <= 255) &&
diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp
index 62719e5d32d6ad..cf2905dc8693dd 100644
--- a/src/coreclr/jit/lsraxarch.cpp
+++ b/src/coreclr/jit/lsraxarch.cpp
@@ -927,7 +927,7 @@ int LinearScan::BuildShiftRotate(GenTree* tree)
}
#if defined(TARGET_64BIT)
else if (compiler->compOpportunisticallyDependsOn(InstructionSet_BMI2) && tree->OperIs(GT_LSH, GT_RSH, GT_RSZ) &&
- !tree->isContained())
+ !tree->isContained() && (genActualType(tree->TypeGet()) == TYP_LONG))
{
srcCount += BuildOperandUses(source, srcCandidates);
srcCount += BuildOperandUses(shiftBy, srcCandidates);
From 9c07d03294b363f436fd20953429e1bb013d9112 Mon Sep 17 00:00:00 2001
From: Julie Lee <63486087+JulieLeeMSFT@users.noreply.github.com>
Date: Fri, 25 Mar 2022 17:35:23 -0700
Subject: [PATCH 04/15] Shlx, Sarx, Shrx test cases
---
src/tests/JIT/SIMD/ShiftOperations.cs | 485 ++++++++++++++++++++++
src/tests/JIT/SIMD/ShiftOperations.csproj | 12 +
2 files changed, 497 insertions(+)
create mode 100644 src/tests/JIT/SIMD/ShiftOperations.cs
create mode 100644 src/tests/JIT/SIMD/ShiftOperations.csproj
diff --git a/src/tests/JIT/SIMD/ShiftOperations.cs b/src/tests/JIT/SIMD/ShiftOperations.cs
new file mode 100644
index 00000000000000..9893ee53ed02ad
--- /dev/null
+++ b/src/tests/JIT/SIMD/ShiftOperations.cs
@@ -0,0 +1,485 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Numerics;
+
+public class Test
+{
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static uint Shl(uint x, int y) => x<< y;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static int Sar(int x, int y) => x >> y;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static uint Shr(uint x, int y) => x >> y;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static uint Ror(uint x) => BitOperations.RotateRight(x, 2);
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static ulong Shlx(ulong x, int y) => x << y;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static long Sarx(long x, int y) => x >> y;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static ulong Shrx(ulong x, int y) => x >> y;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static unsafe ulong ShrxRef(ulong *x, int y) => *x >> y;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static ulong Rorx(ulong x) => BitOperations.RotateRight(x, 2);
+
+public static unsafe int Main()
+{
+ try
+ {
+ uint valUInt = 0xFFFFFFFE;
+ int valInt = 8;
+ ulong valULong = 8;
+ long valLong = 8;
+ int shiftBy = 1;
+ uint resUInt = 0;
+ int resInt = 0;
+ ulong resULong = 0;
+ long resLong = 0;
+ uint expectedUInt = 0;
+ int expectedInt = 0;
+ ulong expectedULong = 0;
+ long expectedLong = 0;
+ int MOD32 = 32;
+ int MOD64 = 64;
+
+ //
+ // shl tests
+ //
+ valUInt = 0;
+ shiftBy = 1;
+ resUInt = Shl(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shl({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ valUInt = 8;
+ shiftBy = 1;
+ resUInt = Shl(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shl({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ valUInt = 1;
+ shiftBy = 31;
+ resUInt = Shl(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shl({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ valUInt = 1;
+ shiftBy = 33;
+ resUInt = Shl(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shl({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ valUInt = 0xFFFFFFFF;
+ shiftBy = 1;
+ resUInt = Shl(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt * Math.Pow(2, shiftBy));
+ Console.Write("UnitTest Shl({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ //
+ // sar tests
+ //
+ valInt = 0;
+ shiftBy = 1;
+ resInt = Sar(valInt, shiftBy);
+ expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Sar({0},{1}): {2}", valInt, shiftBy, resInt);
+ if (resInt != expectedInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedInt);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedInt);
+
+ valInt = -8;
+ shiftBy = 1;
+ resInt = Sar(valInt, shiftBy);
+ expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Sar({0},{1}): {2}", valInt, shiftBy, resInt);
+ if (resInt != expectedInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedInt);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedInt);
+
+ valInt = 1;
+ shiftBy = 33;
+ resInt = Sar(valInt, shiftBy);
+ expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Sar({0},{1}): {2}", valInt, shiftBy, resInt);
+ if (resInt != expectedInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedInt);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedInt);
+
+ valInt = 0x7FFFFFFF;
+ shiftBy = 33;
+ resInt = Sar(valInt, shiftBy);
+ expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Sar({0},{1}): {2}", valInt, shiftBy, resInt);
+ if (resInt != expectedInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedInt);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedInt);
+
+ valInt = 0x7FFFFFFF;
+ shiftBy = 30;
+ resInt = Sar(valInt, shiftBy);
+ expectedInt = (int) (valInt / Math.Pow(2, shiftBy));
+ Console.Write("UnitTest Sar({0},{1}): {2}", valInt, shiftBy, resInt);
+ if (resInt != expectedInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedInt);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedInt);
+
+ //
+ // shr tests
+ //
+ valUInt = 1;
+ shiftBy = 1;
+ resUInt = Shr(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shr({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ valUInt = 8;
+ shiftBy = 2;
+ resUInt = Shr(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shr({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ valUInt = 1;
+ shiftBy = 33;
+ resUInt = Shr(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt / Math.Pow(2, shiftBy));
+ Console.Write("UnitTest Shr({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ valUInt = 0xFFFFFFFF;
+ shiftBy = 31;
+ resUInt = Shr(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shr({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ valUInt = 0xFFFFFFFF;
+ shiftBy = 33;
+ resUInt = Shr(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shr({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ //
+ // Ror tests
+ //
+ valUInt = 0xFF;
+ shiftBy = 2;
+ resUInt = Ror(valUInt);
+ Console.Write("UnitTest Ror({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != 0xC000003F)
+ {
+ Console.Write(" Failed.\n");
+ return 101;
+ }
+ Console.Write(" Passed.\n");
+
+ //
+ // Shlx tests
+ //
+ valULong = 0;
+ shiftBy = 1;
+ resULong = Shlx(valULong, shiftBy);
+ expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Shlx({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ valULong = 8;
+ shiftBy = 1;
+ resULong = Shlx(valULong, shiftBy);
+ expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Shlx({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ valULong = 1;
+ shiftBy = 31;
+ resULong = Shlx(valULong, shiftBy);
+ expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Shlx({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ valULong = 1;
+ shiftBy = 33;
+ resULong = Shlx(valULong, shiftBy);
+ expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Shlx({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ valULong = 0xFFFFFFFF;
+ shiftBy = 1;
+ resULong = Shlx(valULong, shiftBy);
+ expectedULong = (ulong) (valULong * Math.Pow(2, shiftBy));
+ Console.Write("UnitTest Shlx({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ //
+ // Sarx tests
+ //
+ valLong = 1;
+ shiftBy = 1;
+ resLong = Sarx(valLong, shiftBy);
+ expectedLong = (long) (valLong / Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Sarx({0},{1}): {2}", valLong, shiftBy, resLong);
+ if (resLong != expectedLong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedLong);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedLong);
+
+ valLong = -8;
+ shiftBy = 1;
+ resLong = Sarx(valLong, shiftBy);
+ expectedLong = (long) (valLong / Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Sarx({0},{1}): {2}", valLong, shiftBy, resLong);
+ if (resLong != expectedLong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedLong);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedLong);
+
+ valLong = -8;
+ shiftBy = 65;
+ resLong = Sarx(valLong, shiftBy);
+ expectedLong = (long) (valLong / Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Sarx({0},{1}): {2}", valLong, shiftBy, resLong);
+ if (resLong != expectedLong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedLong);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedLong);
+
+ valLong = 0x7FFFFFFFFFFFFFFF;
+ shiftBy = 63;
+ resLong = Sarx(valLong, shiftBy);
+ expectedLong = 0;
+ Console.Write("UnitTest Sarx({0},{1}): {2}", valLong, shiftBy, resLong);
+ if (resLong != 0)
+ {
+ Console.Write(" != {0} Failed.\n", expectedLong);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedLong);
+
+ valLong = 0x7FFFFFFFFFFFFFFF;
+ shiftBy = 65;
+ resLong = Sarx(valLong, shiftBy);
+ expectedLong = 0x3FFFFFFFFFFFFFFF;
+ Console.Write("UnitTest Sarx({0},{1}): {2}", valLong, shiftBy, resLong);
+ if (resLong != expectedLong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedLong);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedLong);
+
+ //
+ // Shrx tests
+ //
+ valULong = 1;
+ shiftBy = 1;
+ resULong = Shrx(valULong, shiftBy);
+ expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Shrx({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ valULong = 8;
+ shiftBy = 2;
+ resULong = Shrx(valULong, shiftBy);
+ expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Shrx({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ valULong = 0xFFFFFFFFFFFFFFFF;
+ shiftBy = 63;
+ resULong = Shrx(valULong, shiftBy);
+ expectedULong = 1;
+ Console.Write("UnitTest Shrx({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ valULong = 0x7FFFFFFFFFFFFFFF;
+ shiftBy = 65;
+ resULong = Shrx(valULong, shiftBy);
+ expectedULong = 0x3FFFFFFFFFFFFFFF;
+ Console.Write("UnitTest Shrx({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ valULong = 8;
+ shiftBy = 65;
+ resULong = Shrx(valULong, shiftBy);
+ expectedULong = 4;
+ Console.Write("UnitTest Shrx({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ //
+ // ShrxRef
+ //
+ valULong = 8;
+ shiftBy = 1;
+ resULong = ShrxRef(&valULong, shiftBy);
+ expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest ShrxRef({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ return 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ //
+ // Rorx tests
+ //
+ valULong = 0xFF;
+ shiftBy = 2;
+ resULong = Rorx(valULong);
+ Console.Write("UnitTest Rorx({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != 0xC00000000000003F)
+ {
+ Console.Write(" Failed.\n");
+ return 101;
+ }
+ Console.Write(" Passed.\n");
+
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e.Message);
+ return 101;
+ }
+ Console.WriteLine("PASSED");
+ return 100;
+}
+}
\ No newline at end of file
diff --git a/src/tests/JIT/SIMD/ShiftOperations.csproj b/src/tests/JIT/SIMD/ShiftOperations.csproj
new file mode 100644
index 00000000000000..5e5fbae5cb863b
--- /dev/null
+++ b/src/tests/JIT/SIMD/ShiftOperations.csproj
@@ -0,0 +1,12 @@
+
+
+ Exe
+
+
+ PdbOnly
+ True
+
+
+
+
+
From adbfc48f2b8c68b5e87a0592c6d09468a419c726 Mon Sep 17 00:00:00 2001
From: Julie Lee <63486087+JulieLeeMSFT@users.noreply.github.com>
Date: Fri, 25 Mar 2022 18:05:37 -0700
Subject: [PATCH 05/15] Shlx, sarx, shrx code clean-up
---
src/coreclr/jit/codegenxarch.cpp | 2 +-
src/coreclr/jit/emitxarch.cpp | 25 ++-----------------------
src/coreclr/jit/emitxarch.h | 3 ---
src/coreclr/jit/lowerxarch.cpp | 2 +-
4 files changed, 4 insertions(+), 28 deletions(-)
diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp
index a6966dbc25d29c..cab21cbc112a37 100644
--- a/src/coreclr/jit/codegenxarch.cpp
+++ b/src/coreclr/jit/codegenxarch.cpp
@@ -4341,7 +4341,7 @@ instruction CodeGen::genGetInsForOper(genTreeOps oper, var_types type)
// tree - the bit shift node (that specifies the type of bit shift to perform).
//
// Assumptions:
-// a) All GenTrees are register allocated or source operand in tree->AsOp()->gtOp1 is contained memory address.
+// a) All GenTrees are register allocated.
// b) The shift-by-amount in tree->AsOp()->gtOp2 is either a contained constant or
// it's a register-allocated expression. If it is in a register that is
// not RCX, it will be moved to RCX (so RCX better not be in use!).
diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp
index c28847419d1120..0d88485d082b55 100644
--- a/src/coreclr/jit/emitxarch.cpp
+++ b/src/coreclr/jit/emitxarch.cpp
@@ -5086,27 +5086,6 @@ void emitter::emitIns_R_R_A(instruction ins, emitAttr attr, regNumber reg1, regN
emitCurIGsize += sz;
}
-void emitter::emitIns_R_A_R(instruction ins, emitAttr attr, regNumber reg1, GenTreeIndir* indir, regNumber reg2)
-{
- assert(IsSSEOrAVXInstruction(ins));
- assert(IsThreeOperandAVXInstruction(ins));
-
- ssize_t offs = indir->Offset();
- instrDesc* id = emitNewInstrAmd(attr, offs);
-
- id->idIns(ins);
- id->idReg1(reg1);
- id->idReg2(reg2);
-
- emitHandleMemOp(indir, id, IF_RWR_RRD_ARD, ins);
-
- UNATIVE_OFFSET sz = emitInsSizeAM(id, insCodeRM(ins));
- id->idCodeSize(sz);
-
- dispIns(id);
- emitCurIGsize += sz;
-}
-
void emitter::emitIns_R_R_AR(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber base, int offs)
{
assert(IsSSEOrAVXInstruction(ins));
@@ -16363,8 +16342,8 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
case INS_sarx:
case INS_shrx:
{
- result.insLatency = PERFSCORE_LATENCY_1C;
- result.insThroughput = PERFSCORE_THROUGHPUT_1C;
+ result.insLatency = PERFSCORE_LATENCY_2C;
+ result.insThroughput = PERFSCORE_THROUGHPUT_2X;
break;
}
diff --git a/src/coreclr/jit/emitxarch.h b/src/coreclr/jit/emitxarch.h
index 552bf469f83154..3f1efdaac5e52b 100644
--- a/src/coreclr/jit/emitxarch.h
+++ b/src/coreclr/jit/emitxarch.h
@@ -347,8 +347,6 @@ void emitIns_R_S_I(instruction ins, emitAttr attr, regNumber reg1, int varx, int
void emitIns_R_R_A(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, GenTreeIndir* indir);
-void emitIns_R_A_R(instruction ins, emitAttr attr, regNumber reg1, GenTreeIndir* indir, regNumber reg2);
-
void emitIns_R_R_AR(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber base, int offs);
void emitIns_R_AR_R(instruction ins,
@@ -463,7 +461,6 @@ void emitIns_AX_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg,
void emitIns_SIMD_R_R_I(instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, int ival);
void emitIns_SIMD_R_R_A(instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, GenTreeIndir* indir);
-void emitIns_SIMD_R_A_R(instruction ins, emitAttr attr, regNumber targetReg, GenTreeIndir* indir, regNumber op2Reg);
void emitIns_SIMD_R_R_AR(
instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber base, int offset);
void emitIns_SIMD_R_R_C(
diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp
index 7d919e463371ed..d33fbc66fd44c9 100644
--- a/src/coreclr/jit/lowerxarch.cpp
+++ b/src/coreclr/jit/lowerxarch.cpp
@@ -4850,7 +4850,7 @@ void Lowering::ContainCheckShiftRotate(GenTreeOp* node)
assert(source->OperGet() == GT_LONG);
MakeSrcContained(node, source);
}
-#endif
+#endif // !TARGET_X86
GenTree* shiftBy = node->gtOp2;
if (IsContainableImmed(node, shiftBy) && (shiftBy->AsIntConCommon()->IconValue() <= 255) &&
From 53181e48feabe1fadf929f4c9e9340b633d5b04b Mon Sep 17 00:00:00 2001
From: Julie Lee <63486087+JulieLeeMSFT@users.noreply.github.com>
Date: Tue, 29 Mar 2022 13:04:02 -0700
Subject: [PATCH 06/15] Emit shlx, sarx, shrx: Enable 32 bit shifts and
addressed feedback.
---
src/coreclr/jit/codegenxarch.cpp | 3 +-
src/coreclr/jit/emitxarch.cpp | 2 +-
src/coreclr/jit/lsraxarch.cpp | 4 +-
src/tests/JIT/SIMD/ShiftOperations.cs | 184 +++++++++++-----------
src/tests/JIT/SIMD/ShiftOperations.csproj | 1 +
5 files changed, 98 insertions(+), 96 deletions(-)
diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp
index cab21cbc112a37..0d969b2fc4b163 100644
--- a/src/coreclr/jit/codegenxarch.cpp
+++ b/src/coreclr/jit/codegenxarch.cpp
@@ -4405,8 +4405,7 @@ void CodeGen::genCodeForShift(GenTree* tree)
}
}
#if defined(TARGET_64BIT)
- else if (compiler->compOpportunisticallyDependsOn(InstructionSet_BMI2) && tree->OperIs(GT_LSH, GT_RSH, GT_RSZ) &&
- (genActualType(targetType) == TYP_LONG))
+ else if (tree->OperIsShift() && compiler->compOpportunisticallyDependsOn(InstructionSet_BMI2))
{
// Try to emit shlx, sarx, shrx if BMI2 is available instead of mov+shl, mov+sar, mov+shr.
switch (tree->OperGet())
diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp
index 0d88485d082b55..5ce70d652983bc 100644
--- a/src/coreclr/jit/emitxarch.cpp
+++ b/src/coreclr/jit/emitxarch.cpp
@@ -9535,7 +9535,7 @@ void emitter::emitDispIns(
regNumber reg3 = id->idReg3();
if (ins == INS_bextr || ins == INS_bzhi || ins == INS_shrx || ins == INS_shlx || ins == INS_sarx)
{
- // BMI bextr and bzhi encodes the reg2 in VEX.vvvv and reg3 in modRM,
+ // BMI bextr,bzhi, shrx, shlx and sarx encode the reg2 in VEX.vvvv and reg3 in modRM,
// which is different from most of other instructions
regNumber tmp = reg2;
reg2 = reg3;
diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp
index cf2905dc8693dd..8ef1a739f3b29f 100644
--- a/src/coreclr/jit/lsraxarch.cpp
+++ b/src/coreclr/jit/lsraxarch.cpp
@@ -926,8 +926,8 @@ int LinearScan::BuildShiftRotate(GenTree* tree)
assert(shiftBy->OperIsConst());
}
#if defined(TARGET_64BIT)
- else if (compiler->compOpportunisticallyDependsOn(InstructionSet_BMI2) && tree->OperIs(GT_LSH, GT_RSH, GT_RSZ) &&
- !tree->isContained() && (genActualType(tree->TypeGet()) == TYP_LONG))
+ else if (tree->OperIsShift() && !tree->isContained() &&
+ compiler->compOpportunisticallyDependsOn(InstructionSet_BMI2))
{
srcCount += BuildOperandUses(source, srcCandidates);
srcCount += BuildOperandUses(shiftBy, srcCandidates);
diff --git a/src/tests/JIT/SIMD/ShiftOperations.cs b/src/tests/JIT/SIMD/ShiftOperations.cs
index 9893ee53ed02ad..5f74fd949507e5 100644
--- a/src/tests/JIT/SIMD/ShiftOperations.cs
+++ b/src/tests/JIT/SIMD/ShiftOperations.cs
@@ -6,28 +6,28 @@ public class Test
{
[MethodImpl(MethodImplOptions.NoInlining)]
- private static uint Shl(uint x, int y) => x<< y;
+ private static uint Shlx32bit(uint x, int y) => x<< y;
[MethodImpl(MethodImplOptions.NoInlining)]
- private static int Sar(int x, int y) => x >> y;
+ private static int Sarx32bit(int x, int y) => x >> y;
[MethodImpl(MethodImplOptions.NoInlining)]
- private static uint Shr(uint x, int y) => x >> y;
+ private static uint Shrx32bit(uint x, int y) => x >> y;
[MethodImpl(MethodImplOptions.NoInlining)]
private static uint Ror(uint x) => BitOperations.RotateRight(x, 2);
[MethodImpl(MethodImplOptions.NoInlining)]
- private static ulong Shlx(ulong x, int y) => x << y;
+ private static ulong Shlx64bit(ulong x, int y) => x << y;
[MethodImpl(MethodImplOptions.NoInlining)]
- private static long Sarx(long x, int y) => x >> y;
+ private static long Sarx64bit(long x, int y) => x >> y;
[MethodImpl(MethodImplOptions.NoInlining)]
- private static ulong Shrx(ulong x, int y) => x >> y;
+ private static ulong Shrx64bit(ulong x, int y) => x >> y;
[MethodImpl(MethodImplOptions.NoInlining)]
- private static unsafe ulong ShrxRef(ulong *x, int y) => *x >> y;
+ private static unsafe ulong ShrxRef64bit(ulong *x, int y) => *x >> y;
[MethodImpl(MethodImplOptions.NoInlining)]
private static ulong Rorx(ulong x) => BitOperations.RotateRight(x, 2);
@@ -36,11 +36,11 @@ public static unsafe int Main()
{
try
{
- uint valUInt = 0xFFFFFFFE;
- int valInt = 8;
- ulong valULong = 8;
- long valLong = 8;
- int shiftBy = 1;
+ uint valUInt = 0;
+ int valInt = 0;
+ ulong valULong = 0;
+ long valLong = 0;
+ int shiftBy = 0;
uint resUInt = 0;
int resInt = 0;
ulong resULong = 0;
@@ -53,13 +53,13 @@ public static unsafe int Main()
int MOD64 = 64;
//
- // shl tests
+ // Shlx32bit tests
//
valUInt = 0;
shiftBy = 1;
- resUInt = Shl(valUInt, shiftBy);
+ resUInt = Shlx32bit(valUInt, shiftBy);
expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shl({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
if (resUInt != expectedUInt)
{
Console.Write(" != {0} Failed.\n", expectedUInt);
@@ -69,9 +69,9 @@ public static unsafe int Main()
valUInt = 8;
shiftBy = 1;
- resUInt = Shl(valUInt, shiftBy);
+ resUInt = Shlx32bit(valUInt, shiftBy);
expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shl({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
if (resUInt != expectedUInt)
{
Console.Write(" != {0} Failed.\n", expectedUInt);
@@ -81,9 +81,9 @@ public static unsafe int Main()
valUInt = 1;
shiftBy = 31;
- resUInt = Shl(valUInt, shiftBy);
+ resUInt = Shlx32bit(valUInt, shiftBy);
expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shl({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
if (resUInt != expectedUInt)
{
Console.Write(" != {0} Failed.\n", expectedUInt);
@@ -93,9 +93,9 @@ public static unsafe int Main()
valUInt = 1;
shiftBy = 33;
- resUInt = Shl(valUInt, shiftBy);
+ resUInt = Shlx32bit(valUInt, shiftBy);
expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shl({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
if (resUInt != expectedUInt)
{
Console.Write(" != {0} Failed.\n", expectedUInt);
@@ -105,9 +105,9 @@ public static unsafe int Main()
valUInt = 0xFFFFFFFF;
shiftBy = 1;
- resUInt = Shl(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt * Math.Pow(2, shiftBy));
- Console.Write("UnitTest Shl({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ resUInt = Shlx32bit(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
if (resUInt != expectedUInt)
{
Console.Write(" != {0} Failed.\n", expectedUInt);
@@ -116,13 +116,13 @@ public static unsafe int Main()
Console.Write(" == {0} Passed.\n", expectedUInt);
//
- // sar tests
+ // Sarx32bit tests
//
valInt = 0;
shiftBy = 1;
- resInt = Sar(valInt, shiftBy);
+ resInt = Sarx32bit(valInt, shiftBy);
expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Sar({0},{1}): {2}", valInt, shiftBy, resInt);
+ Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
if (resInt != expectedInt)
{
Console.Write(" != {0} Failed.\n", expectedInt);
@@ -132,9 +132,9 @@ public static unsafe int Main()
valInt = -8;
shiftBy = 1;
- resInt = Sar(valInt, shiftBy);
+ resInt = Sarx32bit(valInt, shiftBy);
expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Sar({0},{1}): {2}", valInt, shiftBy, resInt);
+ Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
if (resInt != expectedInt)
{
Console.Write(" != {0} Failed.\n", expectedInt);
@@ -144,9 +144,9 @@ public static unsafe int Main()
valInt = 1;
shiftBy = 33;
- resInt = Sar(valInt, shiftBy);
+ resInt = Sarx32bit(valInt, shiftBy);
expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Sar({0},{1}): {2}", valInt, shiftBy, resInt);
+ Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
if (resInt != expectedInt)
{
Console.Write(" != {0} Failed.\n", expectedInt);
@@ -156,9 +156,9 @@ public static unsafe int Main()
valInt = 0x7FFFFFFF;
shiftBy = 33;
- resInt = Sar(valInt, shiftBy);
+ resInt = Sarx32bit(valInt, shiftBy);
expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Sar({0},{1}): {2}", valInt, shiftBy, resInt);
+ Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
if (resInt != expectedInt)
{
Console.Write(" != {0} Failed.\n", expectedInt);
@@ -168,9 +168,9 @@ public static unsafe int Main()
valInt = 0x7FFFFFFF;
shiftBy = 30;
- resInt = Sar(valInt, shiftBy);
- expectedInt = (int) (valInt / Math.Pow(2, shiftBy));
- Console.Write("UnitTest Sar({0},{1}): {2}", valInt, shiftBy, resInt);
+ resInt = Sarx32bit(valInt, shiftBy);
+ expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
if (resInt != expectedInt)
{
Console.Write(" != {0} Failed.\n", expectedInt);
@@ -179,13 +179,13 @@ public static unsafe int Main()
Console.Write(" == {0} Passed.\n", expectedInt);
//
- // shr tests
+ // Shrx32bit tests
//
valUInt = 1;
shiftBy = 1;
- resUInt = Shr(valUInt, shiftBy);
+ resUInt = Shrx32bit(valUInt, shiftBy);
expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shr({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
if (resUInt != expectedUInt)
{
Console.Write(" != {0} Failed.\n", expectedUInt);
@@ -195,9 +195,9 @@ public static unsafe int Main()
valUInt = 8;
shiftBy = 2;
- resUInt = Shr(valUInt, shiftBy);
+ resUInt = Shrx32bit(valUInt, shiftBy);
expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shr({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
if (resUInt != expectedUInt)
{
Console.Write(" != {0} Failed.\n", expectedUInt);
@@ -207,9 +207,9 @@ public static unsafe int Main()
valUInt = 1;
shiftBy = 33;
- resUInt = Shr(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt / Math.Pow(2, shiftBy));
- Console.Write("UnitTest Shr({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ resUInt = Shrx32bit(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
if (resUInt != expectedUInt)
{
Console.Write(" != {0} Failed.\n", expectedUInt);
@@ -219,9 +219,9 @@ public static unsafe int Main()
valUInt = 0xFFFFFFFF;
shiftBy = 31;
- resUInt = Shr(valUInt, shiftBy);
+ resUInt = Shrx32bit(valUInt, shiftBy);
expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shr({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
if (resUInt != expectedUInt)
{
Console.Write(" != {0} Failed.\n", expectedUInt);
@@ -231,9 +231,9 @@ public static unsafe int Main()
valUInt = 0xFFFFFFFF;
shiftBy = 33;
- resUInt = Shr(valUInt, shiftBy);
+ resUInt = Shrx32bit(valUInt, shiftBy);
expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shr({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
if (resUInt != expectedUInt)
{
Console.Write(" != {0} Failed.\n", expectedUInt);
@@ -256,13 +256,13 @@ public static unsafe int Main()
Console.Write(" Passed.\n");
//
- // Shlx tests
+ // Shlx64bit tests
//
valULong = 0;
shiftBy = 1;
- resULong = Shlx(valULong, shiftBy);
+ resULong = Shlx64bit(valULong, shiftBy);
expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shlx({0},{1}): {2}", valULong, shiftBy, resULong);
+ Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
if (resULong != expectedULong)
{
Console.Write(" != {0} Failed.\n", expectedULong);
@@ -272,9 +272,9 @@ public static unsafe int Main()
valULong = 8;
shiftBy = 1;
- resULong = Shlx(valULong, shiftBy);
+ resULong = Shlx64bit(valULong, shiftBy);
expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shlx({0},{1}): {2}", valULong, shiftBy, resULong);
+ Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
if (resULong != expectedULong)
{
Console.Write(" != {0} Failed.\n", expectedULong);
@@ -283,10 +283,10 @@ public static unsafe int Main()
Console.Write(" == {0} Passed.\n", expectedULong);
valULong = 1;
- shiftBy = 31;
- resULong = Shlx(valULong, shiftBy);
+ shiftBy = 63;
+ resULong = Shlx64bit(valULong, shiftBy);
expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shlx({0},{1}): {2}", valULong, shiftBy, resULong);
+ Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
if (resULong != expectedULong)
{
Console.Write(" != {0} Failed.\n", expectedULong);
@@ -295,10 +295,10 @@ public static unsafe int Main()
Console.Write(" == {0} Passed.\n", expectedULong);
valULong = 1;
- shiftBy = 33;
- resULong = Shlx(valULong, shiftBy);
+ shiftBy = 65;
+ resULong = Shlx64bit(valULong, shiftBy);
expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shlx({0},{1}): {2}", valULong, shiftBy, resULong);
+ Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
if (resULong != expectedULong)
{
Console.Write(" != {0} Failed.\n", expectedULong);
@@ -306,11 +306,11 @@ public static unsafe int Main()
}
Console.Write(" == {0} Passed.\n", expectedULong);
- valULong = 0xFFFFFFFF;
+ valULong = 0xFFFFFFFFFFFFFFFF;
shiftBy = 1;
- resULong = Shlx(valULong, shiftBy);
- expectedULong = (ulong) (valULong * Math.Pow(2, shiftBy));
- Console.Write("UnitTest Shlx({0},{1}): {2}", valULong, shiftBy, resULong);
+ resULong = Shlx64bit(valULong, shiftBy);
+ expectedULong = (ulong) (valULong ^ 1);
+ Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
if (resULong != expectedULong)
{
Console.Write(" != {0} Failed.\n", expectedULong);
@@ -319,13 +319,13 @@ public static unsafe int Main()
Console.Write(" == {0} Passed.\n", expectedULong);
//
- // Sarx tests
+ // Sarx64bit tests
//
valLong = 1;
shiftBy = 1;
- resLong = Sarx(valLong, shiftBy);
+ resLong = Sarx64bit(valLong, shiftBy);
expectedLong = (long) (valLong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Sarx({0},{1}): {2}", valLong, shiftBy, resLong);
+ Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
if (resLong != expectedLong)
{
Console.Write(" != {0} Failed.\n", expectedLong);
@@ -335,9 +335,9 @@ public static unsafe int Main()
valLong = -8;
shiftBy = 1;
- resLong = Sarx(valLong, shiftBy);
+ resLong = Sarx64bit(valLong, shiftBy);
expectedLong = (long) (valLong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Sarx({0},{1}): {2}", valLong, shiftBy, resLong);
+ Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
if (resLong != expectedLong)
{
Console.Write(" != {0} Failed.\n", expectedLong);
@@ -347,9 +347,9 @@ public static unsafe int Main()
valLong = -8;
shiftBy = 65;
- resLong = Sarx(valLong, shiftBy);
+ resLong = Sarx64bit(valLong, shiftBy);
expectedLong = (long) (valLong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Sarx({0},{1}): {2}", valLong, shiftBy, resLong);
+ Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
if (resLong != expectedLong)
{
Console.Write(" != {0} Failed.\n", expectedLong);
@@ -359,10 +359,10 @@ public static unsafe int Main()
valLong = 0x7FFFFFFFFFFFFFFF;
shiftBy = 63;
- resLong = Sarx(valLong, shiftBy);
+ resLong = Sarx64bit(valLong, shiftBy);
expectedLong = 0;
- Console.Write("UnitTest Sarx({0},{1}): {2}", valLong, shiftBy, resLong);
- if (resLong != 0)
+ Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
+ if (resLong != expectedLong)
{
Console.Write(" != {0} Failed.\n", expectedLong);
return 101;
@@ -371,9 +371,10 @@ public static unsafe int Main()
valLong = 0x7FFFFFFFFFFFFFFF;
shiftBy = 65;
- resLong = Sarx(valLong, shiftBy);
- expectedLong = 0x3FFFFFFFFFFFFFFF;
- Console.Write("UnitTest Sarx({0},{1}): {2}", valLong, shiftBy, resLong);
+ shiftBy = (int) Math.Pow(2, (shiftBy % MOD64));
+ resLong = Sarx64bit(valLong, shiftBy);
+ expectedLong = 0x1FFFFFFFFFFFFFFF;
+ Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
if (resLong != expectedLong)
{
Console.Write(" != {0} Failed.\n", expectedLong);
@@ -382,13 +383,13 @@ public static unsafe int Main()
Console.Write(" == {0} Passed.\n", expectedLong);
//
- // Shrx tests
+ // Shrx64bit tests
//
valULong = 1;
shiftBy = 1;
- resULong = Shrx(valULong, shiftBy);
+ resULong = Shrx64bit(valULong, shiftBy);
expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shrx({0},{1}): {2}", valULong, shiftBy, resULong);
+ Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
if (resULong != expectedULong)
{
Console.Write(" != {0} Failed.\n", expectedULong);
@@ -398,9 +399,9 @@ public static unsafe int Main()
valULong = 8;
shiftBy = 2;
- resULong = Shrx(valULong, shiftBy);
+ resULong = Shrx64bit(valULong, shiftBy);
expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shrx({0},{1}): {2}", valULong, shiftBy, resULong);
+ Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
if (resULong != expectedULong)
{
Console.Write(" != {0} Failed.\n", expectedULong);
@@ -410,9 +411,9 @@ public static unsafe int Main()
valULong = 0xFFFFFFFFFFFFFFFF;
shiftBy = 63;
- resULong = Shrx(valULong, shiftBy);
+ resULong = Shrx64bit(valULong, shiftBy);
expectedULong = 1;
- Console.Write("UnitTest Shrx({0},{1}): {2}", valULong, shiftBy, resULong);
+ Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
if (resULong != expectedULong)
{
Console.Write(" != {0} Failed.\n", expectedULong);
@@ -422,9 +423,9 @@ public static unsafe int Main()
valULong = 0x7FFFFFFFFFFFFFFF;
shiftBy = 65;
- resULong = Shrx(valULong, shiftBy);
+ resULong = Shrx64bit(valULong, shiftBy);
expectedULong = 0x3FFFFFFFFFFFFFFF;
- Console.Write("UnitTest Shrx({0},{1}): {2}", valULong, shiftBy, resULong);
+ Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
if (resULong != expectedULong)
{
Console.Write(" != {0} Failed.\n", expectedULong);
@@ -434,9 +435,10 @@ public static unsafe int Main()
valULong = 8;
shiftBy = 65;
- resULong = Shrx(valULong, shiftBy);
- expectedULong = 4;
- Console.Write("UnitTest Shrx({0},{1}): {2}", valULong, shiftBy, resULong);
+ resULong = Shrx64bit(valULong, shiftBy);
+ //expectedULong = 4;
+ expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
if (resULong != expectedULong)
{
Console.Write(" != {0} Failed.\n", expectedULong);
@@ -445,13 +447,13 @@ public static unsafe int Main()
Console.Write(" == {0} Passed.\n", expectedULong);
//
- // ShrxRef
+ // ShrxRef64bit
//
valULong = 8;
shiftBy = 1;
- resULong = ShrxRef(&valULong, shiftBy);
+ resULong = ShrxRef64bit(&valULong, shiftBy);
expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest ShrxRef({0},{1}): {2}", valULong, shiftBy, resULong);
+ Console.Write("UnitTest ShrxRef64bit({0},{1}): {2}", valULong, shiftBy, resULong);
if (resULong != expectedULong)
{
Console.Write(" != {0} Failed.\n", expectedULong);
diff --git a/src/tests/JIT/SIMD/ShiftOperations.csproj b/src/tests/JIT/SIMD/ShiftOperations.csproj
index 5e5fbae5cb863b..d7141b8f4b1601 100644
--- a/src/tests/JIT/SIMD/ShiftOperations.csproj
+++ b/src/tests/JIT/SIMD/ShiftOperations.csproj
@@ -1,6 +1,7 @@
Exe
+ true
PdbOnly
From 28438a0084147f5520880c4dee0d0a5aa961ef91 Mon Sep 17 00:00:00 2001
From: Julie Lee <63486087+JulieLeeMSFT@users.noreply.github.com>
Date: Wed, 20 Apr 2022 16:19:57 -0700
Subject: [PATCH 07/15] [shlx/sarx/shrx] Addressed CR feedback. - Removed
some tests from Arm/Arm64 due to a known undefined behavior - Excluded the
test from Mono due to a known undefined behavior - Resolved merge conflict
---
src/coreclr/jit/codegenxarch.cpp | 6 +-
src/coreclr/jit/emitxarch.cpp | 18 +-
src/coreclr/jit/lowerxarch.cpp | 2 +-
src/tests/JIT/SIMD/ShiftOperations.cs | 946 +++++++++++++-------------
src/tests/issues.targets | 5 +-
5 files changed, 500 insertions(+), 477 deletions(-)
diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp
index 0d969b2fc4b163..27688f5d9d4b24 100644
--- a/src/coreclr/jit/codegenxarch.cpp
+++ b/src/coreclr/jit/codegenxarch.cpp
@@ -4384,7 +4384,6 @@ void CodeGen::genCodeForShift(GenTree* tree)
int shiftByValue = (int)shiftBy->AsIntConCommon()->IconValue();
#if defined(TARGET_64BIT)
-
// Try to emit rorx if BMI2 is available instead of mov+rol
// it makes sense only for 64bit integers
if ((genActualType(targetType) == TYP_LONG) && (tree->GetRegNum() != operandReg) &&
@@ -4426,12 +4425,11 @@ void CodeGen::genCodeForShift(GenTree* tree)
unreached();
}
+ // It handles all register forms, but it does not handle contained form for memory operand.
regNumber shiftByReg = shiftBy->GetRegNum();
emitAttr size = emitTypeSize(tree);
+ // The order of operandReg and shiftByReg are swapped to follow shlx, sarx and shrx encoding spec.
GetEmitter()->emitIns_R_R_R(ins, size, tree->GetRegNum(), shiftByReg, operandReg);
- genProduceReg(tree);
-
- return;
}
#endif
else
diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp
index 5ce70d652983bc..89cdb628d53443 100644
--- a/src/coreclr/jit/emitxarch.cpp
+++ b/src/coreclr/jit/emitxarch.cpp
@@ -990,25 +990,32 @@ unsigned emitter::emitOutputRexOrVexPrefixIfNeeded(instruction ins, BYTE* dst, c
case INS_rorx:
case INS_pdep:
case INS_mulx:
+// TODO: Unblock when enabled for x86
+#ifdef TARGET_AMD64
case INS_shrx:
+#endif
{
vexPrefix |= 0x03;
break;
}
case INS_pext:
+// TODO: Unblock when enabled for x86
+#ifdef TARGET_AMD64
case INS_sarx:
+#endif
{
vexPrefix |= 0x02;
break;
}
-
+// TODO: Unblock when enabled for x86
+#ifdef TARGET_AMD64
case INS_shlx:
{
vexPrefix |= 0x01;
break;
}
-
+#endif
default:
{
vexPrefix |= 0x00;
@@ -9537,6 +9544,7 @@ void emitter::emitDispIns(
{
// BMI bextr,bzhi, shrx, shlx and sarx encode the reg2 in VEX.vvvv and reg3 in modRM,
// which is different from most of other instructions
+ // The order of operandReg and shiftByReg are swapped to follow shlx, sarx and shrx encoding spec.
regNumber tmp = reg2;
reg2 = reg3;
reg3 = tmp;
@@ -10328,7 +10336,6 @@ BYTE* emitter::emitOutputAM(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc)
// For this format, moves do not support a third operand, so we only need to handle the binary ops.
if (TakesVexPrefix(ins))
{
-
if (IsDstDstSrcAVXInstruction(ins))
{
regNumber src1 = REG_NA;
@@ -16338,15 +16345,16 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
break;
}
+#ifdef TARGET_AMD64
case INS_shlx:
case INS_sarx:
case INS_shrx:
{
- result.insLatency = PERFSCORE_LATENCY_2C;
+ result.insLatency += PERFSCORE_LATENCY_1C;
result.insThroughput = PERFSCORE_THROUGHPUT_2X;
break;
}
-
+#endif
default:
// unhandled instruction insFmt combination
perfScoreUnhandledInstruction(id, &result);
diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp
index d33fbc66fd44c9..ee94c6d9042ddf 100644
--- a/src/coreclr/jit/lowerxarch.cpp
+++ b/src/coreclr/jit/lowerxarch.cpp
@@ -4843,7 +4843,7 @@ void Lowering::ContainCheckDivOrMod(GenTreeOp* node)
void Lowering::ContainCheckShiftRotate(GenTreeOp* node)
{
assert(node->OperIsShiftOrRotate());
-#if defined(TARGET_X86)
+#ifdef TARGET_X86
GenTree* source = node->gtOp1;
if (node->OperIsShiftLong())
{
diff --git a/src/tests/JIT/SIMD/ShiftOperations.cs b/src/tests/JIT/SIMD/ShiftOperations.cs
index 5f74fd949507e5..17c47da326ecb5 100644
--- a/src/tests/JIT/SIMD/ShiftOperations.cs
+++ b/src/tests/JIT/SIMD/ShiftOperations.cs
@@ -1,487 +1,501 @@
using System;
using System.Runtime.CompilerServices;
using System.Numerics;
+using System.Runtime.InteropServices;
public class Test
-{
-
- [MethodImpl(MethodImplOptions.NoInlining)]
+{
+ [MethodImpl(MethodImplOptions.NoInlining)]
private static uint Shlx32bit(uint x, int y) => x<< y;
-
- [MethodImpl(MethodImplOptions.NoInlining)]
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
private static int Sarx32bit(int x, int y) => x >> y;
-
+
[MethodImpl(MethodImplOptions.NoInlining)]
private static uint Shrx32bit(uint x, int y) => x >> y;
-
- [MethodImpl(MethodImplOptions.NoInlining)]
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
private static uint Ror(uint x) => BitOperations.RotateRight(x, 2);
- [MethodImpl(MethodImplOptions.NoInlining)]
+ [MethodImpl(MethodImplOptions.NoInlining)]
private static ulong Shlx64bit(ulong x, int y) => x << y;
- [MethodImpl(MethodImplOptions.NoInlining)]
+ [MethodImpl(MethodImplOptions.NoInlining)]
private static long Sarx64bit(long x, int y) => x >> y;
[MethodImpl(MethodImplOptions.NoInlining)]
private static ulong Shrx64bit(ulong x, int y) => x >> y;
- [MethodImpl(MethodImplOptions.NoInlining)]
+ [MethodImpl(MethodImplOptions.NoInlining)]
private static unsafe ulong ShrxRef64bit(ulong *x, int y) => *x >> y;
-
- [MethodImpl(MethodImplOptions.NoInlining)]
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
private static ulong Rorx(ulong x) => BitOperations.RotateRight(x, 2);
-
-public static unsafe int Main()
-{
- try
- {
- uint valUInt = 0;
- int valInt = 0;
- ulong valULong = 0;
- long valLong = 0;
- int shiftBy = 0;
- uint resUInt = 0;
- int resInt = 0;
- ulong resULong = 0;
- long resLong = 0;
- uint expectedUInt = 0;
- int expectedInt = 0;
- ulong expectedULong = 0;
- long expectedLong = 0;
- int MOD32 = 32;
- int MOD64 = 64;
-
- //
- // Shlx32bit tests
- //
- valUInt = 0;
- shiftBy = 1;
- resUInt = Shlx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
-
- valUInt = 8;
- shiftBy = 1;
- resUInt = Shlx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
-
- valUInt = 1;
- shiftBy = 31;
- resUInt = Shlx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
-
- valUInt = 1;
- shiftBy = 33;
- resUInt = Shlx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
-
- valUInt = 0xFFFFFFFF;
- shiftBy = 1;
- resUInt = Shlx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
-
- //
- // Sarx32bit tests
- //
- valInt = 0;
- shiftBy = 1;
- resInt = Sarx32bit(valInt, shiftBy);
- expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
- if (resInt != expectedInt)
- {
- Console.Write(" != {0} Failed.\n", expectedInt);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedInt);
-
- valInt = -8;
- shiftBy = 1;
- resInt = Sarx32bit(valInt, shiftBy);
- expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
- if (resInt != expectedInt)
- {
- Console.Write(" != {0} Failed.\n", expectedInt);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedInt);
-
- valInt = 1;
- shiftBy = 33;
- resInt = Sarx32bit(valInt, shiftBy);
- expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
- if (resInt != expectedInt)
- {
- Console.Write(" != {0} Failed.\n", expectedInt);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedInt);
-
- valInt = 0x7FFFFFFF;
- shiftBy = 33;
- resInt = Sarx32bit(valInt, shiftBy);
- expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
- if (resInt != expectedInt)
- {
- Console.Write(" != {0} Failed.\n", expectedInt);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedInt);
-
- valInt = 0x7FFFFFFF;
- shiftBy = 30;
- resInt = Sarx32bit(valInt, shiftBy);
- expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
- if (resInt != expectedInt)
- {
- Console.Write(" != {0} Failed.\n", expectedInt);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedInt);
-
- //
- // Shrx32bit tests
- //
- valUInt = 1;
- shiftBy = 1;
- resUInt = Shrx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
-
- valUInt = 8;
- shiftBy = 2;
- resUInt = Shrx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
-
- valUInt = 1;
- shiftBy = 33;
- resUInt = Shrx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
-
- valUInt = 0xFFFFFFFF;
- shiftBy = 31;
- resUInt = Shrx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
-
- valUInt = 0xFFFFFFFF;
- shiftBy = 33;
- resUInt = Shrx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
-
- //
- // Ror tests
- //
- valUInt = 0xFF;
- shiftBy = 2;
- resUInt = Ror(valUInt);
- Console.Write("UnitTest Ror({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != 0xC000003F)
- {
- Console.Write(" Failed.\n");
- return 101;
- }
- Console.Write(" Passed.\n");
-
- //
- // Shlx64bit tests
- //
- valULong = 0;
- shiftBy = 1;
- resULong = Shlx64bit(valULong, shiftBy);
- expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
-
- valULong = 8;
- shiftBy = 1;
- resULong = Shlx64bit(valULong, shiftBy);
- expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
-
- valULong = 1;
- shiftBy = 63;
- resULong = Shlx64bit(valULong, shiftBy);
- expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
-
- valULong = 1;
- shiftBy = 65;
- resULong = Shlx64bit(valULong, shiftBy);
- expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
-
- valULong = 0xFFFFFFFFFFFFFFFF;
- shiftBy = 1;
- resULong = Shlx64bit(valULong, shiftBy);
- expectedULong = (ulong) (valULong ^ 1);
- Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
-
- //
- // Sarx64bit tests
- //
- valLong = 1;
- shiftBy = 1;
- resLong = Sarx64bit(valLong, shiftBy);
- expectedLong = (long) (valLong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
- if (resLong != expectedLong)
- {
- Console.Write(" != {0} Failed.\n", expectedLong);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedLong);
-
- valLong = -8;
- shiftBy = 1;
- resLong = Sarx64bit(valLong, shiftBy);
- expectedLong = (long) (valLong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
- if (resLong != expectedLong)
- {
- Console.Write(" != {0} Failed.\n", expectedLong);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedLong);
-
- valLong = -8;
- shiftBy = 65;
- resLong = Sarx64bit(valLong, shiftBy);
- expectedLong = (long) (valLong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
- if (resLong != expectedLong)
- {
- Console.Write(" != {0} Failed.\n", expectedLong);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedLong);
-
- valLong = 0x7FFFFFFFFFFFFFFF;
- shiftBy = 63;
- resLong = Sarx64bit(valLong, shiftBy);
- expectedLong = 0;
- Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
- if (resLong != expectedLong)
- {
- Console.Write(" != {0} Failed.\n", expectedLong);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedLong);
-
- valLong = 0x7FFFFFFFFFFFFFFF;
- shiftBy = 65;
- shiftBy = (int) Math.Pow(2, (shiftBy % MOD64));
- resLong = Sarx64bit(valLong, shiftBy);
- expectedLong = 0x1FFFFFFFFFFFFFFF;
- Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
- if (resLong != expectedLong)
- {
- Console.Write(" != {0} Failed.\n", expectedLong);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedLong);
-
- //
- // Shrx64bit tests
- //
- valULong = 1;
- shiftBy = 1;
- resULong = Shrx64bit(valULong, shiftBy);
- expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
-
- valULong = 8;
- shiftBy = 2;
- resULong = Shrx64bit(valULong, shiftBy);
- expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
-
- valULong = 0xFFFFFFFFFFFFFFFF;
- shiftBy = 63;
- resULong = Shrx64bit(valULong, shiftBy);
- expectedULong = 1;
- Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
-
- valULong = 0x7FFFFFFFFFFFFFFF;
- shiftBy = 65;
- resULong = Shrx64bit(valULong, shiftBy);
- expectedULong = 0x3FFFFFFFFFFFFFFF;
- Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
-
- valULong = 8;
- shiftBy = 65;
- resULong = Shrx64bit(valULong, shiftBy);
- //expectedULong = 4;
- expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
-
- //
- // ShrxRef64bit
- //
- valULong = 8;
- shiftBy = 1;
- resULong = ShrxRef64bit(&valULong, shiftBy);
- expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest ShrxRef64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- return 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
-
- //
- // Rorx tests
- //
- valULong = 0xFF;
- shiftBy = 2;
- resULong = Rorx(valULong);
- Console.Write("UnitTest Rorx({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != 0xC00000000000003F)
- {
- Console.Write(" Failed.\n");
- return 101;
- }
- Console.Write(" Passed.\n");
-
- }
- catch (Exception e)
- {
- Console.WriteLine(e.Message);
- return 101;
- }
- Console.WriteLine("PASSED");
- return 100;
+
+ public static unsafe int Main()
+ {
+ int returnCode = 100;
+
+ try
+ {
+ uint valUInt = 0;
+ int valInt = 0;
+ ulong valULong = 0;
+ long valLong = 0;
+ int shiftBy = 0;
+ uint resUInt = 0;
+ int resInt = 0;
+ ulong resULong = 0;
+ long resLong = 0;
+ uint expectedUInt = 0;
+ int expectedInt = 0;
+ ulong expectedULong = 0;
+ long expectedLong = 0;
+ int MOD32 = 32;
+ int MOD64 = 64;
+
+ //
+ // Shlx32bit tests
+ //
+ valUInt = 0;
+ shiftBy = 1;
+ resUInt = Shlx32bit(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ valUInt = 8;
+ shiftBy = 1;
+ resUInt = Shlx32bit(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ valUInt = 1;
+ shiftBy = 31;
+ resUInt = Shlx32bit(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ valUInt = 1;
+ shiftBy = 33;
+ resUInt = Shlx32bit(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ // Test only on x64 and x86. There is a known undefined behavior for Arm64 and Arm.
+ if (RuntimeInformation.ProcessArchitecture == Architecture.X64 || RuntimeInformation.ProcessArchitecture == Architecture.X86)
+ {
+ valUInt = 0xFFFFFFFF;
+ shiftBy = 1;
+ resUInt = Shlx32bit(valUInt, shiftBy);
+ expectedUInt = (uint)(valUInt * Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+ }
+
+ //
+ // Sarx32bit tests
+ //
+ valInt = 0;
+ shiftBy = 1;
+ resInt = Sarx32bit(valInt, shiftBy);
+ expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
+ if (resInt != expectedInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedInt);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedInt);
+
+ valInt = -8;
+ shiftBy = 1;
+ resInt = Sarx32bit(valInt, shiftBy);
+ expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
+ if (resInt != expectedInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedInt);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedInt);
+
+ valInt = 1;
+ shiftBy = 33;
+ resInt = Sarx32bit(valInt, shiftBy);
+ expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
+ if (resInt != expectedInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedInt);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedInt);
+
+ valInt = 0x7FFFFFFF;
+ shiftBy = 33;
+ resInt = Sarx32bit(valInt, shiftBy);
+ expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
+ if (resInt != expectedInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedInt);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedInt);
+
+ valInt = 0x7FFFFFFF;
+ shiftBy = 30;
+ resInt = Sarx32bit(valInt, shiftBy);
+ expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
+ if (resInt != expectedInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedInt);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedInt);
+
+ //
+ // Shrx32bit tests
+ //
+ valUInt = 1;
+ shiftBy = 1;
+ resUInt = Shrx32bit(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ valUInt = 8;
+ shiftBy = 2;
+ resUInt = Shrx32bit(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ valUInt = 1;
+ shiftBy = 33;
+ resUInt = Shrx32bit(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ valUInt = 0xFFFFFFFF;
+ shiftBy = 31;
+ resUInt = Shrx32bit(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ valUInt = 0xFFFFFFFF;
+ shiftBy = 33;
+ resUInt = Shrx32bit(valUInt, shiftBy);
+ expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
+ Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != expectedUInt)
+ {
+ Console.Write(" != {0} Failed.\n", expectedUInt);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedUInt);
+
+ //
+ // Ror tests
+ //
+ valUInt = 0xFF;
+ shiftBy = 2;
+ resUInt = Ror(valUInt);
+ Console.Write("UnitTest Ror({0},{1}): {2}", valUInt, shiftBy, resUInt);
+ if (resUInt != 0xC000003F)
+ {
+ Console.Write(" Failed.\n");
+ returnCode = 101;
+ }
+ Console.Write(" Passed.\n");
+
+ //
+ // Shlx64bit tests
+ //
+ valULong = 0;
+ shiftBy = 1;
+ resULong = Shlx64bit(valULong, shiftBy);
+ expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ valULong = 8;
+ shiftBy = 1;
+ resULong = Shlx64bit(valULong, shiftBy);
+ expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ valULong = 1;
+ shiftBy = 63;
+ resULong = Shlx64bit(valULong, shiftBy);
+ expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ valULong = 1;
+ shiftBy = 65;
+ resULong = Shlx64bit(valULong, shiftBy);
+ expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ valULong = 0xFFFFFFFFFFFFFFFF;
+ shiftBy = 1;
+ resULong = Shlx64bit(valULong, shiftBy);
+ expectedULong = (ulong) (valULong ^ 1);
+ Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ //
+ // Sarx64bit tests
+ //
+ valLong = 1;
+ shiftBy = 1;
+ resLong = Sarx64bit(valLong, shiftBy);
+ expectedLong = (long) (valLong / Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
+ if (resLong != expectedLong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedLong);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedLong);
+
+ valLong = -8;
+ shiftBy = 1;
+ resLong = Sarx64bit(valLong, shiftBy);
+ expectedLong = (long) (valLong / Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
+ if (resLong != expectedLong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedLong);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedLong);
+
+ valLong = -8;
+ shiftBy = 65;
+ resLong = Sarx64bit(valLong, shiftBy);
+ expectedLong = (long) (valLong / Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
+ if (resLong != expectedLong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedLong);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedLong);
+
+ valLong = 0x7FFFFFFFFFFFFFFF;
+ shiftBy = 63;
+ resLong = Sarx64bit(valLong, shiftBy);
+ expectedLong = 0;
+ Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
+ if (resLong != expectedLong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedLong);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedLong);
+
+ valLong = 0x7FFFFFFFFFFFFFFF;
+ shiftBy = 65;
+ shiftBy = (int) Math.Pow(2, (shiftBy % MOD64));
+ resLong = Sarx64bit(valLong, shiftBy);
+ expectedLong = 0x1FFFFFFFFFFFFFFF;
+ Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
+ if (resLong != expectedLong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedLong);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedLong);
+
+ //
+ // Shrx64bit tests
+ //
+ valULong = 1;
+ shiftBy = 1;
+ resULong = Shrx64bit(valULong, shiftBy);
+ expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ valULong = 8;
+ shiftBy = 2;
+ resULong = Shrx64bit(valULong, shiftBy);
+ expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ valULong = 0xFFFFFFFFFFFFFFFF;
+ shiftBy = 63;
+ resULong = Shrx64bit(valULong, shiftBy);
+ expectedULong = 1;
+ Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ valULong = 0x7FFFFFFFFFFFFFFF;
+ shiftBy = 65;
+ resULong = Shrx64bit(valULong, shiftBy);
+ expectedULong = 0x3FFFFFFFFFFFFFFF;
+ Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ valULong = 8;
+ shiftBy = 65;
+ resULong = Shrx64bit(valULong, shiftBy);
+ //expectedULong = 4;
+ expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ //
+ // ShrxRef64bit
+ //
+ valULong = 8;
+ shiftBy = 1;
+ resULong = ShrxRef64bit(&valULong, shiftBy);
+ expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
+ Console.Write("UnitTest ShrxRef64bit({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != expectedULong)
+ {
+ Console.Write(" != {0} Failed.\n", expectedULong);
+ returnCode = 101;
+ }
+ Console.Write(" == {0} Passed.\n", expectedULong);
+
+ //
+ // Rorx tests
+ //
+ valULong = 0xFF;
+ shiftBy = 2;
+ resULong = Rorx(valULong);
+ Console.Write("UnitTest Rorx({0},{1}): {2}", valULong, shiftBy, resULong);
+ if (resULong != 0xC00000000000003F)
+ {
+ Console.Write(" Failed.\n");
+ returnCode = 101;
+ }
+ Console.Write(" Passed.\n");
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e.Message);
+ return 101;
+ }
+
+ if (returnCode == 101)
+ {
+ Console.WriteLine("FAILED");
+ }
+ else if (returnCode == 100)
+ {
+ Console.WriteLine("PASSED");
+ }
+
+ return returnCode;
+ }
}
-}
\ No newline at end of file
diff --git a/src/tests/issues.targets b/src/tests/issues.targets
index 97b8df0f720d7b..844031498cd331 100644
--- a/src/tests/issues.targets
+++ b/src/tests/issues.targets
@@ -1484,7 +1484,10 @@
https://github.com/dotnet/runtime/issues/46174
-
+
+ There is a known undefined behavior with shifts and 0x0FFFFFFFF overflows, so skip the test for mono.
+
+
Tests features specific to coreclr
From 60742eef0d067d1f287166bf477302960b83ae7c Mon Sep 17 00:00:00 2001
From: Julie Lee <63486087+JulieLeeMSFT@users.noreply.github.com>
Date: Fri, 22 Apr 2022 12:52:35 -0700
Subject: [PATCH 08/15] shlx, sarx, shrx: added ifdef to target x64 only
---
src/coreclr/jit/emitxarch.cpp | 8 +++++++-
src/coreclr/jit/instrsxarch.h | 2 ++
src/coreclr/jit/lowerxarch.cpp | 2 +-
3 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp
index 89cdb628d53443..fa04d3208d7dbc 100644
--- a/src/coreclr/jit/emitxarch.cpp
+++ b/src/coreclr/jit/emitxarch.cpp
@@ -1502,9 +1502,11 @@ bool emitter::emitInsCanOnlyWriteSSE2OrAVXReg(instrDesc* id)
case INS_pextrw:
case INS_pextrw_sse41:
case INS_rorx:
+#ifdef TARGET_AMD64
case INS_shlx:
case INS_sarx:
case INS_shrx:
+#endif
{
// These SSE instructions write to a general purpose integer register.
return false;
@@ -9540,7 +9542,11 @@ void emitter::emitDispIns(
assert(IsThreeOperandAVXInstruction(ins));
regNumber reg2 = id->idReg2();
regNumber reg3 = id->idReg3();
- if (ins == INS_bextr || ins == INS_bzhi || ins == INS_shrx || ins == INS_shlx || ins == INS_sarx)
+ if (ins == INS_bextr || ins == INS_bzhi
+#ifdef TARGET_AMD64
+ || ins == INS_shrx || ins == INS_shlx || ins == INS_sarx
+#endif
+ )
{
// BMI bextr,bzhi, shrx, shlx and sarx encode the reg2 in VEX.vvvv and reg3 in modRM,
// which is different from most of other instructions
diff --git a/src/coreclr/jit/instrsxarch.h b/src/coreclr/jit/instrsxarch.h
index 06dd9ef0d2a505..0a8527a6393fe5 100644
--- a/src/coreclr/jit/instrsxarch.h
+++ b/src/coreclr/jit/instrsxarch.h
@@ -605,9 +605,11 @@ INST3(pdep, "pdep", IUM_WR, BAD_CODE, BAD_CODE,
INST3(pext, "pext", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF5), INS_Flags_IsDstDstSrcAVXInstruction) // Parallel Bits Extract
INST3(bzhi, "bzhi", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF5), Resets_OF | Writes_SF | Writes_ZF | Undefined_AF | Undefined_PF | Writes_CF | INS_Flags_IsDstDstSrcAVXInstruction) // Zero High Bits Starting with Specified Bit Position
INST3(mulx, "mulx", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF6), INS_Flags_IsDstDstSrcAVXInstruction) // Unsigned Multiply Without Affecting Flags
+#ifdef TARGET_AMD64
INST3(shlx, "shlx", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF7), INS_Flags_IsDstDstSrcAVXInstruction) // Shift Logical Left Without Affecting Flags
INST3(sarx, "sarx", IUM_WR, BAD_CODE, BAD_CODE, PACK4(0xF3, 0x0F, 0x38, 0xF7), INS_Flags_IsDstDstSrcAVXInstruction) // Shift Arithmetic Right Without Affecting Flags
INST3(shrx, "shrx", IUM_WR, BAD_CODE, BAD_CODE, PACK4(0xF2, 0x0F, 0x38, 0xF7), INS_Flags_IsDstDstSrcAVXInstruction) // Shift Logical Right Without Affecting Flags
+#endif
INST3(LAST_BMI_INSTRUCTION, "LAST_BMI_INSTRUCTION", IUM_WR, BAD_CODE, BAD_CODE, BAD_CODE, INS_FLAGS_None)
diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp
index ee94c6d9042ddf..65124bfc35533a 100644
--- a/src/coreclr/jit/lowerxarch.cpp
+++ b/src/coreclr/jit/lowerxarch.cpp
@@ -4850,7 +4850,7 @@ void Lowering::ContainCheckShiftRotate(GenTreeOp* node)
assert(source->OperGet() == GT_LONG);
MakeSrcContained(node, source);
}
-#endif // !TARGET_X86
+#endif
GenTree* shiftBy = node->gtOp2;
if (IsContainableImmed(node, shiftBy) && (shiftBy->AsIntConCommon()->IconValue() <= 255) &&
From ab2624fe9cb100588870aecdd11679075d4d4429 Mon Sep 17 00:00:00 2001
From: Julie Lee <63486087+JulieLeeMSFT@users.noreply.github.com>
Date: Fri, 22 Apr 2022 14:35:14 -0700
Subject: [PATCH 09/15] shlx, sarx, shrx jit-format fix
---
src/coreclr/jit/emitxarch.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp
index fa04d3208d7dbc..93171241c18aab 100644
--- a/src/coreclr/jit/emitxarch.cpp
+++ b/src/coreclr/jit/emitxarch.cpp
@@ -16356,7 +16356,7 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
case INS_sarx:
case INS_shrx:
{
- result.insLatency += PERFSCORE_LATENCY_1C;
+ result.insLatency += PERFSCORE_LATENCY_1C;
result.insThroughput = PERFSCORE_THROUGHPUT_2X;
break;
}
From 21983281d417efddbe47a41c99cd14566e498b3e Mon Sep 17 00:00:00 2001
From: Julie Lee <63486087+JulieLeeMSFT@users.noreply.github.com>
Date: Wed, 11 May 2022 19:23:53 -0700
Subject: [PATCH 10/15] [shlx/sarx/shrx] Addressed feedback.
---
src/coreclr/jit/codegenxarch.cpp | 1 -
src/coreclr/jit/emitxarch.cpp | 1 -
src/coreclr/jit/lsraxarch.cpp | 1 +
src/tests/JIT/SIMD/ShiftOperations.cs | 466 ++++++--------------------
src/tests/issues.targets | 2 +-
5 files changed, 111 insertions(+), 360 deletions(-)
diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp
index 27688f5d9d4b24..837937d12db79d 100644
--- a/src/coreclr/jit/codegenxarch.cpp
+++ b/src/coreclr/jit/codegenxarch.cpp
@@ -4425,7 +4425,6 @@ void CodeGen::genCodeForShift(GenTree* tree)
unreached();
}
- // It handles all register forms, but it does not handle contained form for memory operand.
regNumber shiftByReg = shiftBy->GetRegNum();
emitAttr size = emitTypeSize(tree);
// The order of operandReg and shiftByReg are swapped to follow shlx, sarx and shrx encoding spec.
diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp
index 93171241c18aab..7ca24ecf672675 100644
--- a/src/coreclr/jit/emitxarch.cpp
+++ b/src/coreclr/jit/emitxarch.cpp
@@ -9550,7 +9550,6 @@ void emitter::emitDispIns(
{
// BMI bextr,bzhi, shrx, shlx and sarx encode the reg2 in VEX.vvvv and reg3 in modRM,
// which is different from most of other instructions
- // The order of operandReg and shiftByReg are swapped to follow shlx, sarx and shrx encoding spec.
regNumber tmp = reg2;
reg2 = reg3;
reg3 = tmp;
diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp
index 8ef1a739f3b29f..3bf9945aece942 100644
--- a/src/coreclr/jit/lsraxarch.cpp
+++ b/src/coreclr/jit/lsraxarch.cpp
@@ -929,6 +929,7 @@ int LinearScan::BuildShiftRotate(GenTree* tree)
else if (tree->OperIsShift() && !tree->isContained() &&
compiler->compOpportunisticallyDependsOn(InstructionSet_BMI2))
{
+ // It handles all register forms, but it does not handle contained form for memory operand.
srcCount += BuildOperandUses(source, srcCandidates);
srcCount += BuildOperandUses(shiftBy, srcCandidates);
BuildDef(tree, dstCandidates);
diff --git a/src/tests/JIT/SIMD/ShiftOperations.cs b/src/tests/JIT/SIMD/ShiftOperations.cs
index 17c47da326ecb5..3333166293e1f4 100644
--- a/src/tests/JIT/SIMD/ShiftOperations.cs
+++ b/src/tests/JIT/SIMD/ShiftOperations.cs
@@ -1,3 +1,5 @@
+// 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 System.Numerics;
@@ -32,9 +34,19 @@ public class Test
[MethodImpl(MethodImplOptions.NoInlining)]
private static ulong Rorx(ulong x) => BitOperations.RotateRight(x, 2);
+ public int Validate(actual, expected)
+ {
+ if (expected != actual)
+ {
+ Console.WriteLine("Fail");
+ return 101;
+ }
+ return 100;
+ }
+
public static unsafe int Main()
{
- int returnCode = 100;
+ int returnCode = 0;
try
{
@@ -57,53 +69,18 @@ public static unsafe int Main()
//
// Shlx32bit tests
//
- valUInt = 0;
- shiftBy = 1;
- resUInt = Shlx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
- valUInt = 8;
- shiftBy = 1;
- resUInt = Shlx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
-
- valUInt = 1;
- shiftBy = 31;
- resUInt = Shlx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
+ Console.Write("### UnitTest: Shlx32bit ###############\n");
+ uint[] valShlx32bit = new uint[] { 0, 8, 1, 1 };
+ int[] shiftByShlx32bit = new int[] { 1, 1, 31, 33 };
+ for (int idx = 0; idx < valShlx32bit.Length; idx++)
{
- Console.Write(" != {0} Failed.\n", expectedUInt);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
-
- valUInt = 1;
- shiftBy = 33;
- resUInt = Shlx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt * Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- returnCode = 101;
+ valUInt = valShlx32bit[idx];
+ shiftBy = shiftByShlx32bit[idx];
+ resUInt = Shlx32bit(valUInt, shiftBy);
+ expectedUInt = (uint)(valUInt * Math.Pow(2, (shiftBy % MOD32)));
+ returnCode = Validate(valUInt, shiftBy, resUInt, expectedUInt);
}
- Console.Write(" == {0} Passed.\n", expectedUInt);
// Test only on x64 and x86. There is a known undefined behavior for Arm64 and Arm.
if (RuntimeInformation.ProcessArchitecture == Architecture.X64 || RuntimeInformation.ProcessArchitecture == Architecture.X86)
@@ -112,374 +89,134 @@ public static unsafe int Main()
shiftBy = 1;
resUInt = Shlx32bit(valUInt, shiftBy);
expectedUInt = (uint)(valUInt * Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shlx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
+ returnCode = Validate(valUInt, shiftBy, resUInt, expectedUInt);
}
//
// Sarx32bit tests
//
- valInt = 0;
- shiftBy = 1;
- resInt = Sarx32bit(valInt, shiftBy);
- expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
- if (resInt != expectedInt)
- {
- Console.Write(" != {0} Failed.\n", expectedInt);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedInt);
- valInt = -8;
- shiftBy = 1;
- resInt = Sarx32bit(valInt, shiftBy);
- expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
- if (resInt != expectedInt)
- {
- Console.Write(" != {0} Failed.\n", expectedInt);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedInt);
-
- valInt = 1;
- shiftBy = 33;
- resInt = Sarx32bit(valInt, shiftBy);
- expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
- if (resInt != expectedInt)
- {
- Console.Write(" != {0} Failed.\n", expectedInt);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedInt);
-
- valInt = 0x7FFFFFFF;
- shiftBy = 33;
- resInt = Sarx32bit(valInt, shiftBy);
- expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
- if (resInt != expectedInt)
- {
- Console.Write(" != {0} Failed.\n", expectedInt);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedInt);
-
- valInt = 0x7FFFFFFF;
- shiftBy = 30;
- resInt = Sarx32bit(valInt, shiftBy);
- expectedInt = (int) (valInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Sarx32bit({0},{1}): {2}", valInt, shiftBy, resInt);
- if (resInt != expectedInt)
+ Console.Write("### UnitTest: Sarx32bit ###############\n");
+ int[] valSarx32bit = new int[] { 0, -8, 1, 0x7FFFFFFF, 0x7FFFFFFF };
+ int[] shiftBySarx32bit = new int[] { 1, 1, 33, 33, 30 };
+ for (int idx = 0; idx < valSarx32bit.Length; idx++)
{
- Console.Write(" != {0} Failed.\n", expectedInt);
- returnCode = 101;
+ valInt = valSarx32bit[idx];
+ shiftBy = shiftBySarx32bit[idx];
+ resInt = Sarx32bit(valInt, shiftBy);
+ expectedInt = (int)(valInt / Math.Pow(2, (shiftBy % MOD32)));
+ returnCode = Validate(valInt, shiftBy, resInt, expectedInt);
}
- Console.Write(" == {0} Passed.\n", expectedInt);
//
// Shrx32bit tests
//
- valUInt = 1;
- shiftBy = 1;
- resUInt = Shrx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
- valUInt = 8;
- shiftBy = 2;
- resUInt = Shrx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
-
- valUInt = 1;
- shiftBy = 33;
- resUInt = Shrx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
+ Console.Write("### UnitTest: Shrx32bit ###############\n");
+ uint[] valShrx32bit = new uint[] { 1, 8, 1, 0xFFFFFFFF, 0xFFFFFFFF };
+ int[] shiftByShrx32bit = new int[] { 1, 2, 33, 31, 33 };
+ for (int idx = 0; idx < valShrx32bit.Length; idx++)
{
- Console.Write(" != {0} Failed.\n", expectedUInt);
- returnCode = 101;
+ valUInt = valShrx32bit[idx];
+ shiftBy = shiftByShrx32bit[idx];
+ resUInt = Shrx32bit(valUInt, shiftBy);
+ expectedUInt = (uint)(valUInt / Math.Pow(2, (shiftBy % MOD32)));
+ returnCode = Validate(valUInt, shiftBy, resUInt, expectedUInt);
}
- Console.Write(" == {0} Passed.\n", expectedUInt);
-
- valUInt = 0xFFFFFFFF;
- shiftBy = 31;
- resUInt = Shrx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
-
- valUInt = 0xFFFFFFFF;
- shiftBy = 33;
- resUInt = Shrx32bit(valUInt, shiftBy);
- expectedUInt = (uint) (valUInt / Math.Pow(2, (shiftBy % MOD32)));
- Console.Write("UnitTest Shrx32bit({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != expectedUInt)
- {
- Console.Write(" != {0} Failed.\n", expectedUInt);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedUInt);
//
// Ror tests
//
+
+ Console.Write("### UnitTest: Ror ###############\n");
valUInt = 0xFF;
shiftBy = 2;
resUInt = Ror(valUInt);
- Console.Write("UnitTest Ror({0},{1}): {2}", valUInt, shiftBy, resUInt);
- if (resUInt != 0xC000003F)
- {
- Console.Write(" Failed.\n");
- returnCode = 101;
- }
- Console.Write(" Passed.\n");
+ expectedUInt = 0xC000003F;
+ returnCode = Validate(valUInt, shiftBy, resUInt, expectedUInt);
//
// Shlx64bit tests
//
- valULong = 0;
- shiftBy = 1;
- resULong = Shlx64bit(valULong, shiftBy);
- expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
-
- valULong = 8;
- shiftBy = 1;
- resULong = Shlx64bit(valULong, shiftBy);
- expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
-
- valULong = 1;
- shiftBy = 63;
- resULong = Shlx64bit(valULong, shiftBy);
- expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
-
- valULong = 1;
- shiftBy = 65;
- resULong = Shlx64bit(valULong, shiftBy);
- expectedULong = (ulong) (valULong * Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
- valULong = 0xFFFFFFFFFFFFFFFF;
- shiftBy = 1;
- resULong = Shlx64bit(valULong, shiftBy);
- expectedULong = (ulong) (valULong ^ 1);
- Console.Write("UnitTest Shlx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
+ Console.Write("### UnitTest: Shlx64bit ###############\n");
+ ulong[] valShlx64bit = new ulong[] { 0, 8, 1, 1, 0xFFFFFFFFFFFFFFFF };
+ int[] shiftByShlx64bit = new int[] { 1, 1, 63, 65, 1 };
+ for (int idx = 0; idx < valShlx64bit.Length; idx++)
{
- Console.Write(" != {0} Failed.\n", expectedULong);
- returnCode = 101;
+ valULong = valShlx64bit[idx];
+ shiftBy = shiftByShlx64bit[idx];
+ resULong = Shlx64bit(valULong, shiftBy);
+ if (idx == 4)
+ expectedULong = (ulong)(valULong ^ 1);
+ else
+ expectedULong = (ulong)(valULong * Math.Pow(2, (shiftBy % MOD64)));
+ returnCode = Validate(valULong, shiftBy, resULong, expectedULong);
}
- Console.Write(" == {0} Passed.\n", expectedULong);
//
// Sarx64bit tests
//
- valLong = 1;
- shiftBy = 1;
- resLong = Sarx64bit(valLong, shiftBy);
- expectedLong = (long) (valLong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
- if (resLong != expectedLong)
- {
- Console.Write(" != {0} Failed.\n", expectedLong);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedLong);
- valLong = -8;
- shiftBy = 1;
- resLong = Sarx64bit(valLong, shiftBy);
- expectedLong = (long) (valLong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
- if (resLong != expectedLong)
- {
- Console.Write(" != {0} Failed.\n", expectedLong);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedLong);
-
- valLong = -8;
- shiftBy = 65;
- resLong = Sarx64bit(valLong, shiftBy);
- expectedLong = (long) (valLong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
- if (resLong != expectedLong)
+ Console.Write("### UnitTest: Sarx64bit ###############\n");
+ long[] valSarx64bit = new long[] { 1, -8, -8, 0x7FFFFFFFFFFFFFFF };
+ int[] shiftBySarx64bit = new int[] { 1, 1, 65, 63 };
+ for (int idx = 0; idx < valSarx64bit.Length; idx++)
{
- Console.Write(" != {0} Failed.\n", expectedLong);
- returnCode = 101;
+ valLong = valSarx64bit[idx];
+ shiftBy = shiftBySarx64bit[idx];
+ resLong = Sarx64bit(valLong, shiftBy);
+ if (idx == 3)
+ expectedLong = 0;
+ else if (idx == 4)
+ expectedLong = 0x1FFFFFFFFFFFFFFF;
+ else
+ expectedLong = (long)(valLong / Math.Pow(2, (shiftBy % MOD64)));
+ returnCode = Validate(valLong, shiftBy, resLong, expectedLong);
}
- Console.Write(" == {0} Passed.\n", expectedLong);
-
- valLong = 0x7FFFFFFFFFFFFFFF;
- shiftBy = 63;
- resLong = Sarx64bit(valLong, shiftBy);
- expectedLong = 0;
- Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
- if (resLong != expectedLong)
- {
- Console.Write(" != {0} Failed.\n", expectedLong);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedLong);
-
- valLong = 0x7FFFFFFFFFFFFFFF;
- shiftBy = 65;
- shiftBy = (int) Math.Pow(2, (shiftBy % MOD64));
- resLong = Sarx64bit(valLong, shiftBy);
- expectedLong = 0x1FFFFFFFFFFFFFFF;
- Console.Write("UnitTest Sarx64bit({0},{1}): {2}", valLong, shiftBy, resLong);
- if (resLong != expectedLong)
- {
- Console.Write(" != {0} Failed.\n", expectedLong);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedLong);
//
// Shrx64bit tests
//
- valULong = 1;
- shiftBy = 1;
- resULong = Shrx64bit(valULong, shiftBy);
- expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
-
- valULong = 8;
- shiftBy = 2;
- resULong = Shrx64bit(valULong, shiftBy);
- expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
-
- valULong = 0xFFFFFFFFFFFFFFFF;
- shiftBy = 63;
- resULong = Shrx64bit(valULong, shiftBy);
- expectedULong = 1;
- Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
-
- valULong = 0x7FFFFFFFFFFFFFFF;
- shiftBy = 65;
- resULong = Shrx64bit(valULong, shiftBy);
- expectedULong = 0x3FFFFFFFFFFFFFFF;
- Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
- valULong = 8;
- shiftBy = 65;
- resULong = Shrx64bit(valULong, shiftBy);
- //expectedULong = 4;
- expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest Shrx64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
+ Console.Write("### UnitTest: Shrx64bit ###############\n");
+ ulong[] valShrx64bit = new ulong[] { 1, 8, 8, 0xFFFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF };
+ int[] shiftByShrx64bit = new int[] { 1, 2, 65, 63, 65 };
+ for (int idx = 0; idx < valShrx64bit.Length; idx++)
{
- Console.Write(" != {0} Failed.\n", expectedULong);
- returnCode = 101;
+ valULong = valShrx64bit[idx];
+ shiftBy = shiftByShrx64bit[idx];
+ resULong = Shrx64bit(valULong, shiftBy);
+ if (idx == 3)
+ expectedULong = 1;
+ else if (idx == 4)
+ expectedULong = 0x3FFFFFFFFFFFFFFF;
+ else
+ expectedULong = (ulong)(valULong / Math.Pow(2, (shiftBy % MOD64)));
+ returnCode = Validate(valULong, shiftBy, resULong, expectedULong);
}
- Console.Write(" == {0} Passed.\n", expectedULong);
//
// ShrxRef64bit
//
+
+ Console.Write("### UnitTest: ShrxRef64bit ###############\n");
valULong = 8;
shiftBy = 1;
resULong = ShrxRef64bit(&valULong, shiftBy);
expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
- Console.Write("UnitTest ShrxRef64bit({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != expectedULong)
- {
- Console.Write(" != {0} Failed.\n", expectedULong);
- returnCode = 101;
- }
- Console.Write(" == {0} Passed.\n", expectedULong);
+ returnCode = Validate(valULong, shiftBy, resULong, expectedULong);
//
// Rorx tests
//
+
+ Console.Write("### UnitTest: Rorx ###############\n");
valULong = 0xFF;
shiftBy = 2;
resULong = Rorx(valULong);
- Console.Write("UnitTest Rorx({0},{1}): {2}", valULong, shiftBy, resULong);
- if (resULong != 0xC00000000000003F)
- {
- Console.Write(" Failed.\n");
- returnCode = 101;
- }
- Console.Write(" Passed.\n");
+ expectedULong = 0xC00000000000003F;
+ returnCode = Validate(valULong, shiftBy, resULong, expectedULong);
}
catch (Exception e)
{
@@ -489,13 +226,28 @@ public static unsafe int Main()
if (returnCode == 101)
{
- Console.WriteLine("FAILED");
+ Console.WriteLine("FAILED.");
}
else if (returnCode == 100)
{
- Console.WriteLine("PASSED");
+ Console.WriteLine("PASSED.");
}
return returnCode;
}
+
+ private static int Validate(T value, int shiftBy, T actual, T expected)
+ {
+ Console.Write("(value, shiftBy) ({0},{1}): {2}", value, shiftBy, actual);
+ if (EqualityComparer.Default.Equals(actual, expected))
+ {
+ Console.Write(" == {0} ==> Passed.\n", expected);
+ return 100;
+ }
+ else
+ {
+ Console.Write(" != {0} ==> Failed.\n", expected);
+ return 101;
+ }
+ }
}
diff --git a/src/tests/issues.targets b/src/tests/issues.targets
index 844031498cd331..458304bc17832f 100644
--- a/src/tests/issues.targets
+++ b/src/tests/issues.targets
@@ -1485,7 +1485,7 @@
https://github.com/dotnet/runtime/issues/46174
- There is a known undefined behavior with shifts and 0x0FFFFFFFF overflows, so skip the test for mono.
+ There is a known undefined behavior with shifts and 0xFFFFFFFF overflows, so skip the test for mono.
From f629bfd0d2582017c14d872bab96f99cf2e9d898 Mon Sep 17 00:00:00 2001
From: Julie Lee <63486087+JulieLeeMSFT@users.noreply.github.com>
Date: Fri, 13 May 2022 12:11:12 -0700
Subject: [PATCH 11/15] [Emit shlx, sarx, shrx] addressed feedback on unit test
---
src/tests/JIT/SIMD/ShiftOperations.cs | 116 +++++++++++++++-----------
1 file changed, 68 insertions(+), 48 deletions(-)
diff --git a/src/tests/JIT/SIMD/ShiftOperations.cs b/src/tests/JIT/SIMD/ShiftOperations.cs
index 3333166293e1f4..831d71fb35eac2 100644
--- a/src/tests/JIT/SIMD/ShiftOperations.cs
+++ b/src/tests/JIT/SIMD/ShiftOperations.cs
@@ -4,11 +4,12 @@
using System.Runtime.CompilerServices;
using System.Numerics;
using System.Runtime.InteropServices;
+using System.Collections.Generic;
public class Test
{
[MethodImpl(MethodImplOptions.NoInlining)]
- private static uint Shlx32bit(uint x, int y) => x<< y;
+ private static uint Shlx32bit(uint x, int y) => x << y;
[MethodImpl(MethodImplOptions.NoInlining)]
private static int Sarx32bit(int x, int y) => x >> y;
@@ -29,29 +30,21 @@ public class Test
private static ulong Shrx64bit(ulong x, int y) => x >> y;
[MethodImpl(MethodImplOptions.NoInlining)]
- private static unsafe ulong ShrxRef64bit(ulong *x, int y) => *x >> y;
+ private static unsafe ulong ShrxRef64bit(ulong* x, int y) => *x >> y;
[MethodImpl(MethodImplOptions.NoInlining)]
private static ulong Rorx(ulong x) => BitOperations.RotateRight(x, 2);
- public int Validate(actual, expected)
- {
- if (expected != actual)
- {
- Console.WriteLine("Fail");
- return 101;
- }
- return 100;
- }
-
public static unsafe int Main()
{
- int returnCode = 0;
+ const int PASS = 100;
+ const int FAIL = 101;
+ int returnCode = PASS;
try
{
- uint valUInt = 0;
- int valInt = 0;
+ uint valUInt = 0;
+ int valInt = 0;
ulong valULong = 0;
long valLong = 0;
int shiftBy = 0;
@@ -70,7 +63,7 @@ public static unsafe int Main()
// Shlx32bit tests
//
- Console.Write("### UnitTest: Shlx32bit ###############\n");
+ Console.WriteLine("### UnitTest: Shlx32bit ###############");
uint[] valShlx32bit = new uint[] { 0, 8, 1, 1 };
int[] shiftByShlx32bit = new int[] { 1, 1, 31, 33 };
for (int idx = 0; idx < valShlx32bit.Length; idx++)
@@ -79,7 +72,10 @@ public static unsafe int Main()
shiftBy = shiftByShlx32bit[idx];
resUInt = Shlx32bit(valUInt, shiftBy);
expectedUInt = (uint)(valUInt * Math.Pow(2, (shiftBy % MOD32)));
- returnCode = Validate(valUInt, shiftBy, resUInt, expectedUInt);
+ if (!Validate(valUInt, shiftBy, resUInt, expectedUInt))
+ {
+ returnCode = FAIL;
+ }
}
// Test only on x64 and x86. There is a known undefined behavior for Arm64 and Arm.
@@ -89,14 +85,17 @@ public static unsafe int Main()
shiftBy = 1;
resUInt = Shlx32bit(valUInt, shiftBy);
expectedUInt = (uint)(valUInt * Math.Pow(2, (shiftBy % MOD32)));
- returnCode = Validate(valUInt, shiftBy, resUInt, expectedUInt);
+ if (!Validate(valUInt, shiftBy, resUInt, expectedUInt))
+ {
+ returnCode = FAIL;
+ }
}
//
// Sarx32bit tests
//
- Console.Write("### UnitTest: Sarx32bit ###############\n");
+ Console.WriteLine("### UnitTest: Sarx32bit ###############");
int[] valSarx32bit = new int[] { 0, -8, 1, 0x7FFFFFFF, 0x7FFFFFFF };
int[] shiftBySarx32bit = new int[] { 1, 1, 33, 33, 30 };
for (int idx = 0; idx < valSarx32bit.Length; idx++)
@@ -105,14 +104,17 @@ public static unsafe int Main()
shiftBy = shiftBySarx32bit[idx];
resInt = Sarx32bit(valInt, shiftBy);
expectedInt = (int)(valInt / Math.Pow(2, (shiftBy % MOD32)));
- returnCode = Validate(valInt, shiftBy, resInt, expectedInt);
+ if (!Validate(valInt, shiftBy, resInt, expectedInt))
+ {
+ returnCode = FAIL;
+ }
}
//
// Shrx32bit tests
//
- Console.Write("### UnitTest: Shrx32bit ###############\n");
+ Console.WriteLine("### UnitTest: Shrx32bit ###############");
uint[] valShrx32bit = new uint[] { 1, 8, 1, 0xFFFFFFFF, 0xFFFFFFFF };
int[] shiftByShrx32bit = new int[] { 1, 2, 33, 31, 33 };
for (int idx = 0; idx < valShrx32bit.Length; idx++)
@@ -121,25 +123,31 @@ public static unsafe int Main()
shiftBy = shiftByShrx32bit[idx];
resUInt = Shrx32bit(valUInt, shiftBy);
expectedUInt = (uint)(valUInt / Math.Pow(2, (shiftBy % MOD32)));
- returnCode = Validate(valUInt, shiftBy, resUInt, expectedUInt);
+ if (!Validate(valUInt, shiftBy, resUInt, expectedUInt))
+ {
+ returnCode = FAIL;
+ }
}
//
// Ror tests
//
- Console.Write("### UnitTest: Ror ###############\n");
+ Console.WriteLine("### UnitTest: Ror ###############");
valUInt = 0xFF;
shiftBy = 2;
resUInt = Ror(valUInt);
expectedUInt = 0xC000003F;
- returnCode = Validate(valUInt, shiftBy, resUInt, expectedUInt);
+ if (!Validate(valUInt, shiftBy, resUInt, expectedUInt))
+ {
+ returnCode = FAIL;
+ }
//
// Shlx64bit tests
//
- Console.Write("### UnitTest: Shlx64bit ###############\n");
+ Console.WriteLine("### UnitTest: Shlx64bit ###############");
ulong[] valShlx64bit = new ulong[] { 0, 8, 1, 1, 0xFFFFFFFFFFFFFFFF };
int[] shiftByShlx64bit = new int[] { 1, 1, 63, 65, 1 };
for (int idx = 0; idx < valShlx64bit.Length; idx++)
@@ -151,14 +159,17 @@ public static unsafe int Main()
expectedULong = (ulong)(valULong ^ 1);
else
expectedULong = (ulong)(valULong * Math.Pow(2, (shiftBy % MOD64)));
- returnCode = Validate(valULong, shiftBy, resULong, expectedULong);
+ if (!Validate(valULong, shiftBy, resULong, expectedULong))
+ {
+ returnCode = FAIL;
+ }
}
//
// Sarx64bit tests
//
- Console.Write("### UnitTest: Sarx64bit ###############\n");
+ Console.WriteLine("### UnitTest: Sarx64bit ###############");
long[] valSarx64bit = new long[] { 1, -8, -8, 0x7FFFFFFFFFFFFFFF };
int[] shiftBySarx64bit = new int[] { 1, 1, 65, 63 };
for (int idx = 0; idx < valSarx64bit.Length; idx++)
@@ -168,18 +179,19 @@ public static unsafe int Main()
resLong = Sarx64bit(valLong, shiftBy);
if (idx == 3)
expectedLong = 0;
- else if (idx == 4)
- expectedLong = 0x1FFFFFFFFFFFFFFF;
else
expectedLong = (long)(valLong / Math.Pow(2, (shiftBy % MOD64)));
- returnCode = Validate(valLong, shiftBy, resLong, expectedLong);
+ if (!Validate(valLong, shiftBy, resLong, expectedLong))
+ {
+ returnCode = FAIL;
+ }
}
//
// Shrx64bit tests
//
- Console.Write("### UnitTest: Shrx64bit ###############\n");
+ Console.WriteLine("### UnitTest: Shrx64bit ###############");
ulong[] valShrx64bit = new ulong[] { 1, 8, 8, 0xFFFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF };
int[] shiftByShrx64bit = new int[] { 1, 2, 65, 63, 65 };
for (int idx = 0; idx < valShrx64bit.Length; idx++)
@@ -193,61 +205,69 @@ public static unsafe int Main()
expectedULong = 0x3FFFFFFFFFFFFFFF;
else
expectedULong = (ulong)(valULong / Math.Pow(2, (shiftBy % MOD64)));
- returnCode = Validate(valULong, shiftBy, resULong, expectedULong);
+ if (!Validate(valULong, shiftBy, resULong, expectedULong))
+ {
+ returnCode = FAIL;
+ }
}
//
// ShrxRef64bit
//
- Console.Write("### UnitTest: ShrxRef64bit ###############\n");
+ Console.WriteLine("### UnitTest: ShrxRef64bit ###############");
valULong = 8;
shiftBy = 1;
resULong = ShrxRef64bit(&valULong, shiftBy);
- expectedULong = (ulong) (valULong / Math.Pow(2, (shiftBy % MOD64)));
- returnCode = Validate(valULong, shiftBy, resULong, expectedULong);
+ expectedULong = (ulong)(valULong / Math.Pow(2, (shiftBy % MOD64)));
+ if (!Validate(valULong, shiftBy, resULong, expectedULong))
+ {
+ returnCode = FAIL;
+ }
//
// Rorx tests
//
- Console.Write("### UnitTest: Rorx ###############\n");
+ Console.WriteLine("### UnitTest: Rorx ###############");
valULong = 0xFF;
shiftBy = 2;
resULong = Rorx(valULong);
expectedULong = 0xC00000000000003F;
- returnCode = Validate(valULong, shiftBy, resULong, expectedULong);
+ if (!Validate(valULong, shiftBy, resULong, expectedULong))
+ {
+ returnCode = FAIL;
+ }
}
catch (Exception e)
{
Console.WriteLine(e.Message);
- return 101;
+ return FAIL;
}
- if (returnCode == 101)
+ if (returnCode == PASS)
{
- Console.WriteLine("FAILED.");
+ Console.WriteLine("PASSED.");
}
- else if (returnCode == 100)
+ else
{
- Console.WriteLine("PASSED.");
+ Console.WriteLine("FAILED.");
}
-
return returnCode;
}
- private static int Validate(T value, int shiftBy, T actual, T expected)
+ private static bool Validate(T value, int shiftBy, T actual, T expected)
{
Console.Write("(value, shiftBy) ({0},{1}): {2}", value, shiftBy, actual);
if (EqualityComparer.Default.Equals(actual, expected))
{
- Console.Write(" == {0} ==> Passed.\n", expected);
- return 100;
+ Console.WriteLine(" == {0} ==> Passed.", expected);
+ return true;
}
else
{
- Console.Write(" != {0} ==> Failed.\n", expected);
- return 101;
+ Console.WriteLine(" != {0} ==> Failed.", expected);
+ return false;
}
}
}
From 2292e0582f03fe7bc223e124d279d32ea6aa6ee1 Mon Sep 17 00:00:00 2001
From: Julie Lee <63486087+JulieLeeMSFT@users.noreply.github.com>
Date: Fri, 13 May 2022 12:49:25 -0700
Subject: [PATCH 12/15] [Emit shlx, sarx, shrx] Removed x86 unit tests.
---
src/tests/JIT/SIMD/ShiftOperations.cs | 30 ++++++++-------------------
1 file changed, 9 insertions(+), 21 deletions(-)
diff --git a/src/tests/JIT/SIMD/ShiftOperations.cs b/src/tests/JIT/SIMD/ShiftOperations.cs
index 831d71fb35eac2..12160ccbd33f95 100644
--- a/src/tests/JIT/SIMD/ShiftOperations.cs
+++ b/src/tests/JIT/SIMD/ShiftOperations.cs
@@ -43,22 +43,23 @@ public static unsafe int Main()
try
{
- uint valUInt = 0;
- int valInt = 0;
ulong valULong = 0;
long valLong = 0;
int shiftBy = 0;
- uint resUInt = 0;
- int resInt = 0;
ulong resULong = 0;
long resLong = 0;
- uint expectedUInt = 0;
- int expectedInt = 0;
ulong expectedULong = 0;
long expectedLong = 0;
- int MOD32 = 32;
int MOD64 = 64;
+/* TODO: Enable 32bit test when x86 shift is enabled.
+ uint valUInt = 0;
+ int valInt = 0;
+ uint resUInt = 0;
+ int resInt = 0;
+ uint expectedUInt = 0;
+ int expectedInt = 0;
+ int MOD32 = 32;
//
// Shlx32bit tests
//
@@ -128,20 +129,7 @@ public static unsafe int Main()
returnCode = FAIL;
}
}
-
- //
- // Ror tests
- //
-
- Console.WriteLine("### UnitTest: Ror ###############");
- valUInt = 0xFF;
- shiftBy = 2;
- resUInt = Ror(valUInt);
- expectedUInt = 0xC000003F;
- if (!Validate(valUInt, shiftBy, resUInt, expectedUInt))
- {
- returnCode = FAIL;
- }
+*/ // End of x86 shift unit tests
//
// Shlx64bit tests
From f85d34ab85bd6b3fa385781d79f33829f13d0091 Mon Sep 17 00:00:00 2001
From: Julie Lee <63486087+JulieLeeMSFT@users.noreply.github.com>
Date: Mon, 16 May 2022 18:00:35 -0700
Subject: [PATCH 13/15] [Emit shlx, sarx, shrx] Remove 32bit test cases.
---
src/tests/JIT/SIMD/ShiftOperations.cs | 91 ---------------------------
1 file changed, 91 deletions(-)
diff --git a/src/tests/JIT/SIMD/ShiftOperations.cs b/src/tests/JIT/SIMD/ShiftOperations.cs
index 12160ccbd33f95..5acc180a56d0c1 100644
--- a/src/tests/JIT/SIMD/ShiftOperations.cs
+++ b/src/tests/JIT/SIMD/ShiftOperations.cs
@@ -8,18 +8,6 @@
public class Test
{
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static uint Shlx32bit(uint x, int y) => x << y;
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static int Sarx32bit(int x, int y) => x >> y;
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static uint Shrx32bit(uint x, int y) => x >> y;
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static uint Ror(uint x) => BitOperations.RotateRight(x, 2);
-
[MethodImpl(MethodImplOptions.NoInlining)]
private static ulong Shlx64bit(ulong x, int y) => x << y;
@@ -52,85 +40,6 @@ public static unsafe int Main()
long expectedLong = 0;
int MOD64 = 64;
-/* TODO: Enable 32bit test when x86 shift is enabled.
- uint valUInt = 0;
- int valInt = 0;
- uint resUInt = 0;
- int resInt = 0;
- uint expectedUInt = 0;
- int expectedInt = 0;
- int MOD32 = 32;
- //
- // Shlx32bit tests
- //
-
- Console.WriteLine("### UnitTest: Shlx32bit ###############");
- uint[] valShlx32bit = new uint[] { 0, 8, 1, 1 };
- int[] shiftByShlx32bit = new int[] { 1, 1, 31, 33 };
- for (int idx = 0; idx < valShlx32bit.Length; idx++)
- {
- valUInt = valShlx32bit[idx];
- shiftBy = shiftByShlx32bit[idx];
- resUInt = Shlx32bit(valUInt, shiftBy);
- expectedUInt = (uint)(valUInt * Math.Pow(2, (shiftBy % MOD32)));
- if (!Validate(valUInt, shiftBy, resUInt, expectedUInt))
- {
- returnCode = FAIL;
- }
- }
-
- // Test only on x64 and x86. There is a known undefined behavior for Arm64 and Arm.
- if (RuntimeInformation.ProcessArchitecture == Architecture.X64 || RuntimeInformation.ProcessArchitecture == Architecture.X86)
- {
- valUInt = 0xFFFFFFFF;
- shiftBy = 1;
- resUInt = Shlx32bit(valUInt, shiftBy);
- expectedUInt = (uint)(valUInt * Math.Pow(2, (shiftBy % MOD32)));
- if (!Validate(valUInt, shiftBy, resUInt, expectedUInt))
- {
- returnCode = FAIL;
- }
- }
-
- //
- // Sarx32bit tests
- //
-
- Console.WriteLine("### UnitTest: Sarx32bit ###############");
- int[] valSarx32bit = new int[] { 0, -8, 1, 0x7FFFFFFF, 0x7FFFFFFF };
- int[] shiftBySarx32bit = new int[] { 1, 1, 33, 33, 30 };
- for (int idx = 0; idx < valSarx32bit.Length; idx++)
- {
- valInt = valSarx32bit[idx];
- shiftBy = shiftBySarx32bit[idx];
- resInt = Sarx32bit(valInt, shiftBy);
- expectedInt = (int)(valInt / Math.Pow(2, (shiftBy % MOD32)));
- if (!Validate(valInt, shiftBy, resInt, expectedInt))
- {
- returnCode = FAIL;
- }
- }
-
- //
- // Shrx32bit tests
- //
-
- Console.WriteLine("### UnitTest: Shrx32bit ###############");
- uint[] valShrx32bit = new uint[] { 1, 8, 1, 0xFFFFFFFF, 0xFFFFFFFF };
- int[] shiftByShrx32bit = new int[] { 1, 2, 33, 31, 33 };
- for (int idx = 0; idx < valShrx32bit.Length; idx++)
- {
- valUInt = valShrx32bit[idx];
- shiftBy = shiftByShrx32bit[idx];
- resUInt = Shrx32bit(valUInt, shiftBy);
- expectedUInt = (uint)(valUInt / Math.Pow(2, (shiftBy % MOD32)));
- if (!Validate(valUInt, shiftBy, resUInt, expectedUInt))
- {
- returnCode = FAIL;
- }
- }
-*/ // End of x86 shift unit tests
-
//
// Shlx64bit tests
//
From 36b26a27936f83ae1fcf23fc3d24ff6fbcc5bb3c Mon Sep 17 00:00:00 2001
From: Julie Lee <63486087+JulieLeeMSFT@users.noreply.github.com>
Date: Wed, 18 May 2022 09:01:45 -0700
Subject: [PATCH 14/15] [Emit shlx, sarx, shrx] Update a comment in
lsraxarch.cpp
Co-authored-by: Kunal Pathak
---
src/coreclr/jit/lsraxarch.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp
index 3bf9945aece942..1250aba799c375 100644
--- a/src/coreclr/jit/lsraxarch.cpp
+++ b/src/coreclr/jit/lsraxarch.cpp
@@ -929,7 +929,7 @@ int LinearScan::BuildShiftRotate(GenTree* tree)
else if (tree->OperIsShift() && !tree->isContained() &&
compiler->compOpportunisticallyDependsOn(InstructionSet_BMI2))
{
- // It handles all register forms, but it does not handle contained form for memory operand.
+ // shlx (as opposed to mov+shl) instructions handles all register forms, but it does not handle contained form for memory operand. Likewise for sarx and shrx.
srcCount += BuildOperandUses(source, srcCandidates);
srcCount += BuildOperandUses(shiftBy, srcCandidates);
BuildDef(tree, dstCandidates);
From 5b454bb3072292b77a3cfe807f771a69d8055208 Mon Sep 17 00:00:00 2001
From: Julie Lee <63486087+JulieLeeMSFT@users.noreply.github.com>
Date: Wed, 18 May 2022 20:22:22 -0700
Subject: [PATCH 15/15] [Emit shlx, sarx, shrx] Added uint, int, ushort and
short test cases.
---
src/coreclr/jit/lsraxarch.cpp | 3 +-
src/tests/JIT/SIMD/ShiftOperations.cs | 280 +++++++++++++++++++-------
2 files changed, 214 insertions(+), 69 deletions(-)
diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp
index 1250aba799c375..1e5f03463c8079 100644
--- a/src/coreclr/jit/lsraxarch.cpp
+++ b/src/coreclr/jit/lsraxarch.cpp
@@ -929,7 +929,8 @@ int LinearScan::BuildShiftRotate(GenTree* tree)
else if (tree->OperIsShift() && !tree->isContained() &&
compiler->compOpportunisticallyDependsOn(InstructionSet_BMI2))
{
- // shlx (as opposed to mov+shl) instructions handles all register forms, but it does not handle contained form for memory operand. Likewise for sarx and shrx.
+ // shlx (as opposed to mov+shl) instructions handles all register forms, but it does not handle contained form
+ // for memory operand. Likewise for sarx and shrx.
srcCount += BuildOperandUses(source, srcCandidates);
srcCount += BuildOperandUses(shiftBy, srcCandidates);
BuildDef(tree, dstCandidates);
diff --git a/src/tests/JIT/SIMD/ShiftOperations.cs b/src/tests/JIT/SIMD/ShiftOperations.cs
index 5acc180a56d0c1..5122d261bdedac 100644
--- a/src/tests/JIT/SIMD/ShiftOperations.cs
+++ b/src/tests/JIT/SIMD/ShiftOperations.cs
@@ -9,19 +9,76 @@
public class Test
{
[MethodImpl(MethodImplOptions.NoInlining)]
- private static ulong Shlx64bit(ulong x, int y) => x << y;
+ private static R Shlx64bit(T x, int y)
+ {
+ switch (x)
+ {
+ case ulong a:
+ ulong resUlong = ((ulong)a) << y;
+ return (R)Convert.ChangeType(resUlong, typeof(R));
+ case uint b:
+ uint resUint = ((uint)b) << y;
+ return (R)Convert.ChangeType(resUint, typeof(R));
+ case ushort c:
+ int resInt = ((ushort)c) << y;
+ return (R)Convert.ChangeType(resInt, typeof(R));
+ default:
+ Console.WriteLine("Unsupported type.");
+ return default(R);
+ }
+ }
[MethodImpl(MethodImplOptions.NoInlining)]
- private static long Sarx64bit(long x, int y) => x >> y;
+ private static R Sarx64bit(T x, int y)
+ {
+ int resInt = 0;
+ switch (x)
+ {
+ case long a:
+ long resLong = ((long)a) >> y;
+ return (R)Convert.ChangeType(resLong, typeof(R));
+ case int b:
+ resInt = ((int)b) >> y;
+ return (R)Convert.ChangeType(resInt, typeof(R));
+ case short c:
+ Console.WriteLine($"Before: {Convert.ToString((short)c, toBase: 2)}");
+ resInt = ((short)c) >> y;
+ Console.WriteLine($"After: {Convert.ToString(resInt, toBase: 2)}");
+ return (R)Convert.ChangeType(resInt, typeof(R));
+ default:
+ Console.WriteLine("Unsupported type.");
+ return default(R);
+ }
+ }
[MethodImpl(MethodImplOptions.NoInlining)]
- private static ulong Shrx64bit(ulong x, int y) => x >> y;
+ private static R Shrx64bit(T x, int y)
+ {
+ switch (x)
+ {
+ case ulong a:
+ ulong resUlong = ((ulong)a) >> y;
+ return (R)Convert.ChangeType(resUlong, typeof(R));
+ case uint b:
+ uint resUint = ((uint)b) >> y;
+ return (R)Convert.ChangeType(resUint, typeof(R));
+ case ushort c:
+ int resInt = ((ushort)c) >> y;
+ return (R)Convert.ChangeType(resInt, typeof(R));
+ default:
+ Console.WriteLine("Unsupported type.");
+ return default(R);
+ }
+ }
[MethodImpl(MethodImplOptions.NoInlining)]
private static unsafe ulong ShrxRef64bit(ulong* x, int y) => *x >> y;
[MethodImpl(MethodImplOptions.NoInlining)]
- private static ulong Rorx(ulong x) => BitOperations.RotateRight(x, 2);
+ private static unsafe uint ShrxRef64bit(uint* x, int y) => *x >> y;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static unsafe int ShrxRef64bit(ushort* x, int y) => *x >> y;
public static unsafe int Main()
{
@@ -31,32 +88,54 @@ public static unsafe int Main()
try
{
- ulong valULong = 0;
- long valLong = 0;
- int shiftBy = 0;
- ulong resULong = 0;
- long resLong = 0;
- ulong expectedULong = 0;
- long expectedLong = 0;
- int MOD64 = 64;
-
//
// Shlx64bit tests
//
- Console.WriteLine("### UnitTest: Shlx64bit ###############");
- ulong[] valShlx64bit = new ulong[] { 0, 8, 1, 1, 0xFFFFFFFFFFFFFFFF };
- int[] shiftByShlx64bit = new int[] { 1, 1, 63, 65, 1 };
- for (int idx = 0; idx < valShlx64bit.Length; idx++)
+ // ulong
+ int MOD64 = 64;
+
+ Console.WriteLine();
+ Console.WriteLine("### UnitTest: Shlx64bit (ulong) ###############");
+ ulong[] valUlong = new ulong[] { 0, 8, 1, 1, 0xFFFFFFFFFFFFFFFF };
+ int[] shiftBy = new int[] { 1, 1, 63, 65, 1 };
+ for (int idx = 0; idx < valUlong.Length; idx++)
+ {
+ ulong resULong = (ulong)Shlx64bit(valUlong[idx], shiftBy[idx]);
+ ulong expectedUlong = (ulong)(valUlong[idx] << (shiftBy[idx] % MOD64));
+ if (!Validate(valUlong[idx], shiftBy[idx], resULong, expectedUlong))
+ {
+ returnCode = FAIL;
+ }
+ }
+
+ // uint
+ int MOD32 = 32;
+
+ Console.WriteLine();
+ Console.WriteLine("### UnitTest: Shlx64bit (uint) ###############");
+ uint[] valUint = new uint[] { 0, 8, 1, 1, 0xFFFFFFFF };
+ shiftBy = new int[] { 1, 1, 32, 33, 1 };
+ for (int idx = 0; idx < valUint.Length; idx++)
+ {
+ uint resUint = (uint)Shlx64bit(valUint[idx], shiftBy[idx]);
+ uint expectedUint = (uint)(valUint[idx] << (shiftBy[idx] % MOD32));
+ if (!Validate(valUint[idx], shiftBy[idx], resUint, expectedUint))
+ {
+ returnCode = FAIL;
+ }
+ }
+
+ // ushort
+ Console.WriteLine();
+ Console.WriteLine("### UnitTest: Shlx64bit (ushort) ###############");
+ ushort[] valUshort = new ushort[] { 0, 8, 1, 1, 0b_0111_0001_1000_0010 };
+ shiftBy = new int[] { 1, 1, 16, 18, 16 };
+ for (int idx = 0; idx < valUshort.Length; idx++)
{
- valULong = valShlx64bit[idx];
- shiftBy = shiftByShlx64bit[idx];
- resULong = Shlx64bit(valULong, shiftBy);
- if (idx == 4)
- expectedULong = (ulong)(valULong ^ 1);
- else
- expectedULong = (ulong)(valULong * Math.Pow(2, (shiftBy % MOD64)));
- if (!Validate(valULong, shiftBy, resULong, expectedULong))
+ int resInt = (int)Shlx64bit(valUshort[idx], shiftBy[idx]);
+ int expectedInt = (int)(((int)valUshort[idx]) << (shiftBy[idx] % MOD32));
+ if (!Validate(valUshort[idx], shiftBy[idx], resInt, expectedInt))
{
returnCode = FAIL;
}
@@ -66,19 +145,46 @@ public static unsafe int Main()
// Sarx64bit tests
//
- Console.WriteLine("### UnitTest: Sarx64bit ###############");
- long[] valSarx64bit = new long[] { 1, -8, -8, 0x7FFFFFFFFFFFFFFF };
- int[] shiftBySarx64bit = new int[] { 1, 1, 65, 63 };
- for (int idx = 0; idx < valSarx64bit.Length; idx++)
+ // long
+ Console.WriteLine();
+ Console.WriteLine("### UnitTest: Sarx64bit (long) ###############");
+ long[] valLong = new long[] { 1, -8, -8, 0x7FFFFFFFFFFFFFFF };
+ shiftBy = new int[] { 1, 1, 65, 63 };
+ for (int idx = 0; idx < valLong.Length; idx++)
+ {
+ long resLong = (long)Sarx64bit(valLong[idx], shiftBy[idx]);
+ long expectedLong = (long)(valLong[idx] >> (shiftBy[idx] % MOD64));
+ if (!Validate(valLong[idx], shiftBy[idx], resLong, expectedLong))
+ {
+ returnCode = FAIL;
+ }
+ }
+
+ // int
+ Console.WriteLine();
+ Console.WriteLine("### UnitTest: Sarx64bit (int) ###############");
+ int[] valInt = new int[] { 1, -8, -8, 0x7FFFFFFF };
+ shiftBy = new int[] { 1, 1, 32, 33 };
+ for (int idx = 0; idx < valInt.Length; idx++)
{
- valLong = valSarx64bit[idx];
- shiftBy = shiftBySarx64bit[idx];
- resLong = Sarx64bit(valLong, shiftBy);
- if (idx == 3)
- expectedLong = 0;
- else
- expectedLong = (long)(valLong / Math.Pow(2, (shiftBy % MOD64)));
- if (!Validate(valLong, shiftBy, resLong, expectedLong))
+ int resInt = (int)Sarx64bit(valInt[idx], shiftBy[idx]);
+ int expectedInt = (int)(valInt[idx] >> (shiftBy[idx] % MOD32));
+ if (!Validate(valInt[idx], shiftBy[idx], resInt, expectedInt))
+ {
+ returnCode = FAIL;
+ }
+ }
+
+ // short
+ Console.WriteLine();
+ Console.WriteLine("### UnitTest: Sarx64bit (short) ###############");
+ short[] valShort = new short[] { 1, -8, -8, 0b_0111_0001_1000_0010 };
+ shiftBy = new int[] { 1, 1, 16, 18 };
+ for (int idx = 0; idx < valShort.Length; idx++)
+ {
+ int resInt = (int)Sarx64bit(valShort[idx], shiftBy[idx]);
+ int expectedInt = (int)valShort[idx] >> (shiftBy[idx] % MOD32);
+ if (!Validate(valShort[idx], shiftBy[idx], resInt, expectedInt))
{
returnCode = FAIL;
}
@@ -88,21 +194,46 @@ public static unsafe int Main()
// Shrx64bit tests
//
- Console.WriteLine("### UnitTest: Shrx64bit ###############");
- ulong[] valShrx64bit = new ulong[] { 1, 8, 8, 0xFFFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF };
- int[] shiftByShrx64bit = new int[] { 1, 2, 65, 63, 65 };
- for (int idx = 0; idx < valShrx64bit.Length; idx++)
+ // ulong
+ Console.WriteLine();
+ Console.WriteLine("### UnitTest: Shrx64bit (ulong) ###############");
+ valUlong = new ulong[] { 1, 8, 8, 0xFFFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF };
+ shiftBy = new int[] { 1, 2, 65, 63, 65 };
+ for (int idx = 0; idx < valUlong.Length; idx++)
+ {
+ ulong resULong = (ulong)Shrx64bit(valUlong[idx], shiftBy[idx]);
+ ulong expectedUlong = (ulong)(valUlong[idx] >> (shiftBy[idx] % MOD64));
+ if (!Validate(valUlong[idx], shiftBy[idx], resULong, expectedUlong))
+ {
+ returnCode = FAIL;
+ }
+ }
+
+ // uint
+ Console.WriteLine();
+ Console.WriteLine("### UnitTest: Shrx64bit (uint) ###############");
+ valUint = new uint[] { 1, 8, 8, 0xFFFFFFFF };
+ shiftBy = new int[] { 1, 1, 32, 33 };
+ for (int idx = 0; idx < valUint.Length; idx++)
{
- valULong = valShrx64bit[idx];
- shiftBy = shiftByShrx64bit[idx];
- resULong = Shrx64bit(valULong, shiftBy);
- if (idx == 3)
- expectedULong = 1;
- else if (idx == 4)
- expectedULong = 0x3FFFFFFFFFFFFFFF;
- else
- expectedULong = (ulong)(valULong / Math.Pow(2, (shiftBy % MOD64)));
- if (!Validate(valULong, shiftBy, resULong, expectedULong))
+ uint resUint = (uint)Shrx64bit(valUint[idx], shiftBy[idx]);
+ uint expectedUint = (uint)(valUint[idx] >> (shiftBy[idx] % MOD32));
+ if (!Validate(valUint[idx], shiftBy[idx], resUint, expectedUint))
+ {
+ returnCode = FAIL;
+ }
+ }
+
+ // ushort
+ Console.WriteLine();
+ Console.WriteLine("### UnitTest: Shrx64bit (ushort) ###############");
+ valUshort = new ushort[] { 0, 8, 0b_1000_0000_0000_0000, 0b_1000_0000_0000_0000, 0b_1111_0001_1000_0010 };
+ shiftBy = new int[] { 1, 1, 15, 18, 40 };
+ for (int idx = 0; idx < valUshort.Length; idx++)
+ {
+ int resInt = (int)Shrx64bit(valUshort[idx], shiftBy[idx]);
+ int expectedInt = (int)(((int)valUshort[idx]) >> (shiftBy[idx] % MOD32));
+ if (!Validate(valUshort[idx], shiftBy[idx], resInt, expectedInt))
{
returnCode = FAIL;
}
@@ -112,26 +243,38 @@ public static unsafe int Main()
// ShrxRef64bit
//
- Console.WriteLine("### UnitTest: ShrxRef64bit ###############");
- valULong = 8;
- shiftBy = 1;
- resULong = ShrxRef64bit(&valULong, shiftBy);
- expectedULong = (ulong)(valULong / Math.Pow(2, (shiftBy % MOD64)));
- if (!Validate(valULong, shiftBy, resULong, expectedULong))
+ // ulong
+ Console.WriteLine();
+ Console.WriteLine("### UnitTest: ShrxRef64bit (ulong) ###############");
+ ulong valUlongRef = 8;
+ int shiftByRef = 1;
+ ulong resUlongRef = ShrxRef64bit(&valUlongRef, shiftByRef);
+ ulong expectedULongRef = (ulong)(valUlongRef >> (shiftByRef % MOD64));
+ if (!Validate(valUlongRef, shiftByRef, resUlongRef, expectedULongRef))
{
returnCode = FAIL;
}
- //
- // Rorx tests
- //
+ // uint
+ Console.WriteLine();
+ Console.WriteLine("### UnitTest: ShrxRef64bit (uint) ###############");
+ uint valUintRef = 0xFFFFFFFF;
+ shiftByRef = 1;
+ uint resUintRef = ShrxRef64bit(&valUintRef, shiftByRef);
+ uint expectedUintRef = (uint)(valUintRef >> (shiftByRef % MOD32));
+ if (!Validate(valUintRef, shiftByRef, resUintRef, expectedUintRef))
+ {
+ returnCode = FAIL;
+ }
- Console.WriteLine("### UnitTest: Rorx ###############");
- valULong = 0xFF;
- shiftBy = 2;
- resULong = Rorx(valULong);
- expectedULong = 0xC00000000000003F;
- if (!Validate(valULong, shiftBy, resULong, expectedULong))
+ // ushort
+ Console.WriteLine();
+ Console.WriteLine("### UnitTest: ShrxRef64bit (ushort) ###############");
+ ushort valUshortRef = 0xFFFF;
+ shiftByRef = 15;
+ int resUshortRef = ShrxRef64bit(&valUshortRef, shiftByRef);
+ int expectedUshortRef = (int)((uint)valUshortRef >> (shiftByRef % MOD32));
+ if (!Validate(valUshortRef, shiftByRef, resUshortRef, expectedUshortRef))
{
returnCode = FAIL;
}
@@ -142,6 +285,7 @@ public static unsafe int Main()
return FAIL;
}
+ Console.WriteLine();
if (returnCode == PASS)
{
Console.WriteLine("PASSED.");
@@ -153,10 +297,10 @@ public static unsafe int Main()
return returnCode;
}
- private static bool Validate(T value, int shiftBy, T actual, T expected)
+ private static bool Validate(TValue value, int shiftBy, TResult actual, TResult expected)
{
Console.Write("(value, shiftBy) ({0},{1}): {2}", value, shiftBy, actual);
- if (EqualityComparer.Default.Equals(actual, expected))
+ if (EqualityComparer.Default.Equals(actual, expected))
{
Console.WriteLine(" == {0} ==> Passed.", expected);
return true;