diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 0a852a43d0deb..27771bbb7c18c 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -1147,11 +1147,13 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo, unsigned skipArgs, un assert((doubleAlignMask & RBM_ARG_REGS) == doubleAlignMask); if (doubleAlignMask != RBM_NONE && doubleAlignMask != RBM_ARG_REGS) { - // doubleAlignMask can only be 0011 and/or 1100 as 'double aligned types' can - // begin at r0 or r2. - assert(doubleAlignMask == 0x3 || doubleAlignMask == 0xC /* || 0xF is if'ed out */); + // 'double aligned types' can begin only at r0 or r2 and we always expect at least two registers to be used + // Note that in rare cases, we can have double-aligned structs of 12 bytes (if specified explicitly with + // attributes) + assert((doubleAlignMask == 0b0011) || (doubleAlignMask == 0b1100) || + (doubleAlignMask == 0b0111) /* || 0b1111 is if'ed out */); - // Now if doubleAlignMask is 0011 i.e., {r0,r1} and we prespill r2 or r3 + // Now if doubleAlignMask is xyz1 i.e., the struct starts in r0, and we prespill r2 or r3 // but not both, then the stack would be misaligned for r0. So spill both // r2 and r3. // @@ -1160,7 +1162,10 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo, unsigned skipArgs, un // ; -8 r1 r1 // ; -c r0 r0 <-- misaligned. // ; callee saved regs - if (doubleAlignMask == 0x3 && doubleAlignMask != codeGen->regSet.rsMaskPreSpillRegArg) + bool startsAtR0 = (doubleAlignMask & 1) == 1; + bool r2XorR3 = ((codeGen->regSet.rsMaskPreSpillRegArg & RBM_R2) == 0) != + ((codeGen->regSet.rsMaskPreSpillRegArg & RBM_R3) == 0); + if (startsAtR0 && r2XorR3) { codeGen->regSet.rsMaskPreSpillAlign = (~codeGen->regSet.rsMaskPreSpillRegArg & ~doubleAlignMask) & RBM_ARG_REGS; diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_42723/Runtime_42723.cs b/src/tests/JIT/Regression/JitBlue/Runtime_42723/Runtime_42723.cs new file mode 100644 index 0000000000000..ac9099a86c86b --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_42723/Runtime_42723.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +class Runtime_42723 +{ + static int Main() + { + return Test(new S { X = 17, Y = 83 }); + } + + // On ARM32 we were asserting for a 8-byte aligned 12-byte struct as a parameter + [MethodImpl(MethodImplOptions.NoInlining)] + static int Test(S s) => (int)(s.X + s.Y); + + [StructLayout(LayoutKind.Sequential, Size = 12)] + struct S + { + public double X; + public float Y; + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_42723/Runtime_42723.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_42723/Runtime_42723.csproj new file mode 100644 index 0000000000000..9a1d21f86b7ea --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_42723/Runtime_42723.csproj @@ -0,0 +1,12 @@ + + + Exe + + + None + False + + + + + \ No newline at end of file