summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/jit/compiler.cpp3
-rw-r--r--src/jit/compiler.h2
-rw-r--r--src/jit/compiler.hpp83
-rw-r--r--src/jit/emit.cpp3
-rw-r--r--src/jit/emitarm.cpp23
-rw-r--r--src/jit/emitarm.h2
-rw-r--r--src/jit/lclvars.cpp2
-rw-r--r--tests/arm/corefx_linux_test_exclusions.txt1
-rw-r--r--tests/arm/corefx_test_exclusions.txt1
-rw-r--r--tests/issues.targets6
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_19537/GitHub_19537.cs417
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_19537/GitHub_19537.csproj35
12 files changed, 518 insertions, 60 deletions
diff --git a/src/jit/compiler.cpp b/src/jit/compiler.cpp
index 43acab3ca8..8093a7defc 100644
--- a/src/jit/compiler.cpp
+++ b/src/jit/compiler.cpp
@@ -4200,7 +4200,8 @@ bool Compiler::compRsvdRegCheck(FrameLayoutState curState)
// Always do the layout even if returning early. Callers might
// depend on us to do the layout.
unsigned frameSize = lvaFrameSize(curState);
- JITDUMP("\ncompRsvdRegCheck\n"
+ JITDUMP("\n"
+ "compRsvdRegCheck\n"
" frame size = %6d\n"
" compArgSize = %6d\n",
frameSize, compArgSize);
diff --git a/src/jit/compiler.h b/src/jit/compiler.h
index a79d77e4e2..7b91d39e2a 100644
--- a/src/jit/compiler.h
+++ b/src/jit/compiler.h
@@ -3055,7 +3055,7 @@ public:
#endif
#ifdef _TARGET_ARM_
- int lvaFrameAddress(int varNum, bool mustBeFPBased, regNumber* pBaseReg, int addrModeOffset);
+ int lvaFrameAddress(int varNum, bool mustBeFPBased, regNumber* pBaseReg, int addrModeOffset, bool isFloatUsage);
#else
int lvaFrameAddress(int varNum, bool* pFPbased);
#endif
diff --git a/src/jit/compiler.hpp b/src/jit/compiler.hpp
index 8461b1f2a0..29a79f862b 100644
--- a/src/jit/compiler.hpp
+++ b/src/jit/compiler.hpp
@@ -2066,25 +2066,37 @@ inline int Compiler::lvaCachedGenericContextArgOffset()
return lvaCachedGenericContextArgOffs;
}
-/*****************************************************************************
- *
- * Return the stack framed offset of the given variable; set *FPbased to
- * true if the variable is addressed off of FP, false if it's addressed
- * off of SP. Note that 'varNum' can be a negated spill-temporary var index.
- *
- * mustBeFPBased - strong about whether the base reg is FP. But it is also
- * strong about not being FPBased after FINAL_FRAME_LAYOUT. i.e.,
- * it enforces SP based.
- *
- * addrModeOffset - is the addressing mode offset, for example: v02 + 0x10
- * So, V02 itself is at offset sp + 0x10 and then addrModeOffset is what gets
- * added beyond that.
- */
-
+//------------------------------------------------------------------------
+// lvaFrameAddress: Determine the stack frame offset of the given variable,
+// and how to generate an address to that stack frame.
+//
+// Arguments:
+// varNum - The variable to inquire about. Positive for user variables
+// or arguments, negative for spill-temporaries.
+// mustBeFPBased - [_TARGET_ARM_ only] True if the base register must be FP.
+// After FINAL_FRAME_LAYOUT, if false, it also requires SP base register.
+// pBaseReg - [_TARGET_ARM_ only] Out arg. *pBaseReg is set to the base
+// register to use.
+// addrModeOffset - [_TARGET_ARM_ only] The mode offset within the variable that we need to address.
+// For example, for a large struct local, and a struct field reference, this will be the offset
+// of the field. Thus, for V02 + 0x28, if V02 itself is at offset SP + 0x10
+// then addrModeOffset is what gets added beyond that, here 0x28.
+// isFloatUsage - [_TARGET_ARM_ only] True if the instruction being generated is a floating
+// point instruction. This requires using floating-point offset restrictions.
+// Note that a variable can be non-float, e.g., struct, but accessed as a
+// float local field.
+// pFPbased - [non-_TARGET_ARM_] Out arg. Set *FPbased to true if the
+// variable is addressed off of FP, false if it's addressed
+// off of SP.
+//
+// Return Value:
+// Returns the variable offset from the given base register.
+//
inline
#ifdef _TARGET_ARM_
int
- Compiler::lvaFrameAddress(int varNum, bool mustBeFPBased, regNumber* pBaseReg, int addrModeOffset)
+ Compiler::lvaFrameAddress(
+ int varNum, bool mustBeFPBased, regNumber* pBaseReg, int addrModeOffset, bool isFloatUsage)
#else
int
Compiler::lvaFrameAddress(int varNum, bool* pFPbased)
@@ -2092,17 +2104,15 @@ inline
{
assert(lvaDoneFrameLayout != NO_FRAME_LAYOUT);
- int offset;
- bool FPbased;
- bool fConservative = false;
- var_types type = TYP_UNDEF;
+ int varOffset;
+ bool FPbased;
+ bool fConservative = false;
if (varNum >= 0)
{
LclVarDsc* varDsc;
assert((unsigned)varNum < lvaCount);
varDsc = lvaTable + varNum;
- type = varDsc->TypeGet();
bool isPrespilledArg = false;
#if defined(_TARGET_ARM_) && defined(PROFILING_SUPPORTED)
isPrespilledArg = varDsc->lvIsParam && compIsProfilerHookNeeded() &&
@@ -2146,7 +2156,7 @@ inline
}
#endif // DEBUG
- offset = varDsc->lvStkOffs;
+ varOffset = varDsc->lvStkOffs;
}
else // Its a spill-temp
{
@@ -2160,8 +2170,7 @@ inline
tmpDsc = codeGen->regSet.tmpFindNum(varNum, RegSet::TEMP_USAGE_USED);
}
assert(tmpDsc != nullptr);
- offset = tmpDsc->tdTempOffs();
- type = tmpDsc->tdTempType();
+ varOffset = tmpDsc->tdTempOffs();
}
else
{
@@ -2188,7 +2197,6 @@ inline
// : :
// ---------------------------------------------------
- type = compFloatingPointUsed ? TYP_FLOAT : TYP_INT;
fConservative = true;
if (!FPbased)
{
@@ -2199,7 +2207,7 @@ inline
#else
int outGoingArgSpaceSize = 0;
#endif
- offset = outGoingArgSpaceSize + max(-varNum * TARGET_POINTER_SIZE, (int)lvaGetMaxSpillTempSize());
+ varOffset = outGoingArgSpaceSize + max(-varNum * TARGET_POINTER_SIZE, (int)lvaGetMaxSpillTempSize());
}
else
{
@@ -2207,9 +2215,9 @@ inline
CLANG_FORMAT_COMMENT_ANCHOR;
#ifdef _TARGET_ARM_
- offset = codeGen->genCallerSPtoInitialSPdelta() - codeGen->genCallerSPtoFPdelta();
+ varOffset = codeGen->genCallerSPtoInitialSPdelta() - codeGen->genCallerSPtoFPdelta();
#else
- offset = -(codeGen->genTotalFrameSize());
+ varOffset = -(codeGen->genTotalFrameSize());
#endif
}
}
@@ -2231,19 +2239,20 @@ inline
// we have already selected the instruction. MinOpts will always reserve R10, so
// for MinOpts always use SP-based offsets, using R10 as necessary, for simplicity.
- int spOffset = fConservative ? compLclFrameSize : offset + codeGen->genSPtoFPdelta();
- int actualOffset = spOffset + addrModeOffset;
- int encodingLimitUpper = varTypeIsFloating(type) ? 0x3FC : 0xFFF;
- int encodingLimitLower = varTypeIsFloating(type) ? -0x3FC : -0xFF;
+ int spVarOffset = fConservative ? compLclFrameSize : varOffset + codeGen->genSPtoFPdelta();
+ int actualSPOffset = spVarOffset + addrModeOffset;
+ int actualFPOffset = varOffset + addrModeOffset;
+ int encodingLimitUpper = isFloatUsage ? 0x3FC : 0xFFF;
+ int encodingLimitLower = isFloatUsage ? -0x3FC : -0xFF;
// Use SP-based encoding. During encoding, we'll pick the best encoding for the actual offset we have.
- if (opts.MinOpts() || (actualOffset <= encodingLimitUpper))
+ if (opts.MinOpts() || (actualSPOffset <= encodingLimitUpper))
{
- offset = spOffset;
+ varOffset = spVarOffset;
*pBaseReg = compLocallocUsed ? REG_SAVED_LOCALLOC_SP : REG_SPBASE;
}
// Use Frame Pointer (R11)-based encoding.
- else if ((encodingLimitLower <= offset) && (offset <= encodingLimitUpper))
+ else if ((encodingLimitLower <= actualFPOffset) && (actualFPOffset <= encodingLimitUpper))
{
*pBaseReg = REG_FPBASE;
}
@@ -2252,7 +2261,7 @@ inline
// the "reserved register", which will get used during encoding.
else
{
- offset = spOffset;
+ varOffset = spVarOffset;
*pBaseReg = compLocallocUsed ? REG_SAVED_LOCALLOC_SP : REG_SPBASE;
}
}
@@ -2265,7 +2274,7 @@ inline
*pFPbased = FPbased;
#endif
- return offset;
+ return varOffset;
}
inline bool Compiler::lvaIsParameter(unsigned varNum)
diff --git a/src/jit/emit.cpp b/src/jit/emit.cpp
index 655f0e2bc8..4a3afc1ab0 100644
--- a/src/jit/emit.cpp
+++ b/src/jit/emit.cpp
@@ -6734,7 +6734,8 @@ target_ssize_t emitter::emitGetInsSC(instrDesc* id)
regNumber baseReg;
int offs = id->idAddr()->iiaLclVar.lvaOffset();
#if defined(_TARGET_ARM_)
- int adr = emitComp->lvaFrameAddress(varNum, id->idIsLclFPBase(), &baseReg, offs);
+ int adr =
+ emitComp->lvaFrameAddress(varNum, id->idIsLclFPBase(), &baseReg, offs, CodeGen::instIsFP(id->idIns()));
int dsp = adr + offs;
if ((id->idIns() == INS_sub) || (id->idIns() == INS_subw))
dsp = -dsp;
diff --git a/src/jit/emitarm.cpp b/src/jit/emitarm.cpp
index 1b8d2af77d..8098c60a41 100644
--- a/src/jit/emitarm.cpp
+++ b/src/jit/emitarm.cpp
@@ -3474,7 +3474,8 @@ void emitter::emitIns_R_S(instruction ins, emitAttr attr, regNumber reg1, int va
int disp;
unsigned undisp;
- base = emitComp->lvaFrameAddress(varx, emitComp->funCurrentFunc()->funKind != FUNC_ROOT, &reg2, offs);
+ base = emitComp->lvaFrameAddress(varx, emitComp->funCurrentFunc()->funKind != FUNC_ROOT, &reg2, offs,
+ CodeGen::instIsFP(ins));
disp = base + offs;
undisp = unsigned_abs(disp);
@@ -3495,7 +3496,7 @@ void emitter::emitIns_R_S(instruction ins, emitAttr attr, regNumber reg1, int va
else
{
regNumber rsvdReg = codeGen->rsGetRsvdReg();
- emitIns_genStackOffset(rsvdReg, varx, offs);
+ emitIns_genStackOffset(rsvdReg, varx, offs, /* isFloatUsage */ true);
emitIns_R_R(INS_add, EA_4BYTE, rsvdReg, reg2);
emitIns_R_R_I(ins, attr, reg1, rsvdReg, 0);
return;
@@ -3519,7 +3520,7 @@ void emitter::emitIns_R_S(instruction ins, emitAttr attr, regNumber reg1, int va
{
// Load disp into a register
regNumber rsvdReg = codeGen->rsGetRsvdReg();
- emitIns_genStackOffset(rsvdReg, varx, offs);
+ emitIns_genStackOffset(rsvdReg, varx, offs, /* isFloatUsage */ false);
fmt = IF_T2_E0;
}
}
@@ -3545,7 +3546,7 @@ void emitter::emitIns_R_S(instruction ins, emitAttr attr, regNumber reg1, int va
{
// Load disp into a register
regNumber rsvdReg = codeGen->rsGetRsvdReg();
- emitIns_genStackOffset(rsvdReg, varx, offs);
+ emitIns_genStackOffset(rsvdReg, varx, offs, /* isFloatUsage */ false);
emitIns_R_R_R(ins, attr, reg1, reg2, rsvdReg);
return;
}
@@ -3583,13 +3584,14 @@ void emitter::emitIns_R_S(instruction ins, emitAttr attr, regNumber reg1, int va
}
// generate the offset of &varx + offs into a register
-void emitter::emitIns_genStackOffset(regNumber r, int varx, int offs)
+void emitter::emitIns_genStackOffset(regNumber r, int varx, int offs, bool isFloatUsage)
{
regNumber regBase;
int base;
int disp;
- base = emitComp->lvaFrameAddress(varx, emitComp->funCurrentFunc()->funKind != FUNC_ROOT, &regBase, offs);
+ base =
+ emitComp->lvaFrameAddress(varx, emitComp->funCurrentFunc()->funKind != FUNC_ROOT, &regBase, offs, isFloatUsage);
disp = base + offs;
emitIns_R_S(INS_movw, EA_4BYTE, r, varx, offs);
@@ -3633,7 +3635,8 @@ void emitter::emitIns_S_R(instruction ins, emitAttr attr, regNumber reg1, int va
int disp;
unsigned undisp;
- base = emitComp->lvaFrameAddress(varx, emitComp->funCurrentFunc()->funKind != FUNC_ROOT, &reg2, offs);
+ base = emitComp->lvaFrameAddress(varx, emitComp->funCurrentFunc()->funKind != FUNC_ROOT, &reg2, offs,
+ CodeGen::instIsFP(ins));
disp = base + offs;
undisp = unsigned_abs(disp);
@@ -3654,7 +3657,7 @@ void emitter::emitIns_S_R(instruction ins, emitAttr attr, regNumber reg1, int va
else
{
regNumber rsvdReg = codeGen->rsGetRsvdReg();
- emitIns_genStackOffset(rsvdReg, varx, offs);
+ emitIns_genStackOffset(rsvdReg, varx, offs, /* isFloatUsage */ true);
emitIns_R_R(INS_add, EA_4BYTE, rsvdReg, reg2);
emitIns_R_R_I(ins, attr, reg1, rsvdReg, 0);
return;
@@ -3676,7 +3679,7 @@ void emitter::emitIns_S_R(instruction ins, emitAttr attr, regNumber reg1, int va
{
// Load disp into a register
regNumber rsvdReg = codeGen->rsGetRsvdReg();
- emitIns_genStackOffset(rsvdReg, varx, offs);
+ emitIns_genStackOffset(rsvdReg, varx, offs, /* isFloatUsage */ false);
fmt = IF_T2_E0;
}
assert((fmt == IF_T1_J2) || (fmt == IF_T2_E0) || (fmt == IF_T2_H0) || (fmt == IF_T2_VLDST) || (fmt == IF_T2_K1));
@@ -6363,7 +6366,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
int varNum = id->idAddr()->iiaLclVar.lvaVarNum();
unsigned ofs = AlignDown(id->idAddr()->iiaLclVar.lvaOffset(), TARGET_POINTER_SIZE);
regNumber regBase;
- int adr = emitComp->lvaFrameAddress(varNum, true, &regBase, ofs);
+ int adr = emitComp->lvaFrameAddress(varNum, true, &regBase, ofs, /* isFloatUsage */ false); // no float GC refs
if (id->idGCref() != GCT_NONE)
{
emitGCvarLiveUpd(adr + ofs, varNum, id->idGCref(), dst);
diff --git a/src/jit/emitarm.h b/src/jit/emitarm.h
index fe24007ef9..1e79af0fed 100644
--- a/src/jit/emitarm.h
+++ b/src/jit/emitarm.h
@@ -267,7 +267,7 @@ void emitIns_C(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fdlHnd, int
void emitIns_S(instruction ins, emitAttr attr, int varx, int offs);
-void emitIns_genStackOffset(regNumber r, int varx, int offs);
+void emitIns_genStackOffset(regNumber r, int varx, int offs, bool isFloatUsage);
void emitIns_S_R(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
diff --git a/src/jit/lclvars.cpp b/src/jit/lclvars.cpp
index 339f7a5ff7..e58130bd5b 100644
--- a/src/jit/lclvars.cpp
+++ b/src/jit/lclvars.cpp
@@ -6722,7 +6722,7 @@ void Compiler::lvaDumpFrameLocation(unsigned lclNum)
regNumber baseReg;
#ifdef _TARGET_ARM_
- offset = lvaFrameAddress(lclNum, compLocallocUsed, &baseReg, 0);
+ offset = lvaFrameAddress(lclNum, compLocallocUsed, &baseReg, 0, /* isFloatUsage */ false);
#else
bool EBPbased;
offset = lvaFrameAddress(lclNum, &EBPbased);
diff --git a/tests/arm/corefx_linux_test_exclusions.txt b/tests/arm/corefx_linux_test_exclusions.txt
index 46698e07b0..907f404840 100644
--- a/tests/arm/corefx_linux_test_exclusions.txt
+++ b/tests/arm/corefx_linux_test_exclusions.txt
@@ -11,7 +11,6 @@ System.Memory.Tests # https://github.com/dotnet/coreclr/issues/
System.Net.Http.Functional.Tests # https://github.com/dotnet/coreclr/issues/17739
System.Net.NameResolution.Functional.Tests # https://github.com/dotnet/coreclr/issues/21224 -- JitStressRegs=1
System.Net.NameResolution.Pal.Tests # https://github.com/dotnet/coreclr/issues/17740
-System.Numerics.Vectors.Tests # https://github.com/dotnet/coreclr/issues/19537
System.Runtime.Tests # https://github.com/dotnet/coreclr/issues/21223 -- JitStress=2
System.Text.Encodings.Web.Tests # https://github.com/dotnet/coreclr/issues/21113 -- minopts
System.Text.Json.Tests # https://github.com/dotnet/coreclr/issues/21112
diff --git a/tests/arm/corefx_test_exclusions.txt b/tests/arm/corefx_test_exclusions.txt
index 315a175658..3667a3b84a 100644
--- a/tests/arm/corefx_test_exclusions.txt
+++ b/tests/arm/corefx_test_exclusions.txt
@@ -11,6 +11,5 @@ System.IO.Ports.Tests # https://github.com/dotnet/coreclr/issues/
System.Management.Tests # https://github.com/dotnet/coreclr/issues/16001
System.Linq.Expressions.Tests # JitStress=1 https://github.com/dotnet/coreclr/issues/19457
System.Net.HttpListener.Tests # https://github.com/dotnet/coreclr/issues/17584
-System.Numerics.Vectors.Tests # https://github.com/dotnet/coreclr/issues/19537
System.Runtime.Numerics.Tests # https://github.com/dotnet/coreclr/issues/18362 -- JitStress=1 JitStress=2
System.Text.RegularExpressions.Tests # https://github.com/dotnet/coreclr/issues/17754 -- timeout -- JitMinOpts only
diff --git a/tests/issues.targets b/tests/issues.targets
index 219139bd15..d40d94ef3c 100644
--- a/tests/issues.targets
+++ b/tests/issues.targets
@@ -196,12 +196,6 @@
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/JitBlue/devdiv_902271/DevDiv_902271/*">
<Issue>times out</Issue>
</ExcludeList>
- <ExcludeList Include="$(XunitTestBinBase)/JIT/SIMD/Matrix4x4_r/*">
- <Issue>19537</Issue>
- </ExcludeList>
- <ExcludeList Include="$(XunitTestBinBase)/JIT/SIMD/Matrix4x4_ro/*">
- <Issue>19537</Issue>
- </ExcludeList>
</ItemGroup>
<!-- Arm64 All OS -->
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_19537/GitHub_19537.cs b/tests/src/JIT/Regression/JitBlue/GitHub_19537/GitHub_19537.cs
new file mode 100644
index 0000000000..9c0de17c87
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_19537/GitHub_19537.cs
@@ -0,0 +1,417 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Collections.Generic;
+
+// Test derived from dotnet/corefx src\System.Numerics.Vectors\src\System\Numerics\Matrix4x4.cs, op_Multiply().
+// This was an ARM32-specific bug for addressing local variables as floats. ARM32 floating-point instructions
+// have a different offset range than integer instructions. If the local variable itself is a struct, but the
+// instruction generated is a float local field, then we were computing the offset as integer, but the actual
+// instruction was float. In certain frame layouts, the range will be out of range in this case, but we will
+// not have allocated a "reserved" register which is used for generating large offsets.
+//
+// The key functions in the JIT that are related are Compiler::compRsvdRegCheck() and Compiler::lvaFrameAddress().
+
+public class Test
+{
+ public struct BigStruct
+ {
+ public float float1;
+ public float float2;
+ public float float3;
+ public float float4;
+ public float float5;
+ public float float6;
+ public float float7;
+ public float float8;
+ public float float9;
+ public float float10;
+ public float float11;
+ public float float12;
+ public float float13;
+ public float float14;
+ public float float15;
+ public float float16;
+ public float float17;
+ public float float18;
+ public float float19;
+ public float float20;
+ public float float21;
+ public float float22;
+ public float float23;
+ public float float24;
+ public float float25;
+ public float float26;
+ public float float27;
+ public float float28;
+ public float float29;
+ public float float30;
+ public float float31;
+ public float float32;
+ public float float33;
+ public float float34;
+ public float float35;
+ public float float36;
+ public float float37;
+ public float float38;
+ public float float39;
+ public float float40;
+ public float float41;
+ public float float42;
+ public float float43;
+ public float float44;
+ public float float45;
+ public float float46;
+ public float float47;
+ public float float48;
+ public float float49;
+ public float float50;
+ public float float51;
+ public float float52;
+ public float float53;
+ public float float54;
+ public float float55;
+ public float float56;
+ public float float57;
+ public float float58;
+ public float float59;
+ public float float60;
+ public float float61;
+ public float float62;
+ public float float63;
+ public float float64;
+ public float float65;
+ public float float66;
+ public float float67;
+ public float float68;
+ public float float69;
+ public float float70;
+ public float float71;
+ public float float72;
+ public float float73;
+ public float float74;
+ public float float75;
+ public float float76;
+ public float float77;
+ public float float78;
+ public float float79;
+ public float float80;
+ public float float81;
+ public float float82;
+ public float float83;
+ public float float84;
+ public float float85;
+ public float float86;
+ public float float87;
+ public float float88;
+ public float float89;
+ public float float90;
+ public float float91;
+ public float float92;
+ public float float93;
+ public float float94;
+ public float float95;
+ public float float96;
+ public float float97;
+ public float float98;
+ public float float99;
+ public float float100;
+ public float float101;
+ public float float102;
+ public float float103;
+ public float float104;
+ public float float105;
+ public float float106;
+ public float float107;
+ public float float108;
+ public float float109;
+ public float float110;
+ public float float111;
+ public float float112;
+ public float float113;
+ public float float114;
+ public float float115;
+ public float float116;
+ public float float117;
+ public float float118;
+ public float float119;
+ public float float120;
+ public float float121;
+ public float float122;
+ public float float123;
+ public float float124;
+ public float float125;
+ public float float126;
+ public float float127;
+ public float float128;
+ public float float129;
+ public float float130;
+ public float float131;
+ public float float132;
+ public float float133;
+ public float float134;
+ public float float135;
+ public float float136;
+ public float float137;
+ public float float138;
+ public float float139;
+ public float float140;
+ public float float141;
+ public float float142;
+ public float float143;
+ public float float144;
+ public float float145;
+ public float float146;
+ public float float147;
+ public float float148;
+ public float float149;
+ public float float150;
+ public float float151;
+ public float float152;
+ public float float153;
+ public float float154;
+ public float float155;
+ public float float156;
+ public float float157;
+ public float float158;
+ public float float159;
+ public float float160;
+ public float float161;
+ public float float162;
+ public float float163;
+ public float float164;
+ public float float165;
+ public float float166;
+ public float float167;
+ public float float168;
+ public float float169;
+ public float float170;
+ public float float171;
+ public float float172;
+ public float float173;
+ public float float174;
+ public float float175;
+ public float float176;
+ public float float177;
+ public float float178;
+ public float float179;
+ public float float180;
+ public float float181;
+ public float float182;
+ public float float183;
+ public float float184;
+ public float float185;
+ public float float186;
+ public float float187;
+ public float float188;
+ public float float189;
+ public float float190;
+ public float float191;
+ public float float192;
+ public float float193;
+ public float float194;
+ public float float195;
+ public float float196;
+ public float float197;
+ public float float198;
+ public float float199;
+ public float float200;
+ public float float201;
+ public float float202;
+ public float float203;
+ public float float204;
+ public float float205;
+ public float float206;
+ public float float207;
+ public float float208;
+ public float float209;
+ public float float210;
+ public float float211;
+ public float float212;
+ public float float213;
+ public float float214;
+ public float float215;
+ public float float216;
+ public float float217;
+ public float float218;
+ public float float219;
+ public float float220;
+ public float float221;
+ public float float222;
+ public float float223;
+ public float float224;
+ public float float225;
+ public float float226;
+ public float float227;
+ public float float228;
+ public float float229;
+ public float float230;
+ public float float231;
+ public float float232;
+ public float float233;
+ public float float234;
+ public float float235;
+ public float float236;
+ public float float237;
+ public float float238;
+ public float float239;
+ public float float240;
+ public float float241;
+ public float float242;
+ public float float243;
+ public float float244;
+ public float float245;
+ public float float246;
+ public float float247;
+ public float float248;
+ public float float249;
+ public float float250;
+ public float float251;
+ public float float252;
+ public float float253;
+ public float float254;
+ public float float255;
+ }
+
+ public struct Matrix4x4
+ {
+ public float M11;
+ public float M12;
+ public float M13;
+ public float M14;
+
+ public float M21;
+ public float M22;
+ public float M23;
+ public float M24;
+
+ public float M31;
+ public float M32;
+ public float M33;
+ public float M34;
+
+ public float M41;
+ public float M42;
+ public float M43;
+ public float M44;
+
+ /// <summary>
+ /// Constructs a Matrix4x4 from the given components.
+ /// </summary>
+ public Matrix4x4(float m11, float m12, float m13, float m14,
+ float m21, float m22, float m23, float m24,
+ float m31, float m32, float m33, float m34,
+ float m41, float m42, float m43, float m44)
+ {
+ this.M11 = m11;
+ this.M12 = m12;
+ this.M13 = m13;
+ this.M14 = m14;
+
+ this.M21 = m21;
+ this.M22 = m22;
+ this.M23 = m23;
+ this.M24 = m24;
+
+ this.M31 = m31;
+ this.M32 = m32;
+ this.M33 = m33;
+ this.M34 = m34;
+
+ this.M41 = m41;
+ this.M42 = m42;
+ this.M43 = m43;
+ this.M44 = m44;
+ }
+
+ /// <summary>
+ /// Returns a boolean indicating whether the given two matrices are equal.
+ /// </summary>
+ /// <param name="value1">The first matrix to compare.</param>
+ /// <param name="value2">The second matrix to compare.</param>
+ /// <returns>True if the given matrices are equal; False otherwise.</returns>
+ public static bool Equals(Matrix4x4 value1, Matrix4x4 value2)
+ {
+ return (value1.M11 == value2.M11 && value1.M22 == value2.M22 && value1.M33 == value2.M33 && value1.M44 == value2.M44 && // Check diagonal element first for early out.
+ value1.M12 == value2.M12 && value1.M13 == value2.M13 && value1.M14 == value2.M14 && value1.M21 == value2.M21 &&
+ value1.M23 == value2.M23 && value1.M24 == value2.M24 && value1.M31 == value2.M31 && value1.M32 == value2.M32 &&
+ value1.M34 == value2.M34 && value1.M41 == value2.M41 && value1.M42 == value2.M42 && value1.M43 == value2.M43);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void AddHelper(ref BigStruct b)
+ {
+ b.float1 += 1.0F;
+ b.float255 += 2.0F;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static Matrix4x4 AddTest(Matrix4x4 value1, Matrix4x4 value2)
+ {
+ BigStruct b = new BigStruct();
+
+ b.float1 = value1.M11 + value2.M11;
+ b.float255 = value1.M12 + value2.M12;
+
+ AddHelper(ref b);
+
+ Matrix4x4 m;
+
+ m = value1;
+ m.M11 = b.float1 + b.float255;
+ m.M12 = b.float1 - b.float255;
+
+ return m;
+ }
+
+ /// <summary>
+ /// Returns a String representing this matrix instance.
+ /// </summary>
+ /// <returns>The string representation.</returns>
+ public override string ToString()
+ {
+ return string.Format("{{ {{M11:{0} M12:{1} M13:{2} M14:{3}}} {{M21:{4} M22:{5} M23:{6} M24:{7}}} {{M31:{8} M32:{9} M33:{10} M34:{11}}} {{M41:{12} M42:{13} M43:{14} M44:{15}}} }}",
+ M11, M12, M13, M14,
+ M21, M22, M23, M24,
+ M31, M32, M33, M34,
+ M41, M42, M43, M44);
+ }
+
+ public static int Main()
+ {
+ Matrix4x4 m1 = new Matrix4x4(1.0F,2.0F,3.0F,4.0F,
+ 5.0F,6.0F,7.0F,8.0F,
+ 9.0F,10.0F,11.0F,12.0F,
+ 13.0F,14.0F,15.0F,16.0F);
+ Matrix4x4 m2 = new Matrix4x4(13.0F,14.0F,15.0F,16.0F,
+ 9.0F,10.0F,11.0F,12.0F,
+ 5.0F,6.0F,7.0F,8.0F,
+ 1.0F,2.0F,3.0F,4.0F);
+
+ Matrix4x4 m3 = AddTest(m1,m2);
+
+ Matrix4x4 mresult = new Matrix4x4(33.0F,-3.0F,3.0F,4.0F,
+ 5.0F,6.0F,7.0F,8.0F,
+ 9.0F,10.0F,11.0F,12.0F,
+ 13.0F,14.0F,15.0F,16.0F);
+ if (Equals(m3,mresult))
+ {
+ Console.WriteLine("PASS");
+ return 100;
+ }
+ else
+ {
+ Console.WriteLine("FAIL: matrices don't match");
+ Console.WriteLine(" m3 = {0}", m3.ToString());
+ Console.WriteLine(" mresult = {0}", mresult.ToString());
+ return 1;
+ }
+ }
+
+ }
+}
+
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_19537/GitHub_19537.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_19537/GitHub_19537.csproj
new file mode 100644
index 0000000000..3f44b60d19
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_19537/GitHub_19537.csproj
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{2649FAFE-07BF-4F93-8120-BA9A69285ABB}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <CLRTestPriority>1</CLRTestPriority>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "></PropertyGroup>
+ <PropertyGroup>
+ <DebugType>None</DebugType>
+ <Optimize>True</Optimize>
+ <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
+ </PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildProjectName).cs" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
+</Project>