Repository: dotnet/runtime
Pull request #113376: Fix assertions related to combining `cmn (extended-register)` (#113337)
Author: login: snickolls-arm
Labels: name: area-CodeGen-coreclr
description: CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
name: community-contribution
description: Indicates that the PR has been added by a community member
Created: 2025-03-11T14:55:47Z | Merged: 2025-03-26T19:18:31Z

Fixes issues highlighted by Fuzzlyn, related to erroneously combining cast=>negate=>compare into `cmn (extended-register)` when the second operand is an integral constant.

Fixes: #113337


Diff:
diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp
index 8c2528de2c2e65..fdfef546fde5a4 100644
--- a/src/coreclr/jit/lowerarmarch.cpp
+++ b/src/coreclr/jit/lowerarmarch.cpp
@@ -406,8 +406,21 @@ bool Lowering::IsContainableUnaryOrBinaryOp(GenTree* parentNode, GenTree* childN
 
             if (childNode->gtGetOp1()->OperIs(GT_CAST))
             {
-                // Grab the cast as well, we can contain this with cmn.
-                GenTreeCast* cast = childNode->gtGetOp1()->AsCast();
+                // Grab the cast as well, we can contain this with cmn (extended-register).
+                GenTreeCast* cast   = childNode->gtGetOp1()->AsCast();
+                GenTree*     castOp = cast->CastOp();
+
+                // Cannot contain the cast from floating point.
+                if (!varTypeIsIntegral(castOp))
+                {
+                    return false;
+                }
+
+                // Cannot contain the cast if it already contains it's CastOp.
+                if (castOp->isContained())
+                {
+                    return false;
+                }
 
                 assert(!cast->gtOverflow());
                 assert(varTypeIsIntegral(cast) && varTypeIsIntegral(cast->CastToType()));
@@ -3187,11 +3200,15 @@ bool Lowering::TryLowerAndOrToCCMP(GenTreeOp* tree, GenTree** next)
     //
     GenCondition cond1;
     if (op2->OperIsCmpCompare() && varTypeIsIntegralOrI(op2->gtGetOp1()) && IsInvariantInRange(op2, tree) &&
+        (op2->gtGetOp1()->IsIntegralConst() || !op2->gtGetOp1()->isContained()) &&
+        (op2->gtGetOp2() == nullptr || op2->gtGetOp2()->IsIntegralConst() || !op2->gtGetOp2()->isContained()) &&
         TryLowerConditionToFlagsNode(tree, op1, &cond1))
     {
         // Fall through, converting op2 to the CCMP
     }
     else if (op1->OperIsCmpCompare() && varTypeIsIntegralOrI(op1->gtGetOp1()) && IsInvariantInRange(op1, tree) &&
+             (op1->gtGetOp1()->IsIntegralConst() || !op1->gtGetOp1()->isContained()) &&
+             (op1->gtGetOp2() == nullptr || op1->gtGetOp2()->IsIntegralConst() || !op1->gtGetOp2()->isContained()) &&
              TryLowerConditionToFlagsNode(tree, op2, &cond1))
     {
         std::swap(op1, op2);
diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_113337/Runtime_113337.cs b/src/tests/JIT/Regression/JitBlue/Runtime_113337/Runtime_113337.cs
new file mode 100644
index 00000000000000..bb0d2c8aa4529b
--- /dev/null
+++ b/src/tests/JIT/Regression/JitBlue/Runtime_113337/Runtime_113337.cs
@@ -0,0 +1,78 @@
+// 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.Numerics;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.Arm;
+using System.Runtime.CompilerServices;
+using Xunit;
+
+#pragma warning disable SYSLIB5003 // Allow experimental SVE
+
+public class Runtime_113337
+{
+    static sbyte[] s_7;
+
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    static void issue1()
+    {
+        try
+        {
+            var vr9 = Vector64.Create<float>(0);
+            if ((2147483647 == (-(int)AdvSimd.Extract(vr9, 1))))
+            {
+                s_7 = s_7;
+            }
+        }
+        catch (PlatformNotSupportedException e)
+        {
+        }
+    }
+
+    static int[][] s_2;
+    static bool s_3;
+
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    static void issue2()
+    {
+        try
+        {
+            s_3 ^= (2021486855 != (-(long)s_2[0][0]));
+        }
+        catch (NullReferenceException e)
+        {
+        }
+    }
+
+    static Vector<ulong>[] s_4;
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    static void issue3()
+    {
+        try
+        {
+            var vr3 = Vector.Create<short>(1);
+            var vr4 = (short)0;
+            var vr5 = Vector128.CreateScalar(vr4).AsVector();
+            if ((Sve.TestFirstTrue(vr3, vr5) | (3268100580U != (-(uint)Sve.SaturatingDecrementBy16BitElementCount(0, 1)))))
+            {
+                s_4[0] = s_4[0];
+            }
+        }
+        catch (PlatformNotSupportedException e)
+        {
+        }
+        catch (NullReferenceException e)
+        {
+        }
+    }
+
+    [Fact]
+    public static void TestEntryPoint()
+    {
+        // Checking for successful compilation
+        issue1();
+        issue2();
+        issue3();
+    }
+}
\ No newline at end of file
diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_113337/Runtime_113337.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_113337/Runtime_113337.csproj
new file mode 100644
index 00000000000000..15edd99711a1a4
--- /dev/null
+++ b/src/tests/JIT/Regression/JitBlue/Runtime_113337/Runtime_113337.csproj
@@ -0,0 +1,8 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <Optimize>True</Optimize>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="$(MSBuildProjectName).cs" />
+  </ItemGroup>
+</Project>
\ No newline at end of file


Reviews:
user: login: jakobbotsch
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-11T15:07:44Z
user: login: jakobbotsch
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-11T15:07:59Z
user: login: jakobbotsch
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-11T15:08:57Z
user: login: EgorBo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-11T15:52:09Z
user: login: snickolls-arm
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T17:07:26Z
user: login: jakobbotsch
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-11T21:11:08Z
user: login: snickolls-arm
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T10:31:54Z
user: login: jakobbotsch
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-13T20:11:12Z
user: login: snickolls-arm
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T10:45:05Z
user: login: jakobbotsch
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T14:08:06Z
user: login: jakobbotsch
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-26T19:14:51Z
user: login: jakobbotsch
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-26T19:14:55Z

Review comments:
diff_hunk: @@ -0,0 +1,39 @@
+using System;
+using System.Numerics;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.Arm;
+using System.Runtime.CompilerServices;
+using Xunit;
+
+public class Program
path: src/tests/JIT/Regression/JitBlue/Runtime_113337/Runtime_113337.cs
user: login: jakobbotsch
body: ```suggestion
public class Runtime_113337
```
created_at: 2025-03-11T15:07:44Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,39 @@
+using System;
+using System.Numerics;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.Arm;
+using System.Runtime.CompilerServices;
+using Xunit;
+
+public class Program
+{
+    static sbyte[] s_7;
+
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    static void issue1()
+    {
+        var vr9 = Vector64.Create<float>(0);
+        if ((2147483647 == (-(int)AdvSimd.Extract(vr9, 1))))
+        {
+            s_7 = s_7;
+        }
+    }
+
+    static int[][] s_2;
+    static bool s_3;
+
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    static void issue2()
+    {
+        s_3 ^= (2021486855 != (-(long)s_2[0][0]));
+    }
+
+    [Fact]
+    public static int TestEntryPoint()
+    {
+        // Checking for successful compilation
+        issue1();
+        issue2();
+        return 100;
+    }
path: src/tests/JIT/Regression/JitBlue/Runtime_113337/Runtime_113337.cs
user: login: jakobbotsch
body: ```suggestion
    public static void TestEntryPoint()
    {
        // Checking for successful compilation
        issue1();
        issue2();
    }
```
created_at: 2025-03-11T15:07:59Z
author_association: MEMBER
diff_hunk: @@ -404,9 +404,9 @@ bool Lowering::IsContainableUnaryOrBinaryOp(GenTree* parentNode, GenTree* childN
                 return false;
             }
 
-            if (childNode->gtGetOp1()->OperIs(GT_CAST))
+            if (childNode->gtGetOp1()->OperIs(GT_CAST) && !parentNode->gtGetOp2()->IsIntegralConst())
path: src/coreclr/jit/lowerarmarch.cpp
user: login: jakobbotsch
body: ```suggestion
            if (childNode->gtGetOp1()->OperIs(GT_CAST) && !parentNode->gtGetOp2()->isContained())
```
Should this check rather be like this? Uncontained constant will still be in a register, and that should be fine.
created_at: 2025-03-11T15:08:57Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,39 @@
+using System;
+using System.Numerics;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.Arm;
+using System.Runtime.CompilerServices;
+using Xunit;
+
+public class Program
path: src/tests/JIT/Regression/JitBlue/Runtime_113337/Runtime_113337.cs
user: login: EgorBo
body: Also, add the standard header (.NET Foundation)
created_at: 2025-03-11T15:52:09Z
author_association: MEMBER
diff_hunk: @@ -404,9 +404,9 @@ bool Lowering::IsContainableUnaryOrBinaryOp(GenTree* parentNode, GenTree* childN
                 return false;
             }
 
-            if (childNode->gtGetOp1()->OperIs(GT_CAST))
+            if (childNode->gtGetOp1()->OperIs(GT_CAST) && !parentNode->gtGetOp2()->IsIntegralConst())
path: src/coreclr/jit/lowerarmarch.cpp
user: login: snickolls-arm
body: This line change doesn't seem to work but I'm not sure why just yet, I'll follow up shortly. It's already guaranteed that the constant is not contained here, because there is a check at the beginning of the function that will return if one of the nodes is contained already.

I've also noticed that `gtGetOp2` isn't a reliable way of getting the other operand, as `childNode` could be `op1` or `op2`, so I've fixed this.
created_at: 2025-03-11T17:07:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -404,9 +404,9 @@ bool Lowering::IsContainableUnaryOrBinaryOp(GenTree* parentNode, GenTree* childN
                 return false;
             }
 
-            if (childNode->gtGetOp1()->OperIs(GT_CAST))
+            if (childNode->gtGetOp1()->OperIs(GT_CAST) && !parentNode->gtGetOp2()->IsIntegralConst())
path: src/coreclr/jit/lowerarmarch.cpp
user: login: jakobbotsch
body: Indeed seems like something else must be wrong. An uncontained constant is, like any other node, going to be in a register, so this check should not make a difference if we know it is not contained.
created_at: 2025-03-11T21:11:08Z
author_association: MEMBER
diff_hunk: @@ -404,9 +404,9 @@ bool Lowering::IsContainableUnaryOrBinaryOp(GenTree* parentNode, GenTree* childN
                 return false;
             }
 
-            if (childNode->gtGetOp1()->OperIs(GT_CAST))
+            if (childNode->gtGetOp1()->OperIs(GT_CAST) && !parentNode->gtGetOp2()->IsIntegralConst())
path: src/coreclr/jit/lowerarmarch.cpp
user: login: snickolls-arm
body: Looking again, I think it was down to the cast node needing more restrictions. I thought the assertion `isGeneralRegister(reg2)` was firing on `REG_NA`, but it was actually firing on a floating point register. The other assertion is down to containing a cast node that already contains a `LCL_VAR`, this shouldn't be allowed.
created_at: 2025-03-12T10:31:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -406,8 +406,21 @@ bool Lowering::IsContainableUnaryOrBinaryOp(GenTree* parentNode, GenTree* childN
 
             if (childNode->gtGetOp1()->OperIs(GT_CAST))
             {
-                // Grab the cast as well, we can contain this with cmn.
-                GenTreeCast* cast = childNode->gtGetOp1()->AsCast();
+                // Grab the cast as well, we can contain this with cmn (extended-register).
+                GenTreeCast* cast   = childNode->gtGetOp1()->AsCast();
+                GenTree*     castOp = cast->CastOp();
+
+                // Cannot contain the cast from floating point.
+                if (!varTypeIsIntegral(castOp))
+                {
+                    return false;
+                }
+
+                // Cannot contain the cast if it may contain or is already containing a memory operation.
+                if (IsContainableMemoryOp(castOp) || castOp->isContained())
path: src/coreclr/jit/lowerarmarch.cpp
user: login: jakobbotsch
body: Is the `IsContainableMemoryOp` check necessary? 
created_at: 2025-03-13T20:11:12Z
author_association: MEMBER
diff_hunk: @@ -406,8 +406,21 @@ bool Lowering::IsContainableUnaryOrBinaryOp(GenTree* parentNode, GenTree* childN
 
             if (childNode->gtGetOp1()->OperIs(GT_CAST))
             {
-                // Grab the cast as well, we can contain this with cmn.
-                GenTreeCast* cast = childNode->gtGetOp1()->AsCast();
+                // Grab the cast as well, we can contain this with cmn (extended-register).
+                GenTreeCast* cast   = childNode->gtGetOp1()->AsCast();
+                GenTree*     castOp = cast->CastOp();
+
+                // Cannot contain the cast from floating point.
+                if (!varTypeIsIntegral(castOp))
+                {
+                    return false;
+                }
+
+                // Cannot contain the cast if it may contain or is already containing a memory operation.
+                if (IsContainableMemoryOp(castOp) || castOp->isContained())
path: src/coreclr/jit/lowerarmarch.cpp
user: login: snickolls-arm
body: Assuming castOp and cast have already been analyzed for containment before this, then it's not necessary. Is that always true?
created_at: 2025-03-24T10:45:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -406,8 +406,21 @@ bool Lowering::IsContainableUnaryOrBinaryOp(GenTree* parentNode, GenTree* childN
 
             if (childNode->gtGetOp1()->OperIs(GT_CAST))
             {
-                // Grab the cast as well, we can contain this with cmn.
-                GenTreeCast* cast = childNode->gtGetOp1()->AsCast();
+                // Grab the cast as well, we can contain this with cmn (extended-register).
+                GenTreeCast* cast   = childNode->gtGetOp1()->AsCast();
+                GenTree*     castOp = cast->CastOp();
+
+                // Cannot contain the cast from floating point.
+                if (!varTypeIsIntegral(castOp))
+                {
+                    return false;
+                }
+
+                // Cannot contain the cast if it may contain or is already containing a memory operation.
+                if (IsContainableMemoryOp(castOp) || castOp->isContained())
path: src/coreclr/jit/lowerarmarch.cpp
user: login: jakobbotsch
body: Yes, that is always true. `castOp` is an operand, and operands always have to appear earlier in linear order.
created_at: 2025-03-24T14:08:06Z
author_association: MEMBER
diff_hunk: @@ -3187,11 +3200,15 @@ bool Lowering::TryLowerAndOrToCCMP(GenTreeOp* tree, GenTree** next)
     //
     GenCondition cond1;
     if (op2->OperIsCmpCompare() && varTypeIsIntegralOrI(op2->gtGetOp1()) && IsInvariantInRange(op2, tree) &&
+        (op2->gtGetOp1()->IsIntegralConst() || !op2->gtGetOp1()->isContained()) &&
+        (op2->gtGetOp2() == nullptr || op2->gtGetOp2()->IsIntegralConst() || !op2->gtGetOp2()->isContained()) &&
path: src/coreclr/jit/lowerarmarch.cpp
user: login: jakobbotsch
body: This nullptr check is unnecessary (we already checked for `CmpCompare` above, all of those are binops). But let's not wait for another round of CI here.
created_at: 2025-03-26T19:14:51Z
author_association: MEMBER

PR comments:
user: login: jakobbotsch
created_at: 2025-03-24T16:36:44Z
body: /azp run Fuzzlyn
author_association: MEMBER
user: login: azure-pipelines[bot]
created_at: 2025-03-24T16:36:58Z
body: <samp>
Azure Pipelines successfully started running 1 pipeline(s).<br>

</samp>
author_association: NONE
user: login: jakobbotsch
created_at: 2025-03-24T19:26:23Z
body: Are the [Fuzzlyn found](https://dev.azure.com/dnceng-public/public/_build/results?buildId=991397&view=ms.vss-build-web.run-extensions-tab) "unreached" assertion failures a different problem?

E.g.
```csharp
// Generated by Fuzzlyn v2.5 on 2025-03-24 18:20:14
// Run on Arm64 Linux
// Seed: 8261718896722533474-vectort,vector64,vector128,armadvsimd,armadvsimdarm64,armaes,armarmbase,armarmbasearm64,armcrc32,armcrc32arm64,armdp,armrdm,armrdmarm64,armsha1,armsha256,armsve
// Reduced from 58.9 KiB to 0.5 KiB in 00:00:22
// Hits JIT assert in Release:
// Assertion failed 'unreached' in 'Program:Main(Fuzzlyn.ExecutionServer.IRuntime)' during 'Generate code' (IL size 72; hash 0xade6b36b; FullOpts)
// 
//     File: /__w/1/s/src/coreclr/jit/codegenarm64.cpp Line: 3530
// 
using System;
using System.Numerics;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;

public class Program
{
    public static Vector<ulong>[] s_3;
    public static void Main()
    {
        var vr3 = Vector.Create<short>(1);
        var vr4 = (short)0;
        var vr5 = Vector128.CreateScalar(vr4).AsVector();
        if ((Sve.TestFirstTrue(vr3, vr5) | (3268100580U != (-(uint)Sve.SaturatingDecrementBy16BitElementCount(0, 1)))))
        {
            s_3[0] = s_3[0];
        }
    }
}
```
author_association: MEMBER
user: login: snickolls-arm
created_at: 2025-03-25T09:41:22Z
body: > Are the [Fuzzlyn found](https://dev.azure.com/dnceng-public/public/_build/results?buildId=991397&view=ms.vss-build-web.run-extensions-tab) "unreached" assertion failures a different problem?

I haven't seen this assertion fire before, but it looks like it's related to this change in containment patterns. I'll take a look today.

author_association: CONTRIBUTOR
user: login: snickolls-arm
created_at: 2025-03-25T14:57:16Z
body: > I haven't seen this assertion fire before, but it looks like it's related to this change in containment patterns. I'll take a look today.

@jakobbotsch 

This new assertion is fired when a `NEG` node contains a `CAST` node. I think this situation is caused by the `CCMP` transform that is running on the code generated by Fuzzlyn. On [this line](https://github.com/dotnet/runtime/blob/32299f4b6aa148fd6ee0da222b01334a88414a25/src/coreclr/jit/lowerarmarch.cpp#L3214) it clears the containment relation between `CMP => NEG` after bashing the `CMP` node to `CCMP`, but it is not clearing the containment relation between `NEG => CAST`.

It's a slightly different problem but still introduced by the same change as before. Would you prefer this fix as a separate pull request, or a continuation here?
author_association: CONTRIBUTOR
user: login: jakobbotsch
created_at: 2025-03-25T15:06:49Z
body: I wonder if we should rethink this transformation, to make it more robust. Would it make more sense to introduce a new `GT_CMPNEG` node to represent the "compare negated" version of the instruction? The multiple levels of containments always seem to cause trouble (it's not the first time we see issues like this).
author_association: MEMBER
user: login: jakobbotsch
created_at: 2025-03-25T16:24:32Z
body: Alternatively I would be ok with skipping the transformation in `TryLowerAndOrToCCMP` when an operand is a contained non-constant. That's an easier fix.
author_association: MEMBER
user: login: snickolls-arm
created_at: 2025-03-25T16:39:40Z
body: > I wonder if we should rethink this transformation, to make it more robust. Would it make more sense to introduce a new `GT_CMPNEG` node to represent the "compare negated" version of the instruction? The multiple levels of containments always seem to cause trouble (it's not the first time we see issues like this).

This could work. There's potentially some complications around the precedence of this transform over the `CCMP` transform, as the node would need to be split up again when converted into `CCMP` after the fact.

> Alternatively I would be ok with skipping the transformation in TryLowerAndOrToCCMP when an operand is a contained non-constant. That's an easier fix.

OK, I'll try this next.
author_association: CONTRIBUTOR
user: login: jakobbotsch
created_at: 2025-03-25T16:43:44Z
body: > This could work. There's potentially some complications around the precedence of this transform over the `CCMP` transform, as the node would need to be split up again when converted into `CCMP` after the fact.

Yeah, but very possibly we would just skip the conversion into `ccmp` for these cases, unless we can show the missed benefit to be significant. The key is that things would be correct by construction (a missed optimization is much better than asserts or potential silent bad codegen).
author_association: MEMBER
user: login: snickolls-arm
created_at: 2025-03-26T16:02:30Z
body: 
> Are the [Fuzzlyn found](https://dev.azure.com/dnceng-public/public/_build/results?buildId=991397&view=ms.vss-build-web.run-extensions-tab) "unreached" assertion failures a different problem?
> 
> E.g.
> 
> ```cs
> // Generated by Fuzzlyn v2.5 on 2025-03-24 18:20:14
> // Run on Arm64 Linux
> // Seed: 8261718896722533474-vectort,vector64,vector128,armadvsimd,armadvsimdarm64,armaes,armarmbase,armarmbasearm64,armcrc32,armcrc32arm64,armdp,armrdm,armrdmarm64,armsha1,armsha256,armsve
> // Reduced from 58.9 KiB to 0.5 KiB in 00:00:22
> // Hits JIT assert in Release:
> // Assertion failed 'unreached' in 'Program:Main(Fuzzlyn.ExecutionServer.IRuntime)' during 'Generate code' (IL size 72; hash 0xade6b36b; FullOpts)
> // 
> //     File: /__w/1/s/src/coreclr/jit/codegenarm64.cpp Line: 3530
> // 
> using System;
> using System.Numerics;
> using System.Runtime.Intrinsics;
> using System.Runtime.Intrinsics.Arm;
> 
> public class Program
> {
>     public static Vector<ulong>[] s_3;
>     public static void Main()
>     {
>         var vr3 = Vector.Create<short>(1);
>         var vr4 = (short)0;
>         var vr5 = Vector128.CreateScalar(vr4).AsVector();
>         if ((Sve.TestFirstTrue(vr3, vr5) | (3268100580U != (-(uint)Sve.SaturatingDecrementBy16BitElementCount(0, 1)))))
>         {
>             s_3[0] = s_3[0];
>         }
>     }
> }
> ```

These latest build failures seem to be network related as far as I understand. I've added this case to the test class and it seems to be compiling now.
author_association: CONTRIBUTOR
user: login: jakobbotsch
created_at: 2025-03-26T16:07:59Z
body: /azp run Fuzzlyn
author_association: MEMBER
user: login: azure-pipelines[bot]
created_at: 2025-03-26T16:08:14Z
body: <samp>
Azure Pipelines successfully started running 1 pipeline(s).<br>

</samp>
author_association: NONE
user: login: jakobbotsch
created_at: 2025-03-26T19:13:31Z
body: Fuzzlyn failures are #113923, #113939, #113940. Linux-x64 failures are azurelinux timeouts.
author_association: MEMBER
user: login: jakobbotsch
created_at: 2025-03-26T19:13:49Z
body: /ba-g Azurelinux timeouts
author_association: MEMBER
user: login: jakobbotsch
created_at: 2025-03-26T19:18:16Z
body: There's a small number of regressions like this one:
![image](https://github.com/user-attachments/assets/2ea8c931-b33d-4553-ad0e-652b1d1dd93a)

Can you take a look at why, and potentially submit a follow-up if it's something unexpected?

I'm going to merge this to clean up Fuzzlyn runs.
author_association: MEMBER