Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,8 @@ class LclVarDsc
unsigned char lvIsOSRLocal : 1; // Root method local in an OSR method. Any stack home will be on the Tier0 frame.
// Initial value will be defined by Tier0. Requires special handing in prolog.

unsigned char lvIsOSRExposedLocal : 1; // OSR local that was address exposed in Tier0

private:
unsigned char lvIsNeverNegative : 1; // The local is known to be never negative

Expand Down Expand Up @@ -1099,14 +1101,16 @@ class LclVarDsc
{
return varTypeIsSmall(TypeGet()) &&
// lvIsStructField is treated the same as the aliased local, see fgDoNormalizeOnStore.
(lvIsParam || m_addrExposed || lvIsStructField);
// OSR exposed locals were normalize on load in the Tier0 frame so must be so for OSR too.
(lvIsParam || m_addrExposed || lvIsStructField || lvIsOSRExposedLocal);
}

bool lvNormalizeOnStore() const
{
return varTypeIsSmall(TypeGet()) &&
// lvIsStructField is treated the same as the aliased local, see fgDoNormalizeOnStore.
!(lvIsParam || m_addrExposed || lvIsStructField);
// OSR exposed locals were normalize on load in the Tier0 frame so must be so for OSR too.
!(lvIsParam || m_addrExposed || lvIsStructField || lvIsOSRExposedLocal);
}

void incRefCnts(weight_t weight, Compiler* pComp, RefCountState state = RCS_NORMAL, bool propagate = true);
Expand Down
23 changes: 15 additions & 8 deletions src/coreclr/jit/lclvars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,12 @@ void Compiler::lvaInitTypeRef()
{
LclVarDsc* const varDsc = lvaGetDesc(lclNum);
varDsc->lvIsOSRLocal = true;

if (info.compPatchpointInfo->IsExposed(lclNum))
{
JITDUMP("-- V%02u is OSR exposed\n", lclNum);
varDsc->lvIsOSRExposedLocal = true;
}
}
}

Expand Down Expand Up @@ -2435,14 +2441,15 @@ void Compiler::StructPromotionHelper::PromoteStructVar(unsigned lclNum)
// refresh the cached varDsc for lclNum.
varDsc = compiler->lvaGetDesc(lclNum);

LclVarDsc* fieldVarDsc = compiler->lvaGetDesc(varNum);
fieldVarDsc->lvType = pFieldInfo->fldType;
fieldVarDsc->lvIsStructField = true;
fieldVarDsc->lvFldOffset = pFieldInfo->fldOffset;
fieldVarDsc->lvFldOrdinal = pFieldInfo->fldOrdinal;
fieldVarDsc->lvParentLcl = lclNum;
fieldVarDsc->lvIsParam = varDsc->lvIsParam;
fieldVarDsc->lvIsOSRLocal = varDsc->lvIsOSRLocal;
LclVarDsc* fieldVarDsc = compiler->lvaGetDesc(varNum);
fieldVarDsc->lvType = pFieldInfo->fldType;
fieldVarDsc->lvIsStructField = true;
fieldVarDsc->lvFldOffset = pFieldInfo->fldOffset;
fieldVarDsc->lvFldOrdinal = pFieldInfo->fldOrdinal;
fieldVarDsc->lvParentLcl = lclNum;
fieldVarDsc->lvIsParam = varDsc->lvIsParam;
fieldVarDsc->lvIsOSRLocal = varDsc->lvIsOSRLocal;
fieldVarDsc->lvIsOSRExposedLocal = varDsc->lvIsOSRExposedLocal;

// This new local may be the first time we've seen a long typed local.
if (fieldVarDsc->lvType == TYP_LONG)
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15069,7 +15069,8 @@ PhaseStatus Compiler::fgRetypeImplicitByRefArgs()
if (fieldVarDsc->lvIsOSRLocal)
{
assert(opts.IsOSR());
fieldVarDsc->lvIsOSRLocal = false;
fieldVarDsc->lvIsOSRLocal = false;
fieldVarDsc->lvIsOSRExposedLocal = false;
}
}

Expand Down
52 changes: 52 additions & 0 deletions src/tests/JIT/opt/OSR/normalizeonload.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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;

// Ensure small OSR locals are marked as normalize on load

class Runtime_83959
{
static bool B(out byte b)
{
b = 1;
return true;
}

[MethodImpl(MethodImplOptions.NoInlining)]
static void F() {}

[MethodImpl(MethodImplOptions.NoInlining)]
[SkipLocalsInit]
static void WithOSR(int n, out char c)
{
c = (char) 0;
B(out byte b);
for (int i = 0; i < n; i++)
{
F();
}
// This load of `b` must be a single byte
c = (char) b;
c += (char) 99;
}

// Ensure stack is filled with nonzero data
static void FillStack(int n)
{
Span<int> s = stackalloc int[n];
for (int i = 0; i < n; i++)
{
s[i] = -1;
}
}

public static int Main()
{
char c = (char) 0;
FillStack(100);
WithOSR(50000, out c);
return (int) c;
}
}
15 changes: 15 additions & 0 deletions src/tests/JIT/opt/OSR/normalizeonload.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<DebugType />
<Optimize>True</Optimize>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />

<CLRTestEnvironmentVariable Include="DOTNET_TieredCompilation" Value="1" />
<CLRTestEnvironmentVariable Include="DOTNET_TC_QuickJitForLoops" Value="1" />
<CLRTestEnvironmentVariable Include="DOTNET_TC_OnStackReplacement" Value="1" />
</ItemGroup>
</Project>