diff --git a/src/jit/compiler.cpp b/src/jit/compiler.cpp index 868e0ce6f5c8..5e8088d2c476 100644 --- a/src/jit/compiler.cpp +++ b/src/jit/compiler.cpp @@ -1004,37 +1004,57 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, assert(structSize > 0); #ifdef UNIX_AMD64_ABI - // An 8-byte struct may need to be returned in a floating point register // So we always consult the struct "Classifier" routine // SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc; eeGetSystemVAmd64PassStructInRegisterDescriptor(clsHnd, &structDesc); - // If we have one eightByteCount then we can set 'useType' based on that if (structDesc.eightByteCount == 1) { - // Set 'useType' to the type of the first eightbyte item - useType = GetEightByteType(structDesc, 0); - assert(structDesc.passedInRegisters == true); + assert(structSize <= sizeof(double)); + + if (structDesc.eightByteClassifications[0] == SystemVClassificationTypeSSE) + { + // If this is returned as a floating type, use that. + // Otherwise, leave as TYP_UNKONWN and we'll sort things out below. + useType = GetEightByteType(structDesc, 0); + howToReturnStruct = SPK_PrimitiveType; + } } -#else // not UNIX_AMD64 +#endif // UNIX_AMD64_ABI + // Check for cases where a small struct is returned in a register + // via a primitive type. + // // The largest primitive type is 8 bytes (TYP_DOUBLE) // so we can skip calling getPrimitiveTypeForStruct when we // have a struct that is larger than that. - // - if (structSize <= sizeof(double)) + if ((useType == TYP_UNKNOWN) && (structSize <= sizeof(double))) { // We set the "primitive" useType based upon the structSize // and also examine the clsHnd to see if it is an HFA of count one // - // The ABI for struct returns in varArg methods, is same as the normal case, so pass false for isVararg + // The ABI for struct returns in varArg methods, is same as the normal case, + // so pass false for isVararg useType = getPrimitiveTypeForStruct(structSize, clsHnd, /*isVararg=*/false); - } -#endif // UNIX_AMD64_ABI + if (useType != TYP_UNKNOWN) + { + if (structSize == genTypeSize(useType)) + { + // Currently: 1, 2, 4, or 8 byte structs + howToReturnStruct = SPK_PrimitiveType; + } + else + { + // Currently: 3, 5, 6, or 7 byte structs + assert(structSize < genTypeSize(useType)); + howToReturnStruct = SPK_EnclosingType; + } + } + } #ifdef _TARGET_64BIT_ // Note this handles an odd case when FEATURE_MULTIREG_RET is disabled and HFAs are enabled @@ -1048,16 +1068,16 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, // if ((FEATURE_MULTIREG_RET == 0) && (useType == TYP_UNKNOWN) && (structSize == (2 * sizeof(float))) && IsHfa(clsHnd)) { - useType = TYP_I_IMPL; + useType = TYP_I_IMPL; + howToReturnStruct = SPK_PrimitiveType; } #endif // Did we change this struct type into a simple "primitive" type? - // if (useType != TYP_UNKNOWN) { - // Yes, we should use the "primitive" type in 'useType' - howToReturnStruct = SPK_PrimitiveType; + // If so, we should have already set howToReturnStruct, too. + assert(howToReturnStruct != SPK_Unknown); } else // We can't replace the struct with a "primitive" type { diff --git a/src/jit/compiler.h b/src/jit/compiler.h index 2e8d27d71a0d..eb92395f7abf 100644 --- a/src/jit/compiler.h +++ b/src/jit/compiler.h @@ -1691,6 +1691,8 @@ class Compiler GenTree* impAssignMultiRegTypeToVar(GenTree* op, CORINFO_CLASS_HANDLE hClass); #endif // FEATURE_MULTIREG_RET + GenTree* impAssignSmallStructTypeToVar(GenTree* op, CORINFO_CLASS_HANDLE hClass); + #ifdef ARM_SOFTFP bool isSingleFloat32Struct(CORINFO_CLASS_HANDLE hClass); #endif // ARM_SOFTFP @@ -4223,6 +4225,9 @@ class Compiler { SPK_Unknown, // Invalid value, never returned SPK_PrimitiveType, // The struct is passed/returned using a primitive type. + SPK_EnclosingType, // Like SPK_Primitive type, but used for return types that + // require a primitive type temp that is larger than the struct size. + // Currently used for structs of size 3, 5, 6, or 7 bytes. SPK_ByValue, // The struct is passed/returned by value (using the ABI rules) // for ARM64 and UNIX_X64 in multiple registers. (when all of the // parameters registers are used, then the stack will be used) diff --git a/src/jit/flowgraph.cpp b/src/jit/flowgraph.cpp index a852fb315f64..197af3100b53 100644 --- a/src/jit/flowgraph.cpp +++ b/src/jit/flowgraph.cpp @@ -22324,33 +22324,113 @@ Compiler::fgWalkResult Compiler::fgUpdateInlineReturnExpressionPlaceHolder(GenTr } } -#if FEATURE_MULTIREG_RET - - // Did we record a struct return class handle above? + // If an inline was rejected and the call returns a struct, we may + // have deferred some work when importing call for cases where the + // struct is returned in register(s). + // + // See the bail-out clauses in impFixupCallStructReturn for inline + // candidates. // + // Do the deferred work now. if (retClsHnd != NO_CLASS_HANDLE) { - // Is this a type that is returned in multiple registers? - // if so we need to force into into a form we accept. - // i.e. LclVar = call() - // - if (comp->IsMultiRegReturnedType(retClsHnd)) + structPassingKind howToReturnStruct; + var_types returnType = comp->getReturnTypeForStruct(retClsHnd, &howToReturnStruct); + GenTree* parent = data->parent; + + switch (howToReturnStruct) { - GenTree* parent = data->parent; - // See assert below, we only look one level above for an asg parent. - if (parent->gtOper == GT_ASG) + +#if FEATURE_MULTIREG_RET + + // Is this a type that is returned in multiple registers + // or a via a primitve type that is larger than the struct type? + // if so we need to force into into a form we accept. + // i.e. LclVar = call() + case SPK_ByValue: + case SPK_ByValueAsHfa: { - // Either lhs is a call V05 = call(); or lhs is addr, and asg becomes a copyBlk. - comp->fgAttachStructInlineeToAsg(parent, tree, retClsHnd); + // See assert below, we only look one level above for an asg parent. + if (parent->gtOper == GT_ASG) + { + // Either lhs is a call V05 = call(); or lhs is addr, and asg becomes a copyBlk. + comp->fgAttachStructInlineeToAsg(parent, tree, retClsHnd); + } + else + { + // Just assign the inlinee to a variable to keep it simple. + tree->ReplaceWith(comp->fgAssignStructInlineeToVar(tree, retClsHnd), comp); + } } - else + break; + +#endif // FEATURE_MULTIREG_RET + + case SPK_EnclosingType: { - // Just assign the inlinee to a variable to keep it simple. - tree->ReplaceWith(comp->fgAssignStructInlineeToVar(tree, retClsHnd), comp); + // For enclosing type returns, we must return the call value to a temp since + // the return type is larger than the struct type. + if (!tree->IsCall()) + { + break; + } + + GenTreeCall* call = tree->AsCall(); + + assert(call->gtReturnType == TYP_STRUCT); + + if (call->gtReturnType != TYP_STRUCT) + { + break; + } + + JITDUMP("\nCall returns small struct via enclosing type, retyping. Before:\n"); + DISPTREE(call); + + // Create new struct typed temp for return value + const unsigned tmpNum = + comp->lvaGrabTemp(true DEBUGARG("small struct return temp for rejected inline")); + comp->lvaSetStruct(tmpNum, retClsHnd, false); + GenTree* assign = comp->gtNewTempAssign(tmpNum, call); + + // Modify assign tree and call return types to the primitive return type + call->gtReturnType = returnType; + call->gtType = returnType; + assign->gtType = returnType; + + // Modify the temp reference in the assign as a primitive reference via GT_LCL_FLD + GenTree* tempAsPrimitive = assign->gtOp.gtOp1; + assert(tempAsPrimitive->gtOper == GT_LCL_VAR); + tempAsPrimitive->gtType = returnType; + tempAsPrimitive->ChangeOper(GT_LCL_FLD); + + // Return temp as value of call tree via comma + GenTree* tempAsStruct = comp->gtNewLclvNode(tmpNum, TYP_STRUCT); + GenTree* comma = comp->gtNewOperNode(GT_COMMA, TYP_STRUCT, assign, tempAsStruct); + parent->ReplaceOperand(pTree, comma); + + JITDUMP("\nAfter:\n"); + DISPTREE(comma); } + break; + + case SPK_PrimitiveType: + // We should have already retyped the call as a primitive type + // when we first imported the call + break; + + case SPK_ByReference: + // We should have already added the return buffer + // when we first imported the call + break; + + default: + noway_assert(!"Unexpected struct passing kind"); + break; } } +#if FEATURE_MULTIREG_RET #if defined(DEBUG) // Make sure we don't have a tree like so: V05 = (, , , retExpr); diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp index e1bc249cdfca..bba58cbecf8f 100644 --- a/src/jit/gentree.cpp +++ b/src/jit/gentree.cpp @@ -17679,6 +17679,10 @@ void ReturnTypeDesc::InitializeStructReturnType(Compiler* comp, CORINFO_CLASS_HA switch (howToReturnStruct) { + case Compiler::SPK_EnclosingType: + m_isEnclosingType = true; + __fallthrough; + case Compiler::SPK_PrimitiveType: { assert(returnType != TYP_UNKNOWN); diff --git a/src/jit/gentree.h b/src/jit/gentree.h index 4baed55b6b5c..e59b79d9c8c5 100644 --- a/src/jit/gentree.h +++ b/src/jit/gentree.h @@ -3089,6 +3089,7 @@ struct ReturnTypeDesc { private: var_types m_regType[MAX_RET_REG_COUNT]; + bool m_isEnclosingType; #ifdef DEBUG bool m_inited; @@ -3114,6 +3115,7 @@ struct ReturnTypeDesc { m_regType[i] = TYP_UNKNOWN; } + m_isEnclosingType = false; #ifdef DEBUG m_inited = false; #endif @@ -3206,6 +3208,13 @@ struct ReturnTypeDesc return result; } + // True if this value is returned in integer register + // that is larger than the type itself. + bool IsEnclosingType() const + { + return m_isEnclosingType; + } + // Get ith ABI return register regNumber GetABIReturnReg(unsigned idx); diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp index 1b2e35771810..74f48083d20d 100644 --- a/src/jit/importer.cpp +++ b/src/jit/importer.cpp @@ -8464,8 +8464,24 @@ GenTree* Compiler::impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HAN { if (retRegCount == 1) { - // struct returned in a single register - call->gtReturnType = retTypeDesc->GetReturnRegType(0); + // See if the struct size is smaller than the return + // type size... + if (retTypeDesc->IsEnclosingType()) + { + // If we know for sure this call will remain a call, + // retype and return value via a suitable temp. + if ((!call->CanTailCall()) && (!call->IsInlineCandidate())) + { + call->gtReturnType = retTypeDesc->GetReturnRegType(0); + return impAssignSmallStructTypeToVar(call, retClsHnd); + } + } + else + { + // Return type is same size as struct, so we can + // simply retype the call. + call->gtReturnType = retTypeDesc->GetReturnRegType(0); + } } else { @@ -8507,7 +8523,25 @@ GenTree* Compiler::impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HAN else { assert(returnType != TYP_UNKNOWN); - call->gtReturnType = returnType; + + // See if the struct size is smaller than the return + // type size... + if (howToReturnStruct == SPK_EnclosingType) + { + // If we know for sure this call will remain a call, + // retype and return value via a suitable temp. + if ((!call->CanTailCall()) && (!call->IsInlineCandidate())) + { + call->gtReturnType = returnType; + return impAssignSmallStructTypeToVar(call, retClsHnd); + } + } + else + { + // Return type is same size as struct, so we can + // simply retype the call. + call->gtReturnType = returnType; + } // ToDo: Refactor this common code sequence into its own method as it is used 4+ times if ((returnType == TYP_LONG) && (compLongUsed == false)) @@ -8555,6 +8589,9 @@ GenTree* Compiler::impFixupStructReturnType(GenTree* op, CORINFO_CLASS_HANDLE re assert(varTypeIsStruct(info.compRetType)); assert(info.compRetBuffArg == BAD_VAR_NUM); + JITDUMP("\nimpFixupStructReturnType: retyping\n"); + DISPTREE(op); + #if defined(_TARGET_XARCH_) #ifdef UNIX_AMD64_ABI @@ -8725,9 +8762,7 @@ GenTree* Compiler::impFixupStructReturnType(GenTree* op, CORINFO_CLASS_HANDLE re } else { - assert(info.compRetNativeType == op->gtCall.gtReturnType); - - // Don't change the gtType of the node just yet, it will get changed later. + // Don't change the gtType of the call just yet, it will get changed later. return op; } } @@ -8750,6 +8785,9 @@ GenTree* Compiler::impFixupStructReturnType(GenTree* op, CORINFO_CLASS_HANDLE re op->gtType = info.compRetNativeType; + JITDUMP("\nimpFixupStructReturnType: result of retyping is\n"); + DISPTREE(op); + return op; } @@ -15647,7 +15685,45 @@ void Compiler::impMarkLclDstNotPromotable(unsigned tmpNum, GenTree* src, CORINFO } #endif // _TARGET_ARM_ +//------------------------------------------------------------------------ +// impAssignSmallStructTypeToVar: ensure calls that return small structs whose +// sizes are not supported integral type sizes return values to temps. +// +// Arguments: +// op -- call returning a small struct in a register +// hClass -- class handle for struct +// +// Returns: +// Tree with reference to struct local to use as call return value. +// +// Remarks: +// The call will be spilled into a preceding statement. +// Currently handles struct returns for 3, 5, 6, and 7 byte structs. + +GenTree* Compiler::impAssignSmallStructTypeToVar(GenTree* op, CORINFO_CLASS_HANDLE hClass) +{ + unsigned tmpNum = lvaGrabTemp(true DEBUGARG("Return value temp for small struct return.")); + impAssignTempGen(tmpNum, op, hClass, (unsigned)CHECK_SPILL_ALL); + GenTree* ret = gtNewLclvNode(tmpNum, lvaTable[tmpNum].lvType); + + // TODO-1stClassStructs: Handle constant propagation and CSE-ing of small struct returns. + ret->gtFlags |= GTF_DONT_CSE; + + return ret; +} + #if FEATURE_MULTIREG_RET +//------------------------------------------------------------------------ +// impAssignMultiRegTypeToVar: ensure calls that return structs in multiple +// registers return values to suitable temps. +// +// Arguments: +// op -- call returning a struct in a registers +// hClass -- class handle for struct +// +// Returns: +// Tree with reference to struct local to use as call return value. + GenTree* Compiler::impAssignMultiRegTypeToVar(GenTree* op, CORINFO_CLASS_HANDLE hClass) { unsigned tmpNum = lvaGrabTemp(true DEBUGARG("Return value temp for multireg return.")); diff --git a/src/jit/lclvars.cpp b/src/jit/lclvars.cpp index b36fcad94164..eb6545f8e944 100644 --- a/src/jit/lclvars.cpp +++ b/src/jit/lclvars.cpp @@ -141,7 +141,8 @@ void Compiler::lvaInitTypeRef() Compiler::structPassingKind howToReturnStruct; var_types returnType = getReturnTypeForStruct(retClsHnd, &howToReturnStruct); - if (howToReturnStruct == SPK_PrimitiveType) + // We can safely widen the return type for enclosed structs. + if ((howToReturnStruct == SPK_PrimitiveType) || (howToReturnStruct == SPK_EnclosingType)) { assert(returnType != TYP_UNKNOWN); assert(!varTypeIsStruct(returnType)); diff --git a/tests/arm/Tests.lst b/tests/arm/Tests.lst index 9e96a1eb994d..db556779e9dc 100644 --- a/tests/arm/Tests.lst +++ b/tests/arm/Tests.lst @@ -94740,3 +94740,67 @@ MaxAllowedDurationSeconds=600 Categories=EXPECTED_PASS HostStyle=0 +[GitHub_18522.cmd_11903] +RelativePath=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522\GitHub_18522.cmd +WorkingDir=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522 +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS +HostStyle=0 + +[GitHub_18522_1.cmd_11904] +RelativePath=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_1\GitHub_18522_1.cmd +WorkingDir=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_1 +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS +HostStyle=0 + +[GitHub_18522_2.cmd_11905] +RelativePath=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_2\GitHub_18522_2.cmd +WorkingDir=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_2 +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS +HostStyle=0 + +[GitHub_18522_3.cmd_11906] +RelativePath=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_3\GitHub_18522_3.cmd +WorkingDir=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_3 +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS +HostStyle=0 + +[GitHub_18522_4.cmd_11907] +RelativePath=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_4\GitHub_18522_4.cmd +WorkingDir=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_4 +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS +HostStyle=0 + +[GitHub_18522_5.cmd_11908] +RelativePath=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_5\GitHub_18522_5.cmd +WorkingDir=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_5 +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS +HostStyle=0 + +[GitHub_18522_6.cmd_11909] +RelativePath=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_6\GitHub_18522_6.cmd +WorkingDir=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_6 +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS +HostStyle=0 + +[GitHub_18522_7.cmd_11910] +RelativePath=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_7\GitHub_18522_7.cmd +WorkingDir=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_7 +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS +HostStyle=0 + diff --git a/tests/arm64/Tests.lst b/tests/arm64/Tests.lst index a9a732053a00..4d7592873474 100644 --- a/tests/arm64/Tests.lst +++ b/tests/arm64/Tests.lst @@ -94763,3 +94763,67 @@ Expected=0 MaxAllowedDurationSeconds=600 Categories=EXPECTED_PASS HostStyle=0 + +[GitHub_18522.cmd_12223] +RelativePath=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522\GitHub_18522.cmd +WorkingDir=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522 +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS +HostStyle=0 + +[GitHub_18522_1.cmd_12224] +RelativePath=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_1\GitHub_18522_1.cmd +WorkingDir=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_1 +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS +HostStyle=0 + +[GitHub_18522_2.cmd_12225] +RelativePath=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_2\GitHub_18522_2.cmd +WorkingDir=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_2 +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS +HostStyle=0 + +[GitHub_18522_3.cmd_12226] +RelativePath=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_3\GitHub_18522_3.cmd +WorkingDir=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_3 +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS +HostStyle=0 + +[GitHub_18522_4.cmd_12227] +RelativePath=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_4\GitHub_18522_4.cmd +WorkingDir=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_4 +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS +HostStyle=0 + +[GitHub_18522_5.cmd_12228] +RelativePath=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_5\GitHub_18522_5.cmd +WorkingDir=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_5 +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS +HostStyle=0 + +[GitHub_18522_6.cmd_12229] +RelativePath=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_6\GitHub_18522_6.cmd +WorkingDir=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_6 +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS +HostStyle=0 + +[GitHub_18522_7.cmd_12230] +RelativePath=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_7\GitHub_18522_7.cmd +WorkingDir=JIT\Regression\JitBlue\GitHub_18522\GitHub_18522_7 +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS +HostStyle=0 diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522.cs b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522.cs new file mode 100644 index 000000000000..8cbcc6e5b8b1 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522.cs @@ -0,0 +1,39 @@ +// 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; + +// Based on a program generated by Fuzzlyn + +struct S0 +{ + public ushort F0; +} + +struct S1 +{ + public S0 F0; + public ushort F1; +} + +public class GitHub_18522 +{ + static S1 s_36; + + // When generating code for the x64 SysV ABI, the jit was + // incorrectly typing the return type from M113, and so + // inadvertently overwriting the F1 field of s_36 on return from + // the (inlined) call. + public static int Main() + { + s_36.F1 = 0xAA; + s_36.F0 = M113(); + return (s_36.F1 == 0xAA ? 100 : 0); + } + + static S0 M113() + { + return new S0(); + } +} diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522.csproj new file mode 100644 index 000000000000..95aba995a255 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522.csproj @@ -0,0 +1,34 @@ + + + + + Debug + AnyCPU + $(MSBuildProjectName) + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + + + + + + + False + + + + + True + + + + + + + + + + diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_1.cs b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_1.cs new file mode 100644 index 000000000000..a5726451fb6c --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_1.cs @@ -0,0 +1,52 @@ +// 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; + +// Based on +// Original generated by Fuzzlyn on 2018-06-20 00:58:58 +// Seed: 11049252875418439527 +// Reduced from 97.5 KiB to 0.5 KiB +// Debug: Outputs -1 +// Release: Outputs -65536 + +struct S0 +{ + public sbyte F0; + public char F1; + public ushort F2; +} + +struct S1 +{ + public short F0; + public S0 F1; + public S0 F2; + public S0 F3; + public int F4; + public S1(int f4): this() + { + F4 = f4; + } +} + +public class GitHub_18522_1 +{ + static S1 s_6; + static S1[] s_13 = new S1[]{new S1(-1)}; + public static int Main() + { + // When generating code for the x64 SysV ABI, the jit was + // incorrectly typing the return type from M16, and so + // inadvertently overwriting the F4 field of s_13[0] on return + // from the (inlined) call. + s_13[0].F3 = M16(); + return s_13[0].F4 == -1 ? 100 : 0; + } + + static S0 M16() + { + return s_6.F3; + } +} diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_1.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_1.csproj new file mode 100644 index 000000000000..95aba995a255 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_1.csproj @@ -0,0 +1,34 @@ + + + + + Debug + AnyCPU + $(MSBuildProjectName) + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + + + + + + + False + + + + + True + + + + + + + + + + diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_2.cs b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_2.cs new file mode 100644 index 000000000000..ab4090d0d369 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_2.cs @@ -0,0 +1,54 @@ +// 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; + +// Based on +// Original generated by Fuzzlyn on 2018-06-20 00:58:58 +// Seed: 11049252875418439527 +// Reduced from 97.5 KiB to 0.5 KiB +// Debug: Outputs -1 +// Release: Outputs -65536 + +struct S0 +{ + public sbyte F0; + public char F1; + public ushort F2; +} + +struct S1 +{ + public short F0; + public S0 F1; + public S0 F2; + public S0 F3; + public int F4; + public S1(int f4): this() + { + F4 = f4; + } +} + +public class GitHub_18522_2 +{ + static S1 s_6; + static S1[] s_13 = new S1[]{new S1(-1)}; + public static int Main() + { + // When generating code for the x64 SysV ABI, the jit was + // incorrectly typing the return type from M16, and so + // inadvertently overwriting the F4 field of s_13[0] on return + // from the (not inlined) call. + s_13[0].F3 = M16(); + return s_13[0].F4 == -1 ? 100 : 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static S0 M16() + { + return s_6.F3; + } +} diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_2.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_2.csproj new file mode 100644 index 000000000000..95aba995a255 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_2.csproj @@ -0,0 +1,34 @@ + + + + + Debug + AnyCPU + $(MSBuildProjectName) + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + + + + + + + False + + + + + True + + + + + + + + + + diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_3.cs b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_3.cs new file mode 100644 index 000000000000..9d6960cfcb76 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_3.cs @@ -0,0 +1,66 @@ +// 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; + +// Based on +// Original generated by Fuzzlyn on 2018-06-20 00:58:58 +// Seed: 11049252875418439527 +// Reduced from 97.5 KiB to 0.5 KiB +// Debug: Outputs -1 +// Release: Outputs -65536 + +struct S0 +{ + public sbyte F0; + public char F1; + public ushort F2; +} + +struct S1 +{ + public short F0; + public S0 F1; + public S0 F2; + public S0 F3; + public int F4; + public S1(int f4): this() + { + F4 = f4; + } +} + +public class GitHub_18522_3 +{ + static S1 s_6; + static S1[] s_13 = new S1[]{new S1(-1)}; + public static int Main() + { + // When generating code for the x64 SysV ABI, the jit was + // incorrectly typing the return type from M16, and so + // inadvertently overwriting the F4 field of s_13[0] on return + // from the call (which was an inline candidate, but not inlined). + s_13[0].F3 = M16(); + return s_13[0].F4 == -1 ? 100 : 0; + } + + static S0 M16() + { + // This bit of code is intended to allow M16 to be an + // inline candidate that ultimately does not get inlined. + short x = 0; + for (int i = 0; i < 10; i++) + { + for (int j = 0; j < 10; j++) + { + x++; + } + } + s_6.F0 = x; + + // Actual interesting part + return s_6.F3; + } +} diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_3.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_3.csproj new file mode 100644 index 000000000000..95aba995a255 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_3.csproj @@ -0,0 +1,34 @@ + + + + + Debug + AnyCPU + $(MSBuildProjectName) + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + + + + + + + False + + + + + True + + + + + + + + + + diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_4.cs b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_4.cs new file mode 100644 index 000000000000..b6f54dc61507 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_4.cs @@ -0,0 +1,62 @@ +// 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; + +// Based on +// Original generated by Fuzzlyn on 2018-06-20 00:58:58 +// Seed: 11049252875418439527 +// Reduced from 97.5 KiB to 0.5 KiB +// Debug: Outputs -1 +// Release: Outputs -65536 + +struct S0 +{ + public sbyte F0; + public char F1; + public ushort F2; +} + +struct S1 +{ + public short F0; + public S0 F1; + public S0 F2; + public S0 F3; + public int F4; + public S1(int f4): this() + { + F4 = f4; + } +} + +public class GitHub_18522_4 +{ + static S1 s_6; + static S1[] s_13 = new S1[]{new S1(-1)}; + public static int Main() + { + // When generating code for the x64 SysV ABI, the jit was + // incorrectly typing the return type from M16, and so + // inadvertently overwriting the F4 field of s_13[0] on return + // from the call. + // + // Here we make sure we properly handle an inline call that + // resolves to a noinline call. + s_13[0].F3 = W(); + return s_13[0].F4 == -1 ? 100 : 0; + } + + static S0 W() + { + return M16(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static S0 M16() + { + return s_6.F3; + } +} diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_4.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_4.csproj new file mode 100644 index 000000000000..95aba995a255 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_4.csproj @@ -0,0 +1,34 @@ + + + + + Debug + AnyCPU + $(MSBuildProjectName) + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + + + + + + + False + + + + + True + + + + + + + + + + diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_5.cs b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_5.cs new file mode 100644 index 000000000000..fdb2a72dc9ca --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_5.cs @@ -0,0 +1,74 @@ +// 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; + +// Based on +// Original generated by Fuzzlyn on 2018-06-20 00:58:58 +// Seed: 11049252875418439527 +// Reduced from 97.5 KiB to 0.5 KiB +// Debug: Outputs -1 +// Release: Outputs -65536 + +struct S0 +{ + public sbyte F0; + public char F1; + public ushort F2; +} + +struct S1 +{ + public short F0; + public S0 F1; + public S0 F2; + public S0 F3; + public int F4; + public S1(int f4): this() + { + F4 = f4; + } +} + +public class GitHub_18522_5 +{ + static S1 s_6; + static S1[] s_13 = new S1[]{new S1(-1)}; + public static int Main() + { + // When generating code for the x64 SysV ABI, the jit was + // incorrectly typing the return type from M16, and so + // inadvertently overwriting the F4 field of s_13[0] on return + // from the call. + // + // Here we make sure we properly handle an inlined call that + // resolves to a rejected inline candidate. + s_13[0].F3 = W(); + return s_13[0].F4 == -1 ? 100 : 0; + } + + static S0 W() + { + return M16(); + } + + static S0 M16() + { + // This bit of code is intended to allow M16 to be an + // inline candidate that ultimately does not get inlined. + short x = 0; + for (int i = 0; i < 10; i++) + { + for (int j = 0; j < 10; j++) + { + x++; + } + } + s_6.F0 = x; + + // Actual interesting part + return s_6.F3; + } +} diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_5.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_5.csproj new file mode 100644 index 000000000000..95aba995a255 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_5.csproj @@ -0,0 +1,34 @@ + + + + + Debug + AnyCPU + $(MSBuildProjectName) + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + + + + + + + False + + + + + True + + + + + + + + + + diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_6.cs b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_6.cs new file mode 100644 index 000000000000..5a3990f509ae --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_6.cs @@ -0,0 +1,61 @@ +// 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; + +// Based on +// Original generated by Fuzzlyn on 2018-06-20 00:58:58 +// Seed: 11049252875418439527 +// Reduced from 97.5 KiB to 0.5 KiB +// Debug: Outputs -1 +// Release: Outputs -65536 + +struct S0 +{ + public sbyte F0; + public char F1; + public ushort F2; +} + +struct S1 +{ + public short F0; + public S0 F1; + public S0 F2; + public S0 F3; + public int F4; + public S1(int f4): this() + { + F4 = f4; + } +} + +public class GitHub_18522_6 +{ + static S1 s_6; + static S1[] s_13 = new S1[]{new S1(-1)}; + public static int Main() + { + // When generating code for the x64 SysV ABI, the jit was + // incorrectly typing the return type from M16, and so + // inadvertently overwriting the F4 field of s_13[0] on return + // from the call. + // + // Here we make sure we properly handle an inlined call that + // resolves to another inlined call. + s_13[0].F3 = W(); + return s_13[0].F4 == -1 ? 100 : 0; + } + + static S0 W() + { + return M16(); + } + + static S0 M16() + { + return s_6.F3; + } +} diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_6.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_6.csproj new file mode 100644 index 000000000000..95aba995a255 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_6.csproj @@ -0,0 +1,34 @@ + + + + + Debug + AnyCPU + $(MSBuildProjectName) + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + + + + + + + False + + + + + True + + + + + + + + + + diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_7.cs b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_7.cs new file mode 100644 index 000000000000..e59d3ded8b19 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_7.cs @@ -0,0 +1,67 @@ +// 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; + +// Based on +// Original generated by Fuzzlyn on 2018-06-20 00:58:58 +// Seed: 11049252875418439527 +// Reduced from 97.5 KiB to 0.5 KiB +// Debug: Outputs -1 +// Release: Outputs -65536 + +// Similar to other variants but using a 3 byte struct instead of 6. + +struct S0 +{ + public byte F0; + public byte F1; + public byte F2; +} + +struct S1 +{ + public S0 F3; + public sbyte F4; + public short F0; + public S1(sbyte f4): this() + { + F4 = f4; + } +} + +public class GitHub_18522_7 +{ + static S1 s_6; + static S1[] s_13 = new S1[]{new S1(-1)}; + public static int Main() + { + // When generating code for the x64 SysV ABI, the jit was + // incorrectly typing the return type from M16, and so + // inadvertently overwriting the F4 field of s_13[0] on return + // from the call. + // + // Here we make sure we properly handle the failed inline case. + s_13[0].F3 = M16(); + return s_13[0].F4 == -1 ? 100 : 0; + } + + static S0 M16() + { + // This bit of code is intended to allow M16 to be an + // inline candidate that ultimately does not get inlined. + short x = 0; + for (int i = 0; i < 10; i++) + { + for (int j = 0; j < 10; j++) + { + x++; + } + } + s_6.F0 = x; + + return s_6.F3; + } +} diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_7.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_7.csproj new file mode 100644 index 000000000000..95aba995a255 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_7.csproj @@ -0,0 +1,34 @@ + + + + + Debug + AnyCPU + $(MSBuildProjectName) + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + + + + + + + False + + + + + True + + + + + + + + + +