diff options
-rw-r--r-- | src/jit/compiler.cpp | 3 | ||||
-rw-r--r-- | src/jit/compiler.h | 2 | ||||
-rw-r--r-- | src/jit/compiler.hpp | 83 | ||||
-rw-r--r-- | src/jit/emit.cpp | 3 | ||||
-rw-r--r-- | src/jit/emitarm.cpp | 23 | ||||
-rw-r--r-- | src/jit/emitarm.h | 2 | ||||
-rw-r--r-- | src/jit/lclvars.cpp | 2 | ||||
-rw-r--r-- | tests/arm/corefx_linux_test_exclusions.txt | 1 | ||||
-rw-r--r-- | tests/arm/corefx_test_exclusions.txt | 1 | ||||
-rw-r--r-- | tests/issues.targets | 6 | ||||
-rw-r--r-- | tests/src/JIT/Regression/JitBlue/GitHub_19537/GitHub_19537.cs | 417 | ||||
-rw-r--r-- | tests/src/JIT/Regression/JitBlue/GitHub_19537/GitHub_19537.csproj | 35 |
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, ®2, offs); + base = emitComp->lvaFrameAddress(varx, emitComp->funCurrentFunc()->funKind != FUNC_ROOT, ®2, 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, ®Base, offs); + base = + emitComp->lvaFrameAddress(varx, emitComp->funCurrentFunc()->funKind != FUNC_ROOT, ®Base, 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, ®2, offs); + base = emitComp->lvaFrameAddress(varx, emitComp->funCurrentFunc()->funKind != FUNC_ROOT, ®2, 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, ®Base, ofs); + int adr = emitComp->lvaFrameAddress(varNum, true, ®Base, 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> |