Skip to content

Commit 600902d

Browse files
authored
JIT: handle boundary cases for casts of long shifts (dotnet#15294)
* JIT: handle boundary cases for casts of long shifts Remove the assert that the shift count is non-negative. Don't try and optimize if the shift count is >= 64 or < 0. Update test case to cover these values. Updates the fix from dotnet#15236. Closes #15291.
1 parent 54e7662 commit 600902d

File tree

4 files changed

+342
-5
lines changed

4 files changed

+342
-5
lines changed

src/jit/morph.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -493,20 +493,31 @@ GenTreePtr Compiler::fgMorphCast(GenTreePtr tree)
493493
if (shiftAmount->IsIntegralConst())
494494
{
495495
const ssize_t shiftAmountValue = shiftAmount->AsIntCon()->IconValue();
496-
assert(shiftAmountValue >= 0);
497496

498-
if (shiftAmountValue >= 32)
497+
if (shiftAmountValue >= 64)
498+
{
499+
// Shift amount is large enough that result is undefined.
500+
// Don't try and optimize.
501+
assert(!canPushCast);
502+
}
503+
else if (shiftAmountValue >= 32)
499504
{
500505
// Result of the shift is zero.
501506
DEBUG_DESTROY_NODE(tree);
502507
GenTree* zero = gtNewZeroConNode(TYP_INT);
503508
return fgMorphTree(zero);
504509
}
505-
else
510+
else if (shiftAmountValue >= 0)
506511
{
507512
// Shift amount is small enough that we can push the cast through.
508513
canPushCast = true;
509514
}
515+
else
516+
{
517+
// Shift amount is negative and so result is undefined.
518+
// Don't try and optimize.
519+
assert(!canPushCast);
520+
}
510521
}
511522
else
512523
{

tests/src/JIT/Regression/JitBlue/GitHub_15077/GitHub_15077.cs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,27 @@ public static UInt32 G31()
2525
return (UInt32)((1UL << q) - 1);
2626
}
2727

28+
[MethodImpl(MethodImplOptions.NoInlining)]
29+
public static UInt32 G64()
30+
{
31+
int q = 64;
32+
return (UInt32)((1UL << q) - 1);
33+
}
34+
35+
[MethodImpl(MethodImplOptions.NoInlining)]
36+
public static UInt32 G63()
37+
{
38+
int q = 63;
39+
return (UInt32)((1UL << q) - 1);
40+
}
41+
42+
[MethodImpl(MethodImplOptions.NoInlining)]
43+
public static UInt32 GM1()
44+
{
45+
int q = -1;
46+
return (UInt32)((1UL << q) - 1);
47+
}
48+
2849
[MethodImpl(MethodImplOptions.NoInlining)]
2950
public static UInt32 Gx(int q)
3051
{
@@ -33,11 +54,30 @@ public static UInt32 Gx(int q)
3354

3455
public static int Main()
3556
{
57+
UInt32 r64 = G64();
58+
UInt32 r63 = G63();
3659
UInt32 r32 = G32();
3760
UInt32 r31 = G31();
61+
UInt32 rm1 = GM1();
62+
63+
UInt32 r64a = Gx(64);
64+
UInt32 r63a = Gx(63);
3865
UInt32 r32a = Gx(32);
3966
UInt32 r31a = Gx(31);
40-
Console.WriteLine($"r32:{r32,0:X} r31:{r31,0:X} r32a:{r32a,0:X} r31a:{r31a,0:X}");
41-
return (r32 == 0xFFFFFFFF) && (r32a == 0xFFFFFFFF) && (r31 == 0x7FFFFFFF) && (r31a == 0x7FFFFFFF) ? 100 : 0;
67+
UInt32 rm1a = Gx(-1);
68+
69+
Console.WriteLine($"r64:{r64,0:X8} r64a:{r64a,0:X8}");
70+
Console.WriteLine($"r63:{r63,0:X8} r63a:{r63a,0:X8}");
71+
Console.WriteLine($"r32:{r32,0:X8} r32a:{r32a,0:X8}");
72+
Console.WriteLine($"r31:{r31,0:X8} r31a:{r31a,0:X8}");
73+
Console.WriteLine($"rm1:{rm1,0:X8} rm1a:{rm1a,0:X8}");
74+
75+
bool b64 = (r64 == 0x00000000) && (r64a == r64);
76+
bool b63 = (r63 == 0xFFFFFFFF) && (r63a == r63);
77+
bool b32 = (r32 == 0xFFFFFFFF) && (r32a == r32);
78+
bool b31 = (r31 == 0x7FFFFFFF) && (r31a == r31);
79+
bool bm1 = (rm1 == 0xFFFFFFFF) && (rm1a == rm1);
80+
81+
return b64 && b63 && b32 && b31 && bm1 ? 100 : 0;
4282
}
4383
}
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
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+
// See the LICENSE file in the project root for more information.
4+
5+
// Test for casts of long shifts.
6+
//
7+
// Same test cases as in GitHub_15077, but without the extra
8+
// and masking done by CSC.
9+
10+
.assembly extern mscorlib {auto}
11+
.assembly extern System.Console {auto}
12+
.assembly GitHub_15219 {}
13+
14+
.class private auto ansi beforefieldinit P
15+
extends [mscorlib]System.Object
16+
{
17+
.method public hidebysig static uint32
18+
G32() cil managed noinlining
19+
{
20+
IL_0003: ldc.i4.1
21+
IL_0004: conv.i8
22+
IL_0000: ldc.i4.s 32
23+
IL_0009: shl
24+
IL_000a: ldc.i4.1
25+
IL_000b: conv.i8
26+
IL_000c: sub
27+
IL_000d: conv.u4
28+
IL_000e: ret
29+
}
30+
31+
.method public hidebysig static uint32
32+
G31() cil managed noinlining
33+
{
34+
IL_0003: ldc.i4.1
35+
IL_0004: conv.i8
36+
IL_0000: ldc.i4.s 31
37+
IL_0009: shl
38+
IL_000a: ldc.i4.1
39+
IL_000b: conv.i8
40+
IL_000c: sub
41+
IL_000d: conv.u4
42+
IL_000e: ret
43+
}
44+
45+
.method public hidebysig static uint32
46+
G64() cil managed noinlining
47+
{
48+
IL_0003: ldc.i4.1
49+
IL_0004: conv.i8
50+
IL_0000: ldc.i4.s 64
51+
IL_0009: shl
52+
IL_000a: ldc.i4.1
53+
IL_000b: conv.i8
54+
IL_000c: sub
55+
IL_000d: conv.u4
56+
IL_000e: ret
57+
}
58+
59+
.method public hidebysig static uint32
60+
G63() cil managed noinlining
61+
{
62+
IL_0003: ldc.i4.1
63+
IL_0004: conv.i8
64+
IL_0000: ldc.i4.s 63
65+
IL_0009: shl
66+
IL_000a: ldc.i4.1
67+
IL_000b: conv.i8
68+
IL_000c: sub
69+
IL_000d: conv.u4
70+
IL_000e: ret
71+
}
72+
73+
.method public hidebysig static uint32
74+
GM1() cil managed noinlining
75+
{
76+
IL_0002: ldc.i4.1
77+
IL_0003: conv.i8
78+
IL_0000: ldc.i4.m1
79+
IL_0008: shl
80+
IL_0009: ldc.i4.1
81+
IL_000a: conv.i8
82+
IL_000b: sub
83+
IL_000c: conv.u4
84+
IL_000d: ret
85+
}
86+
87+
.method public hidebysig static uint32
88+
Gx(int32 q) cil managed noinlining
89+
{
90+
IL_0000: ldc.i4.1
91+
IL_0001: conv.i8
92+
IL_0002: ldarg.0
93+
IL_0006: shl
94+
IL_0007: ldc.i4.1
95+
IL_0008: conv.i8
96+
IL_0009: sub
97+
IL_000a: conv.u4
98+
IL_000b: ret
99+
}
100+
101+
.method public hidebysig static int32 Main() cil managed
102+
{
103+
.entrypoint
104+
.maxstack 3
105+
.locals init ([0] uint32 r64,
106+
[1] uint32 r63,
107+
[2] uint32 r32,
108+
[3] uint32 r31,
109+
[4] uint32 rm1,
110+
[5] uint32 r64a,
111+
[6] uint32 r63a,
112+
[7] uint32 r32a,
113+
[8] uint32 r31a,
114+
[9] uint32 rm1a,
115+
[10] bool b64,
116+
[11] bool b63,
117+
[12] bool b32,
118+
[13] bool b31,
119+
[14] bool bm1)
120+
IL_0000: call uint32 P::G64()
121+
IL_0005: stloc.0
122+
IL_0006: call uint32 P::G63()
123+
IL_000b: stloc.1
124+
IL_000c: call uint32 P::G32()
125+
IL_0011: stloc.2
126+
IL_0012: call uint32 P::G31()
127+
IL_0017: stloc.3
128+
IL_0018: call uint32 P::GM1()
129+
IL_001d: stloc.s rm1
130+
IL_001f: ldc.i4.s 64
131+
IL_0021: call uint32 P::Gx(int32)
132+
IL_0026: stloc.s r64a
133+
IL_0028: ldc.i4.s 63
134+
IL_002a: call uint32 P::Gx(int32)
135+
IL_002f: stloc.s r63a
136+
IL_0031: ldc.i4.s 32
137+
IL_0033: call uint32 P::Gx(int32)
138+
IL_0038: stloc.s r32a
139+
IL_003a: ldc.i4.s 31
140+
IL_003c: call uint32 P::Gx(int32)
141+
IL_0041: stloc.s r31a
142+
IL_0043: ldc.i4.m1
143+
IL_0044: call uint32 P::Gx(int32)
144+
IL_0049: stloc.s rm1a
145+
IL_004b: ldstr "r64:{0,0:X8} r64a:{1,0:X8}"
146+
IL_0050: ldloc.0
147+
IL_0051: box [System.Runtime]System.UInt32
148+
IL_0056: ldloc.s r64a
149+
IL_0058: box [System.Runtime]System.UInt32
150+
IL_005d: call string [System.Runtime]System.String::Format(string,
151+
object,
152+
object)
153+
IL_0062: call void [System.Console]System.Console::WriteLine(string)
154+
IL_0067: ldstr "r63:{0,0:X8} r63a:{1,0:X8}"
155+
IL_006c: ldloc.1
156+
IL_006d: box [System.Runtime]System.UInt32
157+
IL_0072: ldloc.s r63a
158+
IL_0074: box [System.Runtime]System.UInt32
159+
IL_0079: call string [System.Runtime]System.String::Format(string,
160+
object,
161+
object)
162+
IL_007e: call void [System.Console]System.Console::WriteLine(string)
163+
IL_0083: ldstr "r32:{0,0:X8} r32a:{1,0:X8}"
164+
IL_0088: ldloc.2
165+
IL_0089: box [System.Runtime]System.UInt32
166+
IL_008e: ldloc.s r32a
167+
IL_0090: box [System.Runtime]System.UInt32
168+
IL_0095: call string [System.Runtime]System.String::Format(string,
169+
object,
170+
object)
171+
IL_009a: call void [System.Console]System.Console::WriteLine(string)
172+
IL_009f: ldstr "r31:{0,0:X8} r31a:{1,0:X8}"
173+
IL_00a4: ldloc.3
174+
IL_00a5: box [System.Runtime]System.UInt32
175+
IL_00aa: ldloc.s r31a
176+
IL_00ac: box [System.Runtime]System.UInt32
177+
IL_00b1: call string [System.Runtime]System.String::Format(string,
178+
object,
179+
object)
180+
IL_00b6: call void [System.Console]System.Console::WriteLine(string)
181+
IL_00bb: ldstr "rm1:{0,0:X8} rm1a:{1,0:X8}"
182+
IL_00c0: ldloc.s rm1
183+
IL_00c2: box [System.Runtime]System.UInt32
184+
IL_00c7: ldloc.s rm1a
185+
IL_00c9: box [System.Runtime]System.UInt32
186+
IL_00ce: call string [System.Runtime]System.String::Format(string,
187+
object,
188+
object)
189+
IL_00d3: call void [System.Console]System.Console::WriteLine(string)
190+
IL_00d8: ldloc.0
191+
IL_00d9: brtrue.s IL_00e2
192+
193+
IL_00db: ldloc.s r64a
194+
IL_00dd: ldloc.0
195+
IL_00de: ceq
196+
IL_00e0: br.s IL_00e3
197+
198+
IL_00e2: ldc.i4.0
199+
IL_00e3: stloc.s b64
200+
IL_00e5: ldloc.1
201+
IL_00e6: ldc.i4.m1
202+
IL_00e7: bne.un.s IL_00f0
203+
204+
IL_00e9: ldloc.s r63a
205+
IL_00eb: ldloc.1
206+
IL_00ec: ceq
207+
IL_00ee: br.s IL_00f1
208+
209+
IL_00f0: ldc.i4.0
210+
IL_00f1: stloc.s b63
211+
IL_00f3: ldloc.2
212+
IL_00f4: ldc.i4.m1
213+
IL_00f5: bne.un.s IL_00fe
214+
215+
IL_00f7: ldloc.s r32a
216+
IL_00f9: ldloc.2
217+
IL_00fa: ceq
218+
IL_00fc: br.s IL_00ff
219+
220+
IL_00fe: ldc.i4.0
221+
IL_00ff: stloc.s b32
222+
IL_0101: ldloc.3
223+
IL_0102: ldc.i4 0x7fffffff
224+
IL_0107: bne.un.s IL_0110
225+
226+
IL_0109: ldloc.s r31a
227+
IL_010b: ldloc.3
228+
IL_010c: ceq
229+
IL_010e: br.s IL_0111
230+
231+
IL_0110: ldc.i4.0
232+
IL_0111: stloc.s b31
233+
IL_0113: ldloc.s rm1
234+
IL_0115: ldc.i4.m1
235+
IL_0116: bne.un.s IL_0120
236+
237+
IL_0118: ldloc.s rm1a
238+
IL_011a: ldloc.s rm1
239+
IL_011c: ceq
240+
IL_011e: br.s IL_0121
241+
242+
IL_0120: ldc.i4.0
243+
IL_0121: stloc.s bm1
244+
IL_0123: ldloc.s b64
245+
IL_0125: ldloc.s b63
246+
IL_0127: and
247+
IL_0128: ldloc.s b32
248+
IL_012a: and
249+
IL_012b: ldloc.s b31
250+
IL_012d: and
251+
IL_012e: ldloc.s bm1
252+
IL_0130: and
253+
IL_0131: brtrue.s IL_0135
254+
255+
IL_0133: ldc.i4.0
256+
IL_0134: ret
257+
258+
IL_0135: ldc.i4.s 100
259+
IL_0137: ret
260+
}
261+
262+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<AssemblyName>$(MSBuildProjectName)</AssemblyName>
8+
<ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
9+
<OutputType>Exe</OutputType>
10+
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
11+
<CLRTestPriority>1</CLRTestPriority>
12+
</PropertyGroup>
13+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
14+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "></PropertyGroup>
15+
<PropertyGroup>
16+
<DebugType>None</DebugType>
17+
<Optimize>True</Optimize>
18+
</PropertyGroup>
19+
<ItemGroup>
20+
<Compile Include="GitHub_15291.il" />
21+
</ItemGroup>
22+
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
23+
<PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
24+
</Project>

0 commit comments

Comments
 (0)