Skip to content

Commit 3e32e51

Browse files
arm64: Add support for bitwise NOT (#111904)
* Contributes to #68028
1 parent bcc0e89 commit 3e32e51

File tree

6 files changed

+150
-3
lines changed

6 files changed

+150
-3
lines changed

src/coreclr/jit/codegenarm64.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3490,13 +3490,15 @@ void CodeGen::genCodeForNegNot(GenTree* tree)
34903490

34913491
GenTree* operand = tree->gtGetOp1();
34923492
// The src must be a register.
3493-
if (tree->OperIs(GT_NEG) && operand->isContained())
3493+
if (tree->OperIs(GT_NEG, GT_NOT) && operand->isContained())
34943494
{
34953495
genTreeOps oper = operand->OperGet();
34963496
switch (oper)
34973497
{
34983498
case GT_MUL:
34993499
{
3500+
assert(tree->OperIs(GT_NEG));
3501+
35003502
ins = INS_mneg;
35013503
GenTree* op1 = tree->gtGetOp1();
35023504
GenTree* a = op1->gtGetOp1();
@@ -3510,7 +3512,7 @@ void CodeGen::genCodeForNegNot(GenTree* tree)
35103512
case GT_RSH:
35113513
case GT_RSZ:
35123514
{
3513-
assert(ins == INS_neg || ins == INS_negs);
3515+
assert(ins == INS_neg || ins == INS_negs || ins == INS_mvn);
35143516
assert(operand->gtGetOp2()->IsCnsIntOrI());
35153517
assert(operand->gtGetOp2()->isContained());
35163518

src/coreclr/jit/lower.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,11 @@ GenTree* Lowering::LowerNode(GenTree* node)
511511
}
512512
#endif
513513
break;
514+
case GT_NOT:
515+
#ifdef TARGET_ARM64
516+
ContainCheckNot(node->AsOp());
517+
#endif
518+
break;
514519
case GT_SELECT:
515520
return LowerSelect(node->AsConditional());
516521

src/coreclr/jit/lower.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ class Lowering final : public Phase
9494
insCflags TruthifyingFlags(GenCondition cond);
9595
void ContainCheckConditionalCompare(GenTreeCCMP* ccmp);
9696
void ContainCheckNeg(GenTreeOp* neg);
97+
void ContainCheckNot(GenTreeOp* notOp);
9798
void TryLowerCnsIntCselToCinc(GenTreeOp* select, GenTree* cond);
9899
void TryLowerCselToCSOp(GenTreeOp* select, GenTree* cond);
99100
bool TryLowerAddSubToMulLongOp(GenTreeOp* op, GenTree** next);

src/coreclr/jit/lowerarmarch.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ bool Lowering::IsContainableUnaryOrBinaryOp(GenTree* parentNode, GenTree* childN
304304
}
305305
}
306306

307-
if (childNode->OperIs(GT_LSH, GT_RSH, GT_RSZ) && parentNode->OperIs(GT_AND_NOT))
307+
if (childNode->OperIs(GT_LSH, GT_RSH, GT_RSZ) && parentNode->OperIs(GT_NOT, GT_AND_NOT))
308308
{
309309
return true;
310310
}
@@ -3290,6 +3290,31 @@ void Lowering::ContainCheckNeg(GenTreeOp* neg)
32903290
}
32913291
}
32923292

3293+
//------------------------------------------------------------------------
3294+
// ContainCheckNot : determine whether the source of a not should be contained.
3295+
//
3296+
// Arguments:
3297+
// notOp - pointer to the node
3298+
//
3299+
void Lowering::ContainCheckNot(GenTreeOp* notOp)
3300+
{
3301+
if (notOp->isContained())
3302+
return;
3303+
3304+
if (!varTypeIsIntegral(notOp))
3305+
return;
3306+
3307+
if ((notOp->gtFlags & GTF_SET_FLAGS))
3308+
return;
3309+
3310+
GenTree* childNode = notOp->gtGetOp1();
3311+
if (comp->opts.OptimizationEnabled() && childNode->OperIs(GT_LSH, GT_RSH, GT_RSZ) &&
3312+
IsContainableUnaryOrBinaryOp(notOp, childNode))
3313+
{
3314+
MakeSrcContained(notOp, childNode);
3315+
}
3316+
}
3317+
32933318
//----------------------------------------------------------------------------------------------
32943319
// TryLowerCselToCSOp: Try converting SELECT/SELECTCC to SELECT_?/SELECT_?CC. Conversion is possible only if
32953320
// one of the operands of the select node is one of GT_NEG, GT_NOT or GT_ADD.
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Runtime.CompilerServices;
6+
using Xunit;
7+
8+
namespace TestMvn
9+
{
10+
public class Program
11+
{
12+
[MethodImpl(MethodImplOptions.NoInlining)]
13+
[Fact]
14+
public static int CheckMvn()
15+
{
16+
bool fail = false;
17+
18+
if (Mvn(5) != 0xFFFFFFFA)
19+
{
20+
fail = true;
21+
}
22+
23+
if (MvnLSL(10) != 0xFFFAFFFF)
24+
{
25+
fail = true;
26+
}
27+
28+
if (MvnLSR(0x76543210) != 0xFFFFFF89)
29+
{
30+
fail = true;
31+
}
32+
33+
if (MvnASR(0xACE1234) != -0x5670A)
34+
{
35+
fail = true;
36+
}
37+
38+
if (MvnLargeShift(0x1A1A) != 0x5FFFFFFf)
39+
{
40+
fail = true;
41+
}
42+
43+
if (MvnLargeShift64Bit(0x2B3C2B3C2B3C2B3C) != 0xFFFFFFFFD4C3D4C3)
44+
{
45+
fail = true;
46+
}
47+
48+
if (fail)
49+
{
50+
return 101;
51+
}
52+
return 100;
53+
}
54+
55+
[MethodImpl(MethodImplOptions.NoInlining)]
56+
static uint Mvn(uint a)
57+
{
58+
//ARM64-FULL-LINE: mvn {{w[0-9]+}}, {{w[0-9]+}}
59+
return ~a;
60+
}
61+
62+
[MethodImpl(MethodImplOptions.NoInlining)]
63+
static uint MvnLSL(uint a)
64+
{
65+
//ARM64-FULL-LINE: mvn {{w[0-9]+}}, {{w[0-9]+}}, LSL #15
66+
return ~(a<<15);
67+
}
68+
69+
[MethodImpl(MethodImplOptions.NoInlining)]
70+
static uint MvnLSR(uint a)
71+
{
72+
//ARM64-FULL-LINE: mvn {{w[0-9]+}}, {{w[0-9]+}}, LSR #24
73+
return ~(a>>24);
74+
}
75+
76+
[MethodImpl(MethodImplOptions.NoInlining)]
77+
static int MvnASR(int a)
78+
{
79+
//ARM64-FULL-LINE: mvn {{w[0-9]+}}, {{w[0-9]+}}, ASR #9
80+
return ~(a>>9);
81+
}
82+
83+
[MethodImpl(MethodImplOptions.NoInlining)]
84+
static uint MvnLargeShift(uint a)
85+
{
86+
//ARM64-FULL-LINE: mvn {{w[0-9]+}}, {{w[0-9]+}}, LSL #28
87+
return ~(a<<60);
88+
}
89+
90+
[MethodImpl(MethodImplOptions.NoInlining)]
91+
static ulong MvnLargeShift64Bit(ulong a)
92+
{
93+
//ARM64-FULL-LINE: mvn {{x[0-9]+}}, {{x[0-9]+}}, LSR #32
94+
return ~(a>>160);
95+
}
96+
}
97+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<!-- Needed for CLRTestEnvironmentVariable -->
4+
<RequiresProcessIsolation>true</RequiresProcessIsolation>
5+
</PropertyGroup>
6+
<PropertyGroup>
7+
<DebugType>None</DebugType>
8+
<Optimize>True</Optimize>
9+
</PropertyGroup>
10+
<ItemGroup>
11+
<Compile Include="Mvn.cs">
12+
<HasDisasmCheck>true</HasDisasmCheck>
13+
</Compile>
14+
<CLRTestEnvironmentVariable Include="DOTNET_TieredCompilation" Value="0" />
15+
<CLRTestEnvironmentVariable Include="DOTNET_JITMinOpts" Value="0" />
16+
</ItemGroup>
17+
</Project>

0 commit comments

Comments
 (0)