Skip to content

Commit fa1f283

Browse files
authored
Add flags checks to BMI1 intrinsic lowering (#66736)
* add flags checks to BMI1 intrinsic lowering to prevent decomposed longs in x84 from being altered * update bmji1intrinsics tests
1 parent 35be545 commit fa1f283

File tree

2 files changed

+75
-9
lines changed

2 files changed

+75
-9
lines changed

src/coreclr/jit/lowerxarch.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3789,6 +3789,13 @@ GenTree* Lowering::TryLowerAndOpToResetLowestSetBit(GenTreeOp* andNode)
37893789
return nullptr;
37903790
}
37913791

3792+
// Subsequent nodes may rely on CPU flags set by these nodes in which case we cannot remove them
3793+
if (((addOp2->gtFlags & GTF_SET_FLAGS) != 0) || ((op2->gtFlags & GTF_SET_FLAGS) != 0) ||
3794+
((andNode->gtFlags & GTF_SET_FLAGS) != 0))
3795+
{
3796+
return nullptr;
3797+
}
3798+
37923799
NamedIntrinsic intrinsic;
37933800
if (op1->TypeIs(TYP_LONG) && comp->compOpportunisticallyDependsOn(InstructionSet_BMI1_X64))
37943801
{
@@ -3868,6 +3875,12 @@ GenTree* Lowering::TryLowerAndOpToExtractLowestSetBit(GenTreeOp* andNode)
38683875
return nullptr;
38693876
}
38703877

3878+
// Subsequent nodes may rely on CPU flags set by these nodes in which case we cannot remove them
3879+
if (((opNode->gtFlags & GTF_SET_FLAGS) != 0) || ((negNode->gtFlags & GTF_SET_FLAGS) != 0))
3880+
{
3881+
return nullptr;
3882+
}
3883+
38713884
NamedIntrinsic intrinsic;
38723885
if (andNode->TypeIs(TYP_LONG) && comp->compOpportunisticallyDependsOn(InstructionSet_BMI1_X64))
38733886
{
@@ -3947,6 +3960,12 @@ GenTree* Lowering::TryLowerAndOpToAndNot(GenTreeOp* andNode)
39473960
return nullptr;
39483961
}
39493962

3963+
// Subsequent nodes may rely on CPU flags set by these nodes in which case we cannot remove them
3964+
if (((andNode->gtFlags & GTF_SET_FLAGS) != 0) || ((notNode->gtFlags & GTF_SET_FLAGS) != 0))
3965+
{
3966+
return nullptr;
3967+
}
3968+
39503969
NamedIntrinsic intrinsic;
39513970
if (andNode->TypeIs(TYP_LONG) && comp->compOpportunisticallyDependsOn(InstructionSet_BMI1_X64))
39523971
{

src/tests/JIT/Intrinsics/BMI1Intrinsics.cs

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,76 @@ static int Main(string[] args)
2525

2626
foreach (var value in values)
2727
{
28-
Test(value.input1, AndNot(value.input1, value.input2), value.andnExpected, nameof(AndNot));
29-
Test(value.input1, ExtractLowestSetIsolatedBit(value.input1), value.blsiExpected, nameof(ExtractLowestSetIsolatedBit));
30-
Test(value.input1, ResetLowestSetBit(value.input1), value.blsrExpected, nameof(ResetLowestSetBit));
31-
Test(value.input1, GetMaskUpToLowestSetBit(value.input1), value.blmskExpected, nameof(GetMaskUpToLowestSetBit));
28+
Test(value.input1, AndNot_32bit(value.input1, value.input2), value.andnExpected, nameof(AndNot_32bit));
29+
Test(value.input1, ExtractLowestSetIsolatedBit_32bit(value.input1), value.blsiExpected, nameof(ExtractLowestSetIsolatedBit_32bit));
30+
Test(value.input1, ResetLowestSetBit_32bit(value.input1), value.blsrExpected, nameof(ResetLowestSetBit_32bit));
31+
Test(value.input1, GetMaskUpToLowestSetBit_32bit(value.input1), value.blmskExpected, nameof(GetMaskUpToLowestSetBit_32bit));
32+
}
33+
34+
35+
var values2 = new (ulong input1, ulong input2, ulong andnExpected, ulong blsiExpected, ulong blsrExpected, ulong blmskExpected)[] {
36+
(0, 0, 0, 0, 0, 0),
37+
(1, 0, 1, 1, 0,0xFFFFFFFF_FFFFFFFE),
38+
(ulong.MaxValue / 2, 0,0x7FFFFFFF_FFFFFFFF, 1,0x7FFFFFFF_FFFFFFFE,0xFFFFFFFF_FFFFFFFE),
39+
((ulong.MaxValue / 2) - 1, 0,0x7FFFFFFF_FFFFFFFE, 2,0x7FFFFFFF_FFFFFFFC,0xFFFFFFFF_FFFFFFFC),
40+
((ulong.MaxValue / 2) + 1, 0,0x80000000_00000000,0x80000000_00000000, 0, 0),
41+
(ulong.MaxValue - 1, 0,0xFFFFFFFF_FFFFFFFE, 2,0xFFFFFFFF_FFFFFFFC,0xFFFFFFFF_FFFFFFFC),
42+
(ulong.MaxValue, 0,0xFFFFFFFF_FFFFFFFF, 1,0xFFFFFFFF_FFFFFFFE,0xFFFFFFFF_FFFFFFFE),
43+
(0xAAAAAAAA_AAAAAAAA,0xAAAAAAAA_AAAAAAAA, 0, 2,0xAAAAAAAA_AAAAAAA8,0xFFFFFFFF_FFFFFFFC),
44+
(0xAAAAAAAA_AAAAAAAA,0x55555555_55555555,0xAAAAAAAA_AAAAAAAA, 2,0xAAAAAAAA_AAAAAAA8,0xFFFFFFFF_FFFFFFFC),
45+
};
46+
47+
foreach (var value in values2)
48+
{
49+
Test(value.input1, AndNot_64bit(value.input1, value.input2), value.andnExpected, nameof(AndNot_64bit));
50+
Test(value.input1, ExtractLowestSetIsolatedBit_64bit(value.input1), value.blsiExpected, nameof(ExtractLowestSetIsolatedBit_64bit));
51+
Test(value.input1, ResetLowestSetBit_64bit(value.input1), value.blsrExpected, nameof(ResetLowestSetBit_64bit));
52+
Test(value.input1, GetMaskUpToLowestSetBit_64bit(value.input1), value.blmskExpected, nameof(GetMaskUpToLowestSetBit_64bit));
3253
}
3354

3455
return _errorCode;
3556
}
3657

3758
[MethodImpl(MethodImplOptions.NoInlining)]
38-
private static uint AndNot(uint x, uint y) => x & (~y); // bmi1 andn
59+
private static uint AndNot_32bit(uint x, uint y) => x & (~y); // bmi1 andn
60+
61+
[MethodImpl(MethodImplOptions.NoInlining)]
62+
private static ulong AndNot_64bit(ulong x, ulong y) => x & (~y); // bmi1 andn
63+
64+
[MethodImpl(MethodImplOptions.NoInlining)]
65+
private static uint ExtractLowestSetIsolatedBit_32bit(uint x) => (uint)(x & (-x)); // bmi1 blsi
66+
67+
[MethodImpl(MethodImplOptions.NoInlining)]
68+
private static ulong ExtractLowestSetIsolatedBit_64bit(ulong x) => x & (ulong)(-(long)x); // bmi1 blsi
69+
70+
[MethodImpl(MethodImplOptions.NoInlining)]
71+
private static uint ResetLowestSetBit_32bit(uint x) => x & (x - 1); // bmi1 blsr
3972

4073
[MethodImpl(MethodImplOptions.NoInlining)]
41-
private static uint ExtractLowestSetIsolatedBit(uint x) => (uint)(x & (-x)); // bmi1 blsi
74+
private static ulong ResetLowestSetBit_64bit(ulong x) => x & (x - 1); // bmi1 blsr
4275

4376
[MethodImpl(MethodImplOptions.NoInlining)]
44-
private static uint ResetLowestSetBit(uint x) => x & (x - 1); // bmi1 blsr
77+
private static uint GetMaskUpToLowestSetBit_32bit(uint x) => (uint)(x ^ (-x)); // bmi1 blmsk
4578

4679
[MethodImpl(MethodImplOptions.NoInlining)]
47-
private static uint GetMaskUpToLowestSetBit(uint x) => (uint)(x ^ (-x)); // bmi1 blmsk
80+
private static ulong GetMaskUpToLowestSetBit_64bit(ulong x) => x ^ (ulong)(-(long)x); // bmi1 blmsk
81+
82+
[MethodImpl(MethodImplOptions.NoInlining)]
83+
private static void Test(uint input, uint output, uint expected, string callerName)
84+
{
85+
if (output != expected)
86+
{
87+
Console.WriteLine($"{callerName} failed.");
88+
Console.WriteLine($"Input: {input:X}");
89+
Console.WriteLine($"Output: {output:X}");
90+
Console.WriteLine($"Expected: {expected:X}");
91+
92+
_errorCode++;
93+
}
94+
}
4895

4996
[MethodImpl(MethodImplOptions.NoInlining)]
50-
private static void Test(uint input, uint output, uint expected,string callerName)
97+
private static void Test(ulong input, ulong output, ulong expected, string callerName)
5198
{
5299
if (output != expected)
53100
{

0 commit comments

Comments
 (0)