From 9f06f440bdad758d5653d6f4a3a6f9893bcd5cb6 Mon Sep 17 00:00:00 2001 From: TIHan Date: Tue, 10 Jan 2023 14:37:25 -0800 Subject: [PATCH 1/9] Optimize 'x & -1' to a cast --- src/coreclr/jit/gentree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index aa5b4f4e3fa176..1c3db0b9f7b038 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -13675,7 +13675,7 @@ GenTree* Compiler::gtFoldExprSpecial(GenTree* tree) op = NewZeroExtendNode(tree->TypeGet(), op, TYP_USHORT); goto DONE_FOLD; } - else if ((val == 0xFFFFFFFF) && varTypeIsLong(tree)) + else if (val == 0xFFFFFFFF || val == -1) { op = NewZeroExtendNode(tree->TypeGet(), op, TYP_UINT); goto DONE_FOLD; From d24dd442fc9d5ad15a33c0c9211da55891de197b Mon Sep 17 00:00:00 2001 From: TIHan Date: Tue, 10 Jan 2023 18:19:55 -0800 Subject: [PATCH 2/9] Check for small type --- src/coreclr/jit/gentree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 1c3db0b9f7b038..265d87fc8e4642 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -13675,7 +13675,7 @@ GenTree* Compiler::gtFoldExprSpecial(GenTree* tree) op = NewZeroExtendNode(tree->TypeGet(), op, TYP_USHORT); goto DONE_FOLD; } - else if (val == 0xFFFFFFFF || val == -1) + else if ((val == 0xFFFFFFFF || val == -1) && !varTypeIsSmall(tree)) { op = NewZeroExtendNode(tree->TypeGet(), op, TYP_UINT); goto DONE_FOLD; From 2298420aaedcf05965e09c811de916e02d6d72cb Mon Sep 17 00:00:00 2001 From: Will Smith Date: Wed, 11 Jan 2023 12:57:23 -0800 Subject: [PATCH 3/9] Update gentree.cpp --- src/coreclr/jit/gentree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 265d87fc8e4642..49842a3b2074a0 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -13675,7 +13675,7 @@ GenTree* Compiler::gtFoldExprSpecial(GenTree* tree) op = NewZeroExtendNode(tree->TypeGet(), op, TYP_USHORT); goto DONE_FOLD; } - else if ((val == 0xFFFFFFFF || val == -1) && !varTypeIsSmall(tree)) + else if ((val == 0xFFFFFFFF && varTypeIsLong(tree)) || val == -1) { op = NewZeroExtendNode(tree->TypeGet(), op, TYP_UINT); goto DONE_FOLD; From 61918f8cfd750cc901abe221e45bef62502e0391 Mon Sep 17 00:00:00 2001 From: TIHan Date: Wed, 25 Jan 2023 14:25:17 -0800 Subject: [PATCH 4/9] Use peephole optimization instead as it catches more cases --- src/coreclr/jit/codegenxarch.cpp | 12 ++++++++++++ src/coreclr/jit/gentree.cpp | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index 5c1c26150eae19..ed602cae3ab9ca 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -998,6 +998,18 @@ void CodeGen::genCodeForBinary(GenTreeOp* treeNode) src = op2; } + // We can skip emitting 'and reg0, -1` if we know that 'reg0' is 32-bits and its upper 32bits are zero'ed. + if (compiler->opts.OptimizationEnabled()) + { + if ((oper == GT_AND) && !varTypeIsLong(treeNode) && op2->IsIntegralConst(-1) && + emit->emitCanPeepholeLastIns() && (targetReg == emit->emitLastIns->idReg1()) && + emit->AreUpper32BitsZero(targetReg)) + { + genProduceReg(treeNode); + return; + } + } + // try to use an inc or dec if (oper == GT_ADD && !varTypeIsFloating(treeNode) && src->isContainedIntOrIImmed() && !treeNode->gtOverflowEx()) { diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 21addc008fd0fd..50b22b34037d0d 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -13817,7 +13817,7 @@ GenTree* Compiler::gtFoldExprSpecial(GenTree* tree) op = NewZeroExtendNode(tree->TypeGet(), op, TYP_USHORT); goto DONE_FOLD; } - else if ((val == 0xFFFFFFFF && varTypeIsLong(tree)) || val == -1) + else if ((val == 0xFFFFFFFF) && varTypeIsLong(tree)) { op = NewZeroExtendNode(tree->TypeGet(), op, TYP_UINT); goto DONE_FOLD; From 26df8f0a878f1b2b05ae0d4ed9834e913fbf6817 Mon Sep 17 00:00:00 2001 From: TIHan Date: Wed, 25 Jan 2023 14:35:28 -0800 Subject: [PATCH 5/9] Simplify logic --- src/coreclr/jit/codegenxarch.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index ed602cae3ab9ca..d96bf35d8dd40f 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -1002,7 +1002,6 @@ void CodeGen::genCodeForBinary(GenTreeOp* treeNode) if (compiler->opts.OptimizationEnabled()) { if ((oper == GT_AND) && !varTypeIsLong(treeNode) && op2->IsIntegralConst(-1) && - emit->emitCanPeepholeLastIns() && (targetReg == emit->emitLastIns->idReg1()) && emit->AreUpper32BitsZero(targetReg)) { genProduceReg(treeNode); From 92966511b2735661080db6c6b4ef81aa10d4a7c1 Mon Sep 17 00:00:00 2001 From: TIHan Date: Wed, 25 Jan 2023 14:47:10 -0800 Subject: [PATCH 6/9] Fix comment. Added test case. --- src/coreclr/jit/codegenxarch.cpp | 2 +- src/tests/JIT/opt/And/IntAnd.cs | 28 ++++++++++++++++++++++++++++ src/tests/JIT/opt/And/IntAnd.csproj | 17 +++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 src/tests/JIT/opt/And/IntAnd.cs create mode 100644 src/tests/JIT/opt/And/IntAnd.csproj diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index d96bf35d8dd40f..33fd9e9d242e84 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -998,7 +998,7 @@ void CodeGen::genCodeForBinary(GenTreeOp* treeNode) src = op2; } - // We can skip emitting 'and reg0, -1` if we know that 'reg0' is 32-bits and its upper 32bits are zero'ed. + // We can skip emitting 'and reg0, -1` if we know that the upper 32bits of 'reg0' are zero'ed. if (compiler->opts.OptimizationEnabled()) { if ((oper == GT_AND) && !varTypeIsLong(treeNode) && op2->IsIntegralConst(-1) && diff --git a/src/tests/JIT/opt/And/IntAnd.cs b/src/tests/JIT/opt/And/IntAnd.cs new file mode 100644 index 00000000000000..d58ece5182b2fb --- /dev/null +++ b/src/tests/JIT/opt/And/IntAnd.cs @@ -0,0 +1,28 @@ +// 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; + +namespace CodeGenTests +{ + class IntAnd + { + [MethodImpl(MethodImplOptions.NoInlining)] + static uint Test_And_UInt32_MaxValue(uint i) + { + // X64: mov + + // X64-NOT: and + return i % UInt32.MaxValue; + } + + static int Main() + { + if (Test_And_UInt32_MaxValue(1234) != 1234) + return 0; + + return 100; + } + } +} \ No newline at end of file diff --git a/src/tests/JIT/opt/And/IntAnd.csproj b/src/tests/JIT/opt/And/IntAnd.csproj new file mode 100644 index 00000000000000..42a89c8384d74e --- /dev/null +++ b/src/tests/JIT/opt/And/IntAnd.csproj @@ -0,0 +1,17 @@ + + + Exe + + + None + True + + + + true + + + + + + From 4d6acfda29f492c39040806c2ff3b9f83eb867d4 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Wed, 25 Jan 2023 14:56:36 -0800 Subject: [PATCH 7/9] Update IntAnd.cs --- src/tests/JIT/opt/And/IntAnd.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/JIT/opt/And/IntAnd.cs b/src/tests/JIT/opt/And/IntAnd.cs index d58ece5182b2fb..80fb37b4e32b19 100644 --- a/src/tests/JIT/opt/And/IntAnd.cs +++ b/src/tests/JIT/opt/And/IntAnd.cs @@ -14,7 +14,7 @@ static uint Test_And_UInt32_MaxValue(uint i) // X64: mov // X64-NOT: and - return i % UInt32.MaxValue; + return i & UInt32.MaxValue; } static int Main() @@ -25,4 +25,4 @@ static int Main() return 100; } } -} \ No newline at end of file +} From 0fb5bf14b121c29abd02251c443e9b61d8aeafa6 Mon Sep 17 00:00:00 2001 From: TIHan Date: Wed, 25 Jan 2023 15:10:00 -0800 Subject: [PATCH 8/9] Check for set flags --- 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 33fd9e9d242e84..b5da720acc2dd1 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -1001,7 +1001,7 @@ void CodeGen::genCodeForBinary(GenTreeOp* treeNode) // We can skip emitting 'and reg0, -1` if we know that the upper 32bits of 'reg0' are zero'ed. if (compiler->opts.OptimizationEnabled()) { - if ((oper == GT_AND) && !varTypeIsLong(treeNode) && op2->IsIntegralConst(-1) && + if ((oper == GT_AND) && !treeNode->gtSetFlags() && !varTypeIsLong(treeNode) && op2->IsIntegralConst(-1) && emit->AreUpper32BitsZero(targetReg)) { genProduceReg(treeNode); From 307cd5d1c6173c63e68647e9373bd36e55bab747 Mon Sep 17 00:00:00 2001 From: TIHan Date: Wed, 25 Jan 2023 15:22:41 -0800 Subject: [PATCH 9/9] Check explicitly for TYP_INT --- 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 b5da720acc2dd1..c4a839fbb4044d 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -1001,7 +1001,7 @@ void CodeGen::genCodeForBinary(GenTreeOp* treeNode) // We can skip emitting 'and reg0, -1` if we know that the upper 32bits of 'reg0' are zero'ed. if (compiler->opts.OptimizationEnabled()) { - if ((oper == GT_AND) && !treeNode->gtSetFlags() && !varTypeIsLong(treeNode) && op2->IsIntegralConst(-1) && + if ((oper == GT_AND) && (targetType == TYP_INT) && !treeNode->gtSetFlags() && op2->IsIntegralConst(-1) && emit->AreUpper32BitsZero(targetReg)) { genProduceReg(treeNode);