dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.93k stars 4.64k forks source link

JIT: Assertion failed 'node->AsMultiOp()->GetOperandCount() == 2' during 'Assertion prop' #106544

Open amanasifkhalid opened 3 weeks ago

amanasifkhalid commented 3 weeks ago

Hit by Antigen on Windows x64:

// Found by Antigen
// Reduced from 43.48 KB to 1.19 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
{
    static bool s_bool_5 = false;
    static Vector256<int> s_v256_int_34 = Vector256.Create(2, 5, 5, 2, 20, -2, 2, -1);
    Vector256<int> v256_int_95 = Vector256.Create(5);
    private static List<string> toPrint = new List<string>();
    public void Method0()
    {
        unchecked
        {
            s_bool_5 = Vector256.LessThanOrEqualAll(Vector256.GreaterThanOrEqual(s_v256_int_34 ^ v256_int_95| (s_v256_int_34 = s_v256_int_34), v256_int_95 + s_v256_int_34 + s_v256_int_34) & (Vector256.Equals(s_v256_int_34 & s_v256_int_34, s_v256_int_34) ^ Vector256.GreaterThanOrEqual(s_v256_int_34 ^ v256_int_95| (s_v256_int_34 = s_v256_int_34), v256_int_95 + s_v256_int_34 + s_v256_int_34)), Vector256.IsPositive(s_v256_int_34 & s_v256_int_34));
            return;
        }
    }
    public static void Main(string[] args)
{}
    public static int Antigen()
    {
        new TestClass().Method0();
        return string.Join(Environment.NewLine, toPrint).GetHashCode();
    }
}
/*
Environment:

set DOTNET_JitDoReversePostOrderLayout=1
set DOTNET_TailcallStress=1
set DOTNET_JitForceControlFlowGuard=1
set DOTNET_JitRLCSEGreedy=1
set DOTNET_JitProfileCasts=1
set DOTNET_JitRandomEdgeCounts=1
set DOTNET_TieredCompilation=0
set DOTNET_PreferredVectorBitWidth=512
set DOTNET_EnablePCLMULQDQ=1
set DOTNET_EnableFMA=1
set DOTNET_JitStress=1
set DOTNET_JitThrowOnAssertionFailure=1
set DOTNET_LegacyExceptionHandling=1

Debug: -1456706854

Release: 0
JIT assert failed:
Assertion failed 'node->AsMultiOp()->GetOperandCount() == 2' in 'TestClass:Method0():this' during 'Assertion prop' (IL size 192; hash 0x46e9aa75; FullOpts)

    File: D:\a\_work\1\s\src\coreclr\jit\compiler.h Line: 11931

*/

cc @dotnet/jit-contrib

dotnet-policy-service[bot] commented 3 weeks ago

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

AndyAyersMS commented 3 weeks ago

I'll take a look.

AndyAyersMS commented 3 weeks ago

This one requires jit stress, specifically, STRESS_OPT_REPEAT

AndyAyersMS commented 3 weeks ago

Issue is that we transform an XOR into a NOT, but the XOR has GTF_REVERSE_OPS which we only expect to see on binary operations.

Fix seems to be simple enough, and this is not a product issue (reverse flag should be harmless on a unary op), so will not backport.

AndyAyersMS commented 3 weeks ago

Easy to do a point fix, in morph when we transform xor->not we can clear GTF_REVERSE_OPS.

But we do a lot of operator manipulation for HW intrinsics these days, seems like the general solution would be to reset some of this state when we change operators.

@tannergooding any thoughts?

tannergooding commented 3 weeks ago

But we do a lot of operator manipulation for HW intrinsics these days, seems like the general solution would be to reset some of this state when we change operators.

That sounds reasonable. We currently always indirectly go through SetHWIntrinsicId when such transforms happen and that has some minimal validation about state already. So I suspect that'd be the right place to do it.

The direct callsites are ChangeHWIntrinsicId and ResetHWIntrinsicId. The former is required to keep the number of operands the same, while the latter can change the number of operands., but in both cases the caller is meant to update flags as appropriate.