Skip to content

Commit ee0b034

Browse files
Fix for 126457 (#127050)
For a bool-typed inlinee that contains a tail call, where the return is in a seperate block from the tailcall (for a single-return method, for example), the inliner inserts an int->ubyte->int normalizing cast ``` * RETURN int \--* CAST int <- ubyte <- int \--* LCL_VAR int V04 tmp3 ``` The tail-call validation in morph doesn't expect a cast there. However, a normalizing cast here may be safely ignored for tailcalls because 1 - If the calling function was not inlined, the normalizing cast is intead inserted later in morph after the tailcall transformation, and 2 - Callees are responsible for this adjustment anyway so the tailcall return value would have already been normalized fixes #126457
1 parent a6bc864 commit ee0b034

3 files changed

Lines changed: 126 additions & 0 deletions

File tree

src/coreclr/jit/morph.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5040,6 +5040,15 @@ void Compiler::fgValidateIRForTailCall(GenTreeCall* call)
50405040
{
50415041
assert(ValidateUse(tree) && "Expected use of local to be tailcall value");
50425042
}
5043+
else if (tree->OperIs(GT_CAST))
5044+
{
5045+
// The inliner can insert small-type-normalizing casts before the return
5046+
// (int -> ubyte -> int for bool-return-calls, for example)
5047+
// In the jit the callee is responsible for normalizing, so a tailcall
5048+
// can freely bypass this extra cast
5049+
assert(!m_compiler->fgCastNeeded(m_tailcall, tree->AsCast()->CastToType()) &&
5050+
ValidateUse(tree->AsCast()->CastOp()) && "Expected normalizing cast of tailcall result");
5051+
}
50435052
else if (IsCommaNop(tree))
50445053
{
50455054
// COMMA(NOP,NOP)
@@ -5065,6 +5074,11 @@ void Compiler::fgValidateIRForTailCall(GenTreeCall* call)
50655074

50665075
bool ValidateUse(GenTree* node)
50675076
{
5077+
if (node->OperIs(GT_CAST))
5078+
{
5079+
node = node->AsCast()->CastOp();
5080+
}
5081+
50685082
if (m_lclNum != BAD_VAR_NUM)
50695083
{
50705084
return node->OperIs(GT_LCL_VAR) && (node->AsLclVar()->GetLclNum() == m_lclNum);
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
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+
// In some cases the Inliner can insert a CAST node between
5+
// a tail call and the return
6+
7+
.assembly extern System.Runtime
8+
{
9+
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A)
10+
}
11+
12+
.assembly Runtime_126457 { }
13+
.module Runtime_126457.dll
14+
15+
.class interface public abstract auto ansi ISite
16+
{
17+
.method public hidebysig newslot abstract virtual
18+
instance bool tailcall() cil managed
19+
{
20+
}
21+
}
22+
23+
.class public auto ansi beforefieldinit Component
24+
extends [System.Runtime]System.Object
25+
{
26+
.field family class ISite _site
27+
28+
.method family hidebysig newslot virtual
29+
instance bool callee() cil managed
30+
{
31+
.maxstack 8
32+
ldarg.0
33+
ldfld class ISite Component::_site
34+
dup
35+
brtrue.s CALL
36+
pop
37+
ldc.i4.0
38+
br.s DONE
39+
CALL:
40+
callvirt instance bool ISite::tailcall()
41+
DONE:
42+
ret
43+
}
44+
45+
.method public hidebysig specialname rtspecialname
46+
instance void .ctor() cil managed
47+
{
48+
ldarg.0
49+
call instance void [System.Runtime]System.Object::.ctor()
50+
ret
51+
}
52+
}
53+
54+
.class public auto ansi beforefieldinit DerivedComponent
55+
extends Component
56+
{
57+
.method public hidebysig virtual
58+
instance bool caller() cil managed
59+
{
60+
.maxstack 8
61+
ldarg.0
62+
call instance bool Component::callee()
63+
ret
64+
}
65+
66+
.method public hidebysig specialname rtspecialname
67+
instance void .ctor() cil managed
68+
{
69+
ldarg.0
70+
call instance void Component::.ctor()
71+
ret
72+
}
73+
}
74+
75+
.class private auto ansi beforefieldinit Program
76+
extends [System.Runtime]System.Object
77+
{
78+
.method private hidebysig static int32
79+
Main() cil managed
80+
{
81+
.entrypoint
82+
.maxstack 1
83+
newobj instance void DerivedComponent::.ctor()
84+
call bool Program::Test(class DerivedComponent)
85+
pop
86+
ldc.i4.s 100
87+
ret
88+
}
89+
90+
.method private hidebysig static bool
91+
Test(class DerivedComponent c) cil managed noinlining
92+
{
93+
.maxstack 8
94+
ldarg.0
95+
callvirt instance bool DerivedComponent::caller()
96+
ret
97+
}
98+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk.IL">
2+
<PropertyGroup>
3+
<RequiresProcessIsolation>true</RequiresProcessIsolation>
4+
</PropertyGroup>
5+
<PropertyGroup>
6+
<DebugType>None</DebugType>
7+
<Optimize>True</Optimize>
8+
</PropertyGroup>
9+
<ItemGroup>
10+
<Compile Include="$(MSBuildProjectName).il" />
11+
12+
<CLRTestEnvironmentVariable Include="DOTNET_TieredCompilation" Value="0" />
13+
</ItemGroup>
14+
</Project>

0 commit comments

Comments
 (0)