Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

windows/x64: Assertion failed 'unreached' during 'Physical promotion' #110326

Closed
kunalspathak opened this issue Dec 2, 2024 · 13 comments · Fixed by #110485
Closed

windows/x64: Assertion failed 'unreached' during 'Physical promotion' #110326

kunalspathak opened this issue Dec 2, 2024 · 13 comments · Fixed by #110485
Assignees
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI in-pr There is an active PR which will close this issue when it is merged
Milestone

Comments

@kunalspathak
Copy link
Member

// Found by Antigen
// Reduced from 37.21 KB to 3.82 KB.


using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;
using System.Runtime.Intrinsics.X86;
using System.Numerics;
public class TestClass
{
    public struct S1
    {
        public Vector<double> v_double_0;
    }
    public struct S2
    {
        public struct S2_D1_F2
        {
            public struct S2_D2_F1
            {
            }
            public struct S2_D2_F2
            {
                public S1 s1_7;
            }
            public struct S2_D2_F3
            {
                public Vector3 v3_10;
            }
        }
        public struct S2_D1_F3
        {
            public struct S2_D2_F3
            {
                public Vector256<int> v256_int_14;
            }
            public Vector128<long> v128_long_13;
            public Vector512<uint> v512_uint_16;
        }
    }
    public struct S3
    {
    }
    public struct S4
    {
        public struct S4_D1_F1
        {
            public struct S4_D2_F3
            {
            }
            public S2.S2_D1_F3 s2_s2_d1_f3_19;
        }
    }
    public struct S5
    {
    }
    static Vector512<uint> s_v512_uint_63 = Vector512.CreateScalar((uint)5);
    S4.S4_D1_F1 s4_s4_d1_f1_162 = new S4.S4_D1_F1();
    private static List<string> toPrint = new List<string>();
    public void Method0()
    {
        unchecked
        {
            double double_248 = -1.9610389610389611;
            short short_249 = 2;
            string string_254 = "QM2DZ5IX";
            ushort ushort_255 = 2;
            ulong ulong_257 = 5;
            S1 s1_259 = new S1();
            S2.S2_D1_F2.S2_D2_F1 s2_s2_d1_f2_s2_d2_f1_260 = new S2.S2_D1_F2.S2_D2_F1();
            S2.S2_D1_F2.S2_D2_F1 s2_s2_d1_f2_s2_d2_f1_261 = s2_s2_d1_f2_s2_d2_f1_260;
            S2.S2_D1_F2.S2_D2_F2 s2_s2_d1_f2_s2_d2_f2_262 = new S2.S2_D1_F2.S2_D2_F2();
            S2.S2_D1_F2.S2_D2_F2 s2_s2_d1_f2_s2_d2_f2_263 = s2_s2_d1_f2_s2_d2_f2_262;
            S2.S2_D1_F2.S2_D2_F3 s2_s2_d1_f2_s2_d2_f3_264 = new S2.S2_D1_F2.S2_D2_F3();
            S2.S2_D1_F2.S2_D2_F3 s2_s2_d1_f2_s2_d2_f3_265 = s2_s2_d1_f2_s2_d2_f3_264;
            S2.S2_D1_F2 s2_s2_d1_f2_266 = new S2.S2_D1_F2();
            S2.S2_D1_F3.S2_D2_F3 s2_s2_d1_f3_s2_d2_f3_268 = new S2.S2_D1_F3.S2_D2_F3();
            S2.S2_D1_F3 s2_s2_d1_f3_269 = new S2.S2_D1_F3();
            S2.S2_D1_F3 s2_s2_d1_f3_270 = s2_s2_d1_f3_269;
            S4.S4_D1_F1 s4_s4_d1_f1_276 = new S4.S4_D1_F1();
            s2_s2_d1_f3_270.v512_uint_16 = Vector512.IsZero(s_v512_uint_63 = s4_s4_d1_f1_162.s2_s2_d1_f3_19.v512_uint_16 * s4_s4_d1_f1_276.s2_s2_d1_f3_19.v512_uint_16);
            Log("double_248", double_248);
            Log("short_249", short_249);
            Log("string_254", string_254);
            Log("ushort_255", ushort_255);
            Log("ulong_257", ulong_257);
            Log("s1_259", s1_259);
            Log("s2_s2_d1_f", s2_s2_d1_f2_s2_d2_f2_262.s1_7.v_double_0);
            Log("s2_s2_d1_f", s2_s2_d1_f2_s2_d2_f2_263.s1_7.v_double_0);
            Log("s2_s2_d1_f", s2_s2_d1_f2_s2_d2_f1_260);
            Log("s2_s2_d1_f", s2_s2_d1_f2_s2_d2_f1_261);
            Log("s2_s2_d1_f", s2_s2_d1_f2_s2_d2_f3_264);
            Log("s2_s2_d1_f", s2_s2_d1_f2_s2_d2_f3_265.v3_10);
            Log("s2_s2_d1_f", s2_s2_d1_f2_266);
            Log("s2_s2_d1_f", s2_s2_d1_f3_s2_d2_f3_268.v256_int_14);
            Log("s2_s2_d1_f", s2_s2_d1_f3_269.v128_long_13);
            Log("s2_s2_d1_f", s2_s2_d1_f3_270.v128_long_13);
            return;
        }
    }
    public static void Main(string[] args)
{}
    public static int Antigen()
    {
        new TestClass().Method0();
        return string.Join(Environment.NewLine, toPrint).GetHashCode();
    }
    [MethodImpl(MethodImplOptions.NoInlining)]
    public static void Log(string varName, object varValue)
    {
    }
}
/*
Environment:

set DOTNET_JitProfileCasts=1
set DOTNET_JitAggressiveInlining=0
set DOTNET_HeapVerify=1
set DOTNET_TieredCompilation=0
set DOTNET_PreferredVectorBitWidth=512
set DOTNET_JitStress=2
set DOTNET_JitThrowOnAssertionFailure=1
set DOTNET_LegacyExceptionHandling=1

Debug: -899992286

Release: 0
JIT assert failed:
Assertion failed 'unreached' in 'TestClass:Method0():this' during 'Physical promotion' (IL size 459; hash 0x46e9aa75; FullOpts)

    File: D:\a\_work\1\s\src\coreclr\jit\gentree.cpp Line: 8260


*/
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Dec 2, 2024
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Dec 2, 2024
@kunalspathak
Copy link
Member Author

@dotnet/jit-contrib

Copy link
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

@amanasifkhalid
Copy link
Member

I'm not able to repro this failure locally, though I suspect all these unreached() asserts from the last Antigen run were introduced by #110195, and might be fixed by #110307. I'll kick off a new run to check.

@amanasifkhalid
Copy link
Member

A similar unreached() assertion hit in the latest Antigen run, so looks like #110307 didn't fix it. cc @tannergooding

@tannergooding
Copy link
Member

Simplified repro is:

sing System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;

public class TestClass
{
    public struct S1
    {
        public bool bool_2;
        public Vector512<short> v512_short_3;
        public Vector512<float> v512_float_4;
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    public static ulong Method1()
    {
        S1 s1_s1_d1_f3_160 = new S1();
        return Vector512.ExtractMostSignificantBits(s1_s1_d1_f3_160.v512_short_3);
    }
    public static void Main(string[] args)
    {
        TestClass.Method1();
    }
}

@jakobbotsch the tree shape we have is roughly:

STMT00000 ( 0x000[E-] ... 0x003 )
               [000002] DA---------                         *  STORE_LCL_VAR struct<TestClass+S1, 192>(P) V00 loc0         
                                                            *    ubyte  field V00.bool_2 (fldOffset=0x0) -> V02 tmp1         
                                                            *    simd64 field V00.v512_short_3 (fldOffset=0x40) -> V03 tmp2         
                                                            *    simd64 field V00.v512_float_4 (fldOffset=0x80) -> V04 tmp3         
               [000001] -----------                         \--*  CNS_INT   int    0

***** BB01 [0000]
STMT00001 ( 0x008[E-] ... 0x013 )
               [000009] -----------                         *  RETURN    long  
               [000008] -----------                         \--*  HWINTRINSIC long   short MoveMask
               [000007] -----------                            \--*  HWINTRINSIC mask   short ConvertVectorToMask
               [000006] -----------                               \--*  LCL_VAR   simd64 V03 tmp2         

My guess is that it isn't "safe" for us to be retyping the promoted field that exists as LCL_VAR: V03 tmp2 and we need to have an additional filter that excludes such local variables, is that correct?

-- The failure here is because TYP_MASK isn't handled in gtNewConWithPattern, which is specifically used by TryInitFiledByField.

@jakobbotsch
Copy link
Member

My guess is that it isn't "safe" for us to be retyping the promoted field that exists as LCL_VAR: V03 tmp2 and we need to have an additional filter that excludes such local variables, is that correct?

Right, the optimization needs to skip promoted fields (lvIsStructField) because of the possibility of dependent promotion.

The original assertion failure seems to be during physical promotion, though, and old promotion should not be involved there. Can you share a jitdump or SPMI collection? Curious to see what physical promotion is seeing.

@tannergooding
Copy link
Member

tannergooding commented Dec 4, 2024

Here is the dump:
out.txt

The repro is just the simplified repro above (#110326 (comment)) being run with DOTNET_TieredCompilation=0 (on a machine with AVX512, which can be tested under AltJit)

@jakobbotsch
Copy link
Member

Here is the dump:
out.txt

This dump seems to make it past physical promotion, into morph, so it's not quite the same failure mode as the assert from the OP.

The repro is just the simplified repro above (#110326 (comment)) being run with DOTNET_TieredCompilation=0 (on a machine with AVX512, which can be tested under AltJit)

When I try the original repro with AltJit, after adding a call to Antigen() in Main, I hit this assert instead:

Assert failure(PID 60440 [0x0000ec18], Thread: 26892 [0x690c]): Assertion failed 'size == info.compCompHnd->getClassSize(typeHnd)' in 'TestClass:Method0():this' during 'Importation' (IL size 459; hash 0x46e9aa75; FullOpts)

    File: C:\dev\dotnet\runtime\src\coreclr\jit\simd.cpp:466
    Image: C:\dev\dotnet\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\corerun.exe

@tannergooding
Copy link
Member

When I try the original repro with AltJit, after adding a call to Antigen() in Main, I hit this assert instead:

I'll try and take a look at this and see if I can root cause it as well. I missed that Main wasn't actually calling the function, which would be why I couldn't get a repro...

@jakobbotsch
Copy link
Member

I have a guess as to what might be happening -- if you have assignments between physically promoted structs and regularly/old promoted structs, then physical promotion will sometimes promote fields based on that assignment.
So that might cause physical promotion to promote something as TYP_MASK in this case. Disqualifying the TYP_MASK retyping for old promotion should fix it in that case too.

@kunalspathak
Copy link
Member Author

I hit this assert instead:

can you retry with DOTNET_MaxVectorTBitWidth=128?

@tannergooding
Copy link
Member

The original repro fails in the same place, with the following callstack:

 	KernelBase.dll!wil::details::DebugBreak(void)	Unknown
 	clrjit.dll!assertAbort(const char * why, const char * file, unsigned int line) Line 288	C++
 	clrjit.dll!noWayAssertAbortHelper(const char * cond, const char * file, unsigned int line) Line 495	C++
 	clrjit.dll!noWayAssertBody(const char * cond, const char * file, unsigned int line) Line 519	C++
 	clrjit.dll!Compiler::gtNewConWithPattern(var_types type, unsigned char pattern) Line 8260	C++
 	clrjit.dll!DecompositionPlan::FinalizeInit(DecompositionStatementList * statements) Line 412	C++
 	clrjit.dll!DecompositionPlan::Finalize(DecompositionStatementList * statements) Line 166	C++
>	clrjit.dll!ReplaceVisitor::HandleStructStore(GenTree * * use, GenTree * user) Line 1405	C++
 	clrjit.dll!ReplaceVisitor::PostOrderVisit(GenTree * * use, GenTree * user) Line 1780	C++
 	clrjit.dll!GenTreeVisitor<ReplaceVisitor>::WalkTree(GenTree * * use, GenTree * user) Line 12116	C++
 	clrjit.dll!Promotion::Run() Line 2810	C++
 	clrjit.dll!Compiler::PhysicalPromotion() Line 43	C++
 	clrjit.dll!CompilerPhaseWithStatus::DoPhase() Line 132	C++
 	clrjit.dll!Phase::Run() Line 61	C++

JitStress=2 and TieredCompilation=0 are required; with changing Main to call Antigen, a simplified repro is below and the JIT dump is out.txt:

using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Numerics;
public class TestClass
{
    public struct S2_D1_F2
    {
        public struct S2_D2_F2
        {
            public Vector<double> v_double_0;
        }
        public struct S2_D2_F3
        {
            public Vector3 v3_10;
        }
    }
    public struct S2_D1_F3
    {
        public struct S2_D2_F3
        {
            public Vector256<int> v256_int_14;
        }
        public Vector128<long> v128_long_13;
        public Vector512<uint> v512_uint_16;
    }
    public void Method0()
    {
        unchecked
        {
            S2_D1_F2.S2_D2_F2 s2_s2_d1_f2_s2_d2_f2_262 = new S2_D1_F2.S2_D2_F2();
            S2_D1_F2.S2_D2_F2 s2_s2_d1_f2_s2_d2_f2_263 = s2_s2_d1_f2_s2_d2_f2_262;
            S2_D1_F2.S2_D2_F3 s2_s2_d1_f2_s2_d2_f3_264 = new S2_D1_F2.S2_D2_F3();
            S2_D1_F2.S2_D2_F3 s2_s2_d1_f2_s2_d2_f3_265 = s2_s2_d1_f2_s2_d2_f3_264;
            S2_D1_F2 s2_s2_d1_f2_266 = new S2_D1_F2();
            S2_D1_F3.S2_D2_F3 s2_s2_d1_f3_s2_d2_f3_268 = new S2_D1_F3.S2_D2_F3();
            S2_D1_F3 s2_s2_d1_f3_269 = new S2_D1_F3();
            S2_D1_F3 s2_s2_d1_f3_270 = s2_s2_d1_f3_269;
            s2_s2_d1_f3_270.v512_uint_16 = Vector512.IsZero(Vector512<uint>.AllBitsSet);
            Log("s2_s2_d1_f", s2_s2_d1_f2_s2_d2_f2_262.v_double_0);
            Log("s2_s2_d1_f", s2_s2_d1_f2_s2_d2_f2_263.v_double_0);
            Log("s2_s2_d1_f", s2_s2_d1_f2_s2_d2_f3_264);
            Log("s2_s2_d1_f", s2_s2_d1_f2_s2_d2_f3_265.v3_10);
            Log("s2_s2_d1_f", s2_s2_d1_f2_266);
            Log("s2_s2_d1_f", s2_s2_d1_f3_s2_d2_f3_268.v256_int_14);
            Log("s2_s2_d1_f", s2_s2_d1_f3_269.v128_long_13);
            Log("s2_s2_d1_f", s2_s2_d1_f3_270.v128_long_13);
            return;
        }
    }
    public static void Main(string[] args)
    {
        new TestClass().Method0();
    }
    [MethodImpl(MethodImplOptions.NoInlining)]
    public static void Log(string varName, object varValue)
    {
    }
}

CC. @jakobbotsch -- I know where/how to disable the promoted field support from the new mask optimization, but I'm not quite sure the best place to disable TYP_MASK for old promotion, any pointer here would be appreciated

@jakobbotsch
Copy link
Member

The original repro fails in the same place, with the following callstack:

 	KernelBase.dll!wil::details::DebugBreak(void)	Unknown
 	clrjit.dll!assertAbort(const char * why, const char * file, unsigned int line) Line 288	C++
 	clrjit.dll!noWayAssertAbortHelper(const char * cond, const char * file, unsigned int line) Line 495	C++
 	clrjit.dll!noWayAssertBody(const char * cond, const char * file, unsigned int line) Line 519	C++
 	clrjit.dll!Compiler::gtNewConWithPattern(var_types type, unsigned char pattern) Line 8260	C++
 	clrjit.dll!DecompositionPlan::FinalizeInit(DecompositionStatementList * statements) Line 412	C++
 	clrjit.dll!DecompositionPlan::Finalize(DecompositionStatementList * statements) Line 166	C++
>	clrjit.dll!ReplaceVisitor::HandleStructStore(GenTree * * use, GenTree * user) Line 1405	C++
 	clrjit.dll!ReplaceVisitor::PostOrderVisit(GenTree * * use, GenTree * user) Line 1780	C++
 	clrjit.dll!GenTreeVisitor<ReplaceVisitor>::WalkTree(GenTree * * use, GenTree * user) Line 12116	C++
 	clrjit.dll!Promotion::Run() Line 2810	C++
 	clrjit.dll!Compiler::PhysicalPromotion() Line 43	C++
 	clrjit.dll!CompilerPhaseWithStatus::DoPhase() Line 132	C++
 	clrjit.dll!Phase::Run() Line 61	C++

JitStress=2 and TieredCompilation=0 are required; with changing Main to call Antigen, a simplified repro is below and the JIT dump is out.txt:

using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Numerics;
public class TestClass
{
public struct S2_D1_F2
{
public struct S2_D2_F2
{
public Vector v_double_0;
}
public struct S2_D2_F3
{
public Vector3 v3_10;
}
}
public struct S2_D1_F3
{
public struct S2_D2_F3
{
public Vector256 v256_int_14;
}
public Vector128 v128_long_13;
public Vector512 v512_uint_16;
}
public void Method0()
{
unchecked
{
S2_D1_F2.S2_D2_F2 s2_s2_d1_f2_s2_d2_f2_262 = new S2_D1_F2.S2_D2_F2();
S2_D1_F2.S2_D2_F2 s2_s2_d1_f2_s2_d2_f2_263 = s2_s2_d1_f2_s2_d2_f2_262;
S2_D1_F2.S2_D2_F3 s2_s2_d1_f2_s2_d2_f3_264 = new S2_D1_F2.S2_D2_F3();
S2_D1_F2.S2_D2_F3 s2_s2_d1_f2_s2_d2_f3_265 = s2_s2_d1_f2_s2_d2_f3_264;
S2_D1_F2 s2_s2_d1_f2_266 = new S2_D1_F2();
S2_D1_F3.S2_D2_F3 s2_s2_d1_f3_s2_d2_f3_268 = new S2_D1_F3.S2_D2_F3();
S2_D1_F3 s2_s2_d1_f3_269 = new S2_D1_F3();
S2_D1_F3 s2_s2_d1_f3_270 = s2_s2_d1_f3_269;
s2_s2_d1_f3_270.v512_uint_16 = Vector512.IsZero(Vector512.AllBitsSet);
Log("s2_s2_d1_f", s2_s2_d1_f2_s2_d2_f2_262.v_double_0);
Log("s2_s2_d1_f", s2_s2_d1_f2_s2_d2_f2_263.v_double_0);
Log("s2_s2_d1_f", s2_s2_d1_f2_s2_d2_f3_264);
Log("s2_s2_d1_f", s2_s2_d1_f2_s2_d2_f3_265.v3_10);
Log("s2_s2_d1_f", s2_s2_d1_f2_266);
Log("s2_s2_d1_f", s2_s2_d1_f3_s2_d2_f3_268.v256_int_14);
Log("s2_s2_d1_f", s2_s2_d1_f3_269.v128_long_13);
Log("s2_s2_d1_f", s2_s2_d1_f3_270.v128_long_13);
return;
}
}
public static void Main(string[] args)
{
new TestClass().Method0();
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void Log(string varName, object varValue)
{
}
}
CC. @jakobbotsch -- I know where/how to disable the promoted field support from the new mask optimization, but I'm not quite sure the best place to disable TYP_MASK for old promotion, any pointer here would be appreciated

Disabling it in the new mask optimization should be enough -- old promotion promotes based on metadata, and no metadata field will be of type TYP_MASK. No change should be necessary in physical promotion either, the dump shows that the MASK promotion indeed happens because of an assignment from an old promoted struct with a TYP_MASK field.

@dotnet-policy-service dotnet-policy-service bot added the in-pr There is an active PR which will close this issue when it is merged label Dec 6, 2024
@JulieLeeMSFT JulieLeeMSFT removed the untriaged New issue has not been triaged by the area owner label Dec 6, 2024
@JulieLeeMSFT JulieLeeMSFT added this to the 10.0.0 milestone Dec 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI in-pr There is an active PR which will close this issue when it is merged
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants