diff --git a/src/coreclr/src/jit/compiler.h b/src/coreclr/src/jit/compiler.h index e94dc8ad4c9a2f..c3a01feb9d7cec 100644 --- a/src/coreclr/src/jit/compiler.h +++ b/src/coreclr/src/jit/compiler.h @@ -476,8 +476,6 @@ class LclVarDsc unsigned char lvContainsHoles : 1; // True when we have a promoted struct that contains holes unsigned char lvCustomLayout : 1; // True when this struct has "CustomLayout" - unsigned char lvForceLoadNormalize : 1; // True when this local had a cast on the LHS of an assignment - unsigned char lvIsMultiRegArg : 1; // true if this is a multireg LclVar struct used in an argument context unsigned char lvIsMultiRegRet : 1; // true if this is a multireg LclVar struct assigned from a multireg call @@ -886,14 +884,14 @@ class LclVarDsc { return varTypeIsSmall(TypeGet()) && // lvIsStructField is treated the same as the aliased local, see fgDoNormalizeOnStore. - (lvIsParam || lvAddrExposed || lvIsStructField || lvForceLoadNormalize); + (lvIsParam || lvAddrExposed || lvIsStructField); } bool lvNormalizeOnStore() const { return varTypeIsSmall(TypeGet()) && // lvIsStructField is treated the same as the aliased local, see fgDoNormalizeOnStore. - !(lvIsParam || lvAddrExposed || lvIsStructField || lvForceLoadNormalize); + !(lvIsParam || lvAddrExposed || lvIsStructField); } void incRefCnts(BasicBlock::weight_t weight, diff --git a/src/coreclr/src/jit/flowgraph.cpp b/src/coreclr/src/jit/flowgraph.cpp index 48f3273e38eaaa..03e1936224e8b3 100644 --- a/src/coreclr/src/jit/flowgraph.cpp +++ b/src/coreclr/src/jit/flowgraph.cpp @@ -21608,6 +21608,10 @@ void Compiler::fgDebugCheckFlags(GenTree* tree) chkFlags |= GTF_GLOB_REF | GTF_ASG; break; + case GT_LCL_VAR: + assert((tree->gtFlags & GTF_VAR_FOLDED_IND) == 0); + break; + default: break; } diff --git a/src/coreclr/src/jit/gentree.h b/src/coreclr/src/jit/gentree.h index 5c3a94395db6fc..c7d5f2cf3a3a08 100644 --- a/src/coreclr/src/jit/gentree.h +++ b/src/coreclr/src/jit/gentree.h @@ -815,6 +815,9 @@ struct GenTree #define GTF_VAR_ITERATOR 0x00800000 // GT_LCL_VAR -- this is a iterator reference in the loop condition #define GTF_VAR_CLONED 0x00400000 // GT_LCL_VAR -- this node has been cloned or is a clone #define GTF_VAR_CONTEXT 0x00200000 // GT_LCL_VAR -- this node is part of a runtime lookup +#define GTF_VAR_FOLDED_IND 0x00100000 // GT_LCL_VAR -- this node was folded from *(typ*)&lclVar expression tree in fgMorphSmpOp() +// where 'typ' is a small type and 'lclVar' corresponds to a normalized-on-store local variable. +// This flag identifies such nodes in order to make sure that fgDoNormalizeOnStore() is called on their parents in post-order morph. // Relevant for inlining optimizations (see fgInlinePrependStatements) diff --git a/src/coreclr/src/jit/morph.cpp b/src/coreclr/src/jit/morph.cpp index dc5bef62f9c44e..b3547979766860 100644 --- a/src/coreclr/src/jit/morph.cpp +++ b/src/coreclr/src/jit/morph.cpp @@ -12643,6 +12643,13 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) { case GT_ASG: + if (op1->OperIs(GT_LCL_VAR) && ((op1->gtFlags & GTF_VAR_FOLDED_IND) != 0)) + { + op1->gtFlags &= ~GTF_VAR_FOLDED_IND; + tree = fgDoNormalizeOnStore(tree); + op2 = tree->gtGetOp2(); + } + lclVarTree = fgIsIndirOfAddrOfLocal(op1); if (lclVarTree != nullptr) { @@ -13601,17 +13608,16 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) break; case GT_IND: - + { // Can not remove a GT_IND if it is currently a CSE candidate. if (gtIsActiveCSE_Candidate(tree)) { break; } - bool foldAndReturnTemp; - foldAndReturnTemp = false; - temp = nullptr; - ival1 = 0; + bool foldAndReturnTemp = false; + temp = nullptr; + ival1 = 0; // Don't remove a volatile GT_IND, even if the address points to a local variable. if ((tree->gtFlags & GTF_IND_VOLATILE) == 0) @@ -13641,11 +13647,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) unsigned lclNum = temp->AsLclVarCommon()->GetLclNum(); LclVarDsc* varDsc = &lvaTable[lclNum]; - // Note that fgMorph uses GTF_DONT_CSE to mark the left side of an assignment - // Thus stores have this flag and load do not have this flag - // - bool isLoad = (tree->gtFlags & GTF_DONT_CSE) == 0; - // We will try to optimize when we have a promoted struct promoted with a zero lvFldOffset if (varDsc->lvPromoted && (varDsc->lvFldOffset == 0)) { @@ -13675,25 +13676,25 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) // correctly normalized. // // The below transformation cannot be applied if the local var needs to be normalized on load. - else if (varTypeIsSmall(typ) && (genTypeSize(lvaTable[lclNum].lvType) == genTypeSize(typ)) && + else if (varTypeIsSmall(typ) && (genTypeSize(varDsc) == genTypeSize(typ)) && !lvaTable[lclNum].lvNormalizeOnLoad()) { - // For any stores of small types, we will force loads to be normalized - // this is necessary as we need to zero/sign extend any load - // after this kind of store. - // - if (!isLoad) - { - varDsc->lvForceLoadNormalize = true; - } - // otherwise we have a load operation - // - // And for loads signed/unsigned differences do matter. - // - else if (varTypeIsUnsigned(lvaTable[lclNum].lvType) == varTypeIsUnsigned(typ)) + const bool definitelyLoad = (tree->gtFlags & GTF_DONT_CSE) == 0; + const bool possiblyStore = !definitelyLoad; + + if (possiblyStore || (varTypeIsUnsigned(varDsc) == varTypeIsUnsigned(typ))) { - tree->gtType = typ = temp->TypeGet(); - foldAndReturnTemp = true; + typ = temp->TypeGet(); + tree->gtType = typ; + foldAndReturnTemp = true; + + if (possiblyStore) + { + // This node can be on the left-hand-side of an assignment node. + // Mark this node with GTF_VAR_FOLDED_IND to make sure that fgDoNormalizeOnStore() + // is called on its parent in post-order morph. + temp->gtFlags |= GTF_VAR_FOLDED_IND; + } } } // For matching types we can fold @@ -13970,6 +13971,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) } break; + } case GT_ADDR: diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_40607/Runtime_40607.cs b/src/tests/JIT/Regression/JitBlue/Runtime_40607/Runtime_40607.cs new file mode 100644 index 00000000000000..5395a16b4a03bf --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_40607/Runtime_40607.cs @@ -0,0 +1,69 @@ +using System; +using System.Runtime.CompilerServices; + +namespace Runtime_40607 +{ + class Program + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static bool WillBeInlined(out bool shouldBeFalse) + { + shouldBeFalse = false; + return true; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [SkipLocalsInit] + static int DependsOnUnInitValue() + { + int retVal = 1; + bool shouldBeFalse; + + while (WillBeInlined(out shouldBeFalse)) + { + if (shouldBeFalse) + { + retVal = 0; + } + break; + } + + return retVal; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe int PoisonStackWith(uint fillValue) + { + int retVal = 1; + bool shouldBeFalse; + + *(uint*)&shouldBeFalse = fillValue; + + while (WillBeInlined(out shouldBeFalse)) + { + if (shouldBeFalse) + { + retVal = 0; + } + break; + } + + return retVal; + } + + static int Main(string[] args) + { + PoisonStackWith(0xdeadbeef); + + const int expected = 1; + int actual = DependsOnUnInitValue(); + + if (expected != actual) + { + return 0; + } + + return 100; + } + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_40607/Runtime_40607.il b/src/tests/JIT/Regression/JitBlue/Runtime_40607/Runtime_40607.il new file mode 100644 index 00000000000000..ca0106255f1f4b --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_40607/Runtime_40607.il @@ -0,0 +1,705 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +.assembly extern System.Console +{ +} +.assembly extern System.Runtime +{ +} +.assembly Runtime_40607 +{ +} +.module Runtime_40607.dll + +.class private auto ansi beforefieldinit Runtime_40607.Program extends [System.Runtime]System.Object +{ + .method private hidebysig static int32 DependsOnUnInitValue(bool valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (int32 V_0, bool V_1) + + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: br.s IL_000b + + IL_0004: ldloc.1 + IL_0005: brfalse.s IL_0011 + + IL_0007: ldc.i4.0 + IL_0008: stloc.0 + IL_0009: br.s IL_0011 + + IL_000b: ldloca.s V_1 + IL_000d: ldarg.0 + IL_000e: stind.i1 + IL_000f: br.s IL_0004 + + IL_0011: ldloc.0 + IL_0012: ret + } + + .method private hidebysig static int32 DependsOnUnInitValue(int8 valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (int32 V_0, int8 V_1) + + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: br.s IL_000b + + IL_0004: ldloc.1 + IL_0005: brfalse.s IL_0011 + + IL_0007: ldc.i4.0 + IL_0008: stloc.0 + IL_0009: br.s IL_0011 + + IL_000b: ldloca.s V_1 + IL_000d: ldarg.0 + IL_000e: stind.i1 + IL_000f: br.s IL_0004 + + IL_0011: ldloc.0 + IL_0012: ret + } + + .method private hidebysig static int32 DependsOnUnInitValue(uint8 valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (int32 V_0, uint8 V_1) + + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: br.s IL_000b + + IL_0004: ldloc.1 + IL_0005: brfalse.s IL_0011 + + IL_0007: ldc.i4.0 + IL_0008: stloc.0 + IL_0009: br.s IL_0011 + + IL_000b: ldloca.s V_1 + IL_000d: ldarg.0 + IL_000e: stind.i1 + IL_000f: br.s IL_0004 + + IL_0011: ldloc.0 + IL_0012: ret + } + + .method private hidebysig static int32 DependsOnUnInitValue(int16 valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (int32 V_0, int16 V_1) + + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: br.s IL_000b + + IL_0004: ldloc.1 + IL_0005: brfalse.s IL_0011 + + IL_0007: ldc.i4.0 + IL_0008: stloc.0 + IL_0009: br.s IL_0011 + + IL_000b: ldloca.s V_1 + IL_000d: ldarg.0 + IL_000e: stind.i2 + IL_000f: br.s IL_0004 + + IL_0011: ldloc.0 + IL_0012: ret + } + + .method private hidebysig static int32 DependsOnUnInitValue(uint16 valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (int32 V_0, uint16 V_1) + + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: br.s IL_000b + + IL_0004: ldloc.1 + IL_0005: brfalse.s IL_0011 + + IL_0007: ldc.i4.0 + IL_0008: stloc.0 + IL_0009: br.s IL_0011 + + IL_000b: ldloca.s V_1 + IL_000d: ldarg.0 + IL_000e: stind.i2 + IL_000f: br.s IL_0004 + + IL_0011: ldloc.0 + IL_0012: ret + } + + .method private hidebysig static int32 DependsOnUnInitValue(int32 valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (int32 V_0, int32 V_1) + + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: br.s IL_000b + + IL_0004: ldloc.1 + IL_0005: brfalse.s IL_0011 + + IL_0007: ldc.i4.0 + IL_0008: stloc.0 + IL_0009: br.s IL_0011 + + IL_000b: ldloca.s V_1 + IL_000d: ldarg.0 + IL_000e: stind.i4 + IL_000f: br.s IL_0004 + + IL_0011: ldloc.0 + IL_0012: ret + } + + .method private hidebysig static int32 DependsOnUnInitValue(uint32 valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (int32 V_0, uint32 V_1) + + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: br.s IL_000b + + IL_0004: ldloc.1 + IL_0005: brfalse.s IL_0011 + + IL_0007: ldc.i4.0 + IL_0008: stloc.0 + IL_0009: br.s IL_0011 + + IL_000b: ldloca.s V_1 + IL_000d: ldarg.0 + IL_000e: stind.i4 + IL_000f: br.s IL_0004 + + IL_0011: ldloc.0 + IL_0012: ret + } + + .method private hidebysig static int32 SignExtendsWrittenValue(int8 valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (int8 V_0) + + IL_0000: br.s IL_0007 + + IL_0002: ldloca.s V_0 + IL_0004: ldind.i1 + IL_0005: br.s IL_000d + + IL_0007: ldloca.s V_0 + IL_0009: ldarg.0 + IL_000a: stind.i1 + IL_000b: br.s IL_0002 + + IL_000d: ret + } + + .method private hidebysig static int32 ZeroExtendsWrittenValue(int8 valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (int8 V_0) + + IL_0000: br.s IL_0007 + + IL_0002: ldloca.s V_0 + IL_0004: ldind.u1 + IL_0005: br.s IL_000d + + IL_0007: ldloca.s V_0 + IL_0009: ldarg.0 + IL_000a: stind.i1 + IL_000b: br.s IL_0002 + + IL_000d: ret + } + + .method private hidebysig static int32 SignExtendsWrittenValue(uint8 valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (uint8 V_0) + + IL_0000: br.s IL_0007 + + IL_0002: ldloca.s V_0 + IL_0004: ldind.i1 + IL_0005: br.s IL_000d + + IL_0007: ldloca.s V_0 + IL_0009: ldarg.0 + IL_000a: stind.i1 + IL_000b: br.s IL_0002 + + IL_000d: ret + } + + .method private hidebysig static int32 ZeroExtendsWrittenValue(uint8 valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (uint8 V_0) + + IL_0000: br.s IL_0007 + + IL_0002: ldloca.s V_0 + IL_0004: ldind.u1 + IL_0005: br.s IL_000d + + IL_0007: ldloca.s V_0 + IL_0009: ldarg.0 + IL_000a: stind.i1 + IL_000b: br.s IL_0002 + + IL_000d: ret + } + + .method private hidebysig static int32 SignExtendsWrittenValue(int16 valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (int16 V_0) + + IL_0000: br.s IL_0007 + + IL_0002: ldloca.s V_0 + IL_0004: ldind.i2 + IL_0005: br.s IL_000d + + IL_0007: ldloca.s V_0 + IL_0009: ldarg.0 + IL_000a: stind.i2 + IL_000b: br.s IL_0002 + + IL_000d: ret + } + + .method private hidebysig static int32 ZeroExtendsWrittenValue(int16 valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (int16 V_0) + + IL_0000: br.s IL_0007 + + IL_0002: ldloca.s V_0 + IL_0004: ldind.u2 + IL_0005: br.s IL_000d + + IL_0007: ldloca.s V_0 + IL_0009: ldarg.0 + IL_000a: stind.i2 + IL_000b: br.s IL_0002 + + IL_000d: ret + } + + .method private hidebysig static int32 SignExtendsWrittenValue(uint16 valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (uint16 V_0) + + IL_0000: br.s IL_0007 + + IL_0002: ldloca.s V_0 + IL_0004: ldind.i2 + IL_0005: br.s IL_000d + + IL_0007: ldloca.s V_0 + IL_0009: ldarg.0 + IL_000a: stind.i2 + IL_000b: br.s IL_0002 + + IL_000d: ret + } + + .method private hidebysig static int32 ZeroExtendsWrittenValue(uint16 valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (uint16 V_0) + + IL_0000: br.s IL_0007 + + IL_0002: ldloca.s V_0 + IL_0004: ldind.u2 + IL_0005: br.s IL_000d + + IL_0007: ldloca.s V_0 + IL_0009: ldarg.0 + IL_000a: stind.i2 + IL_000b: br.s IL_0002 + + IL_000d: ret + } + + + .method private hidebysig static int32 PoisonStackWith(int32 valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (int32 V_0, int32 V_1) + + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: br.s IL_000b + + IL_0004: ldloc.1 + IL_0005: brfalse.s IL_0014 + + IL_0007: ldc.i4.0 + IL_0008: stloc.0 + IL_0009: br.s IL_0014 + + IL_000b: ldloca.s V_1 + IL_000d: conv.u + IL_000e: ldc.i4.0 + IL_000f: add + IL_0010: ldarg.0 + IL_0011: stind.i4 + IL_0012: br.s IL_0004 + + IL_0014: ldloc.0 + IL_0015: ret + } + + .method private hidebysig static int32 Main(string[] args) cil managed + { + .entrypoint + .maxstack 2 + .locals init (int32 V_0) + + ldc.i4.s 100 + stloc.0 +// BEGIN_DependsOnUnInitValue_bool + ldc.i4 0xdeadbeef + call int32 Runtime_40607.Program::PoisonStackWith(int32) + pop + + ldc.i4.0 + call int32 Runtime_40607.Program::DependsOnUnInitValue(bool) + brtrue.s END_DependsOnUnInitValue_bool + + ldstr "DependsOnUnInitValue(bool) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_DependsOnUnInitValue_bool: + +// BEGIN_DependsOnUnInitValue_int8 + ldc.i4 0xdeadbeef + call int32 Runtime_40607.Program::PoisonStackWith(int32) + pop + + ldc.i4.0 + call int32 Runtime_40607.Program::DependsOnUnInitValue(int8) + brtrue.s END_DependsOnUnInitValue_int8 + + ldstr "DependsOnUnInitValue(int8) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_DependsOnUnInitValue_int8: + +// BEGIN_DependsOnUnInitValue_uint8 + ldc.i4 0xdeadbeef + call int32 Runtime_40607.Program::PoisonStackWith(int32) + pop + + ldc.i4.0 + call int32 Runtime_40607.Program::DependsOnUnInitValue(uint8) + brtrue.s END_DependsOnUnInitValue_uint8 + + ldstr "DependsOnUnInitValue(uint8) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_DependsOnUnInitValue_uint8: + +// BEGIN_DependsOnUnInitValue_int16 + ldc.i4 0xdeadbeef + call int32 Runtime_40607.Program::PoisonStackWith(int32) + pop + + ldc.i4.0 + call int32 Runtime_40607.Program::DependsOnUnInitValue(int16) + brtrue.s END_DependsOnUnInitValue_int16 + + ldstr "DependsOnUnInitValue(int16) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_DependsOnUnInitValue_int16: + +// BEGIN_DependsOnUnInitValue_uint16 + ldc.i4 0xdeadbeef + call int32 Runtime_40607.Program::PoisonStackWith(int32) + pop + + ldc.i4.0 + call int32 Runtime_40607.Program::DependsOnUnInitValue(uint16) + brtrue.s END_DependsOnUnInitValue_uint16 + + ldstr "DependsOnUnInitValue(uint16) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_DependsOnUnInitValue_uint16: + +// BEGIN_DependsOnUnInitValue_int32 + ldc.i4 0xdeadbeef + call int32 Runtime_40607.Program::PoisonStackWith(int32) + pop + + ldc.i4.0 + call int32 Runtime_40607.Program::DependsOnUnInitValue(int32) + brtrue.s END_DependsOnUnInitValue_int32 + + ldstr "DependsOnUnInitValue(int32) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_DependsOnUnInitValue_int32: + +// BEGIN_DependsOnUnInitValue_uint32 + ldc.i4 0xdeadbeef + call int32 Runtime_40607.Program::PoisonStackWith(int32) + pop + + ldc.i4.0 + call int32 Runtime_40607.Program::DependsOnUnInitValue(uint32) + brtrue.s END_DependsOnUnInitValue_uint32 + + ldstr "DependsOnUnInitValue(uint32) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_DependsOnUnInitValue_uint32: + +// BEGIN_SignExtendsWrittenValue_int8_0x7f: + ldc.i4 0x7f + call int32 Runtime_40607.Program::SignExtendsWrittenValue(int8) + ldc.i4 0x7f + beq.s END_SignExtendsWrittenValue_int8_0x7f + + ldstr "SignExtendsWrittenValue(int8) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_SignExtendsWrittenValue_int8_0x7f: + +// BEGIN_ZeroExtendsWrittenValue_int8_0x7f: + ldc.i4 0x7f + call int32 Runtime_40607.Program::ZeroExtendsWrittenValue(int8) + ldc.i4 0x7f + beq.s END_ZeroExtendsWrittenValue_int8_0x7f + + ldstr "ZeroExtendsWrittenValue(int8) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_ZeroExtendsWrittenValue_int8_0x7f: + +// BEGIN_SignExtendsWrittenValue_int8_0x80: + ldc.i4 0x80 + call int32 Runtime_40607.Program::SignExtendsWrittenValue(int8) + ldc.i4 0xffffff80 + beq.s END_SignExtendsWrittenValue_int8_0x80 + + ldstr "SignExtendsWrittenValue(int8) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_SignExtendsWrittenValue_int8_0x80: + +// BEGIN_ZeroExtendsWrittenValue_int8_0x80: + ldc.i4 0x80 + call int32 Runtime_40607.Program::ZeroExtendsWrittenValue(int8) + ldc.i4 0x80 + beq.s END_ZeroExtendsWrittenValue_int8_0x80 + + ldstr "ZeroExtendsWrittenValue(int8) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_ZeroExtendsWrittenValue_int8_0x80: + +// BEGIN_SignExtendsWrittenValue_uint8_0x7f: + ldc.i4 0x7f + call int32 Runtime_40607.Program::SignExtendsWrittenValue(uint8) + ldc.i4 0x7f + beq.s END_SignExtendsWrittenValue_uint8_0x7f + + ldstr "SignExtendsWrittenValue(uint8) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_SignExtendsWrittenValue_uint8_0x7f: + +// BEGIN_ZeroExtendsWrittenValue_uint8_0x7f: + ldc.i4 0x7f + call int32 Runtime_40607.Program::ZeroExtendsWrittenValue(uint8) + ldc.i4 0x7f + beq.s END_ZeroExtendsWrittenValue_uint8_0x7f + + ldstr "ZeroExtendsWrittenValue(uint8) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_ZeroExtendsWrittenValue_uint8_0x7f: + +// BEGIN_SignExtendsWrittenValue_uint8_0x80: + ldc.i4 0x80 + call int32 Runtime_40607.Program::SignExtendsWrittenValue(uint8) + ldc.i4 0xffffff80 + beq.s END_SignExtendsWrittenValue_uint8_0x80 + + ldstr "SignExtendsWrittenValue(uint8) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_SignExtendsWrittenValue_uint8_0x80: + +// BEGIN_ZeroExtendsWrittenValue_uint8_0x80: + ldc.i4 0x80 + call int32 Runtime_40607.Program::ZeroExtendsWrittenValue(uint8) + ldc.i4 0x80 + beq.s END_ZeroExtendsWrittenValue_uint8_0x80 + + ldstr "ZeroExtendsWrittenValue(uint8) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_ZeroExtendsWrittenValue_uint8_0x80: + +// BEGIN_SignExtendsWrittenValue_int16_0x7fff: + ldc.i4 0x7fff + call int32 Runtime_40607.Program::SignExtendsWrittenValue(int16) + ldc.i4 0x7fff + beq.s END_SignExtendsWrittenValue_int16_0x7fff + + ldstr "SignExtendsWrittenValue(int16) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_SignExtendsWrittenValue_int16_0x7fff: + +// BEGIN_ZeroExtendsWrittenValue_int16_0x7fff: + ldc.i4 0x7fff + call int32 Runtime_40607.Program::ZeroExtendsWrittenValue(int16) + ldc.i4 0x7fff + beq.s END_ZeroExtendsWrittenValue_int16_0x7fff + + ldstr "ZeroExtendsWrittenValue(int16) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_ZeroExtendsWrittenValue_int16_0x7fff: + +// BEGIN_SignExtendsWrittenValue_int16_0x8000: + ldc.i4 0x8000 + call int32 Runtime_40607.Program::SignExtendsWrittenValue(int16) + ldc.i4 0xffff8000 + beq.s END_SignExtendsWrittenValue_int16_0x8000 + + ldstr "SignExtendsWrittenValue(int16) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_SignExtendsWrittenValue_int16_0x8000: + +// BEGIN_ZeroExtendsWrittenValue_int16_0x8000: + ldc.i4 0x8000 + call int32 Runtime_40607.Program::ZeroExtendsWrittenValue(int16) + ldc.i4 0x8000 + beq.s END_ZeroExtendsWrittenValue_int16_0x8000 + + ldstr "ZeroExtendsWrittenValue(int16) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_ZeroExtendsWrittenValue_int16_0x8000: + +// BEGIN_SignExtendsWrittenValue_uint16_0x7fff: + ldc.i4 0x7fff + call int32 Runtime_40607.Program::SignExtendsWrittenValue(uint16) + ldc.i4 0x7fff + beq.s END_SignExtendsWrittenValue_uint16_0x7fff + + ldstr "SignExtendsWrittenValue(uint16) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_SignExtendsWrittenValue_uint16_0x7fff: + +// BEGIN_ZeroExtendsWrittenValue_uint16_0x7fff: + ldc.i4 0x7fff + call int32 Runtime_40607.Program::ZeroExtendsWrittenValue(uint16) + ldc.i4 0x7fff + beq.s END_ZeroExtendsWrittenValue_uint16_0x7fff + + ldstr "ZeroExtendsWrittenValue(uint16) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_ZeroExtendsWrittenValue_uint16_0x7fff: + +// BEGIN_SignExtendsWrittenValue_uint16_0x8000: + ldc.i4 0x8000 + call int32 Runtime_40607.Program::SignExtendsWrittenValue(uint16) + ldc.i4 0xffff8000 + beq.s END_SignExtendsWrittenValue_uint16_0x8000 + + ldstr "SignExtendsWrittenValue(uint16) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_SignExtendsWrittenValue_uint16_0x8000: + +// BEGIN_ZeroExtendsWrittenValue_uint16_0x8000: + ldc.i4 0x8000 + call int32 Runtime_40607.Program::ZeroExtendsWrittenValue(uint16) + ldc.i4 0x8000 + beq.s END_ZeroExtendsWrittenValue_uint16_0x8000 + + ldstr "ZeroExtendsWrittenValue(uint16) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_ZeroExtendsWrittenValue_uint16_0x8000: + + ldloc.0 + ret + } +} + diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_40607/Runtime_40607.ilproj b/src/tests/JIT/Regression/JitBlue/Runtime_40607/Runtime_40607.ilproj new file mode 100644 index 00000000000000..7dab57fe6d2256 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_40607/Runtime_40607.ilproj @@ -0,0 +1,10 @@ + + + Exe + None + True + + + + + diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_40607/Runtime_40607.tt b/src/tests/JIT/Regression/JitBlue/Runtime_40607/Runtime_40607.tt new file mode 100644 index 00000000000000..9d3223581fbb9c --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_40607/Runtime_40607.tt @@ -0,0 +1,204 @@ +<#@ template debug="false" hostspecific="true" language="C#" #> +<#@ output extension=".il" #> +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +.assembly extern System.Console +{ +} +.assembly extern System.Runtime +{ +} +.assembly Runtime_40607 +{ +} +.module Runtime_40607.dll + +.class private auto ansi beforefieldinit Runtime_40607.Program extends [System.Runtime]System.Object +{ +<# + foreach ((string varType, int sizeInBytes) in new [] { ("bool", sizeof(bool)), ("int8", sizeof(sbyte)), ("uint8", sizeof(byte)), ("int16", sizeof(short)), ("uint16", sizeof(ushort)), ("int32", sizeof(int)), ("uint32", sizeof(uint)) }) + { +#> + .method private hidebysig static int32 DependsOnUnInitValue(<#= varType #> valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (int32 V_0, <#= varType #> V_1) + + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: br.s IL_000b + + IL_0004: ldloc.1 + IL_0005: brfalse.s IL_0011 + + IL_0007: ldc.i4.0 + IL_0008: stloc.0 + IL_0009: br.s IL_0011 + + IL_000b: ldloca.s V_1 + IL_000d: ldarg.0 + IL_000e: stind.i<#= sizeInBytes #> + IL_000f: br.s IL_0004 + + IL_0011: ldloc.0 + IL_0012: ret + } + +<# + } + + foreach ((string varType, int sizeInBytes) in new [] { ("int8", sizeof(sbyte)), ("uint8", sizeof(byte)), ("int16", sizeof(short)), ("uint16", sizeof(ushort)) }) + { +#> + .method private hidebysig static int32 SignExtendsWrittenValue(<#= varType #> valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (<#= varType #> V_0) + + IL_0000: br.s IL_0007 + + IL_0002: ldloca.s V_0 + IL_0004: ldind.i<#= sizeInBytes #> + IL_0005: br.s IL_000d + + IL_0007: ldloca.s V_0 + IL_0009: ldarg.0 + IL_000a: stind.i<#= sizeInBytes #> + IL_000b: br.s IL_0002 + + IL_000d: ret + } + + .method private hidebysig static int32 ZeroExtendsWrittenValue(<#= varType #> valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (<#= varType #> V_0) + + IL_0000: br.s IL_0007 + + IL_0002: ldloca.s V_0 + IL_0004: ldind.u<#= sizeInBytes #> + IL_0005: br.s IL_000d + + IL_0007: ldloca.s V_0 + IL_0009: ldarg.0 + IL_000a: stind.i<#= sizeInBytes #> + IL_000b: br.s IL_0002 + + IL_000d: ret + } + +<# + } +#> + + .method private hidebysig static int32 PoisonStackWith(int32 valueToWrite) cil managed noinlining + { + .maxstack 8 + .locals (int32 V_0, int32 V_1) + + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: br.s IL_000b + + IL_0004: ldloc.1 + IL_0005: brfalse.s IL_0014 + + IL_0007: ldc.i4.0 + IL_0008: stloc.0 + IL_0009: br.s IL_0014 + + IL_000b: ldloca.s V_1 + IL_000d: conv.u + IL_000e: ldc.i4.0 + IL_000f: add + IL_0010: ldarg.0 + IL_0011: stind.i4 + IL_0012: br.s IL_0004 + + IL_0014: ldloc.0 + IL_0015: ret + } + + .method private hidebysig static int32 Main(string[] args) cil managed + { + .entrypoint + .maxstack 2 + .locals init (int32 V_0) + + ldc.i4.s 100 + stloc.0 +<# + foreach (string varType in new [] { "bool", "int8", "uint8", "int16", "uint16", "int32", "uint32" }) + { + string testName = $"DependsOnUnInitValue_{varType}"; +#> +// BEGIN_<#= testName #> + ldc.i4 0xdeadbeef + call int32 Runtime_40607.Program::PoisonStackWith(int32) + pop + + ldc.i4.0 + call int32 Runtime_40607.Program::DependsOnUnInitValue(<#= varType #>) + brtrue.s END_<#= testName #> + + ldstr "DependsOnUnInitValue(<#= varType #>) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_<#= testName #>: + +<# + } + + foreach ((string varType, int sizeInBytes, int valueToWrite) in new [] { + ("int8", sizeof(sbyte), 0x7f), + ("int8", sizeof(sbyte), 0x80), + ("uint8", sizeof(byte), 0x7f), + ("uint8", sizeof(byte), 0x80), + ("int16", sizeof(short), 0x7fff), + ("int16", sizeof(short), 0x8000), + ("uint16", sizeof(ushort), 0x7fff), + ("uint16", sizeof(ushort), 0x8000) }) + foreach ((string testName, int expectedResult) in new[] { + ("SignExtendsWrittenValue", SignExtend(valueToWrite, sizeInBytes)), + ("ZeroExtendsWrittenValue", valueToWrite) }) + { + string lblName = $"{testName}_{varType}_0x{valueToWrite:x}"; +#> +// BEGIN_<#= lblName #>: + ldc.i4 0x<#= valueToWrite.ToString("x") #> + call int32 Runtime_40607.Program::<#= testName #>(<#= varType #>) + ldc.i4 0x<#= expectedResult.ToString("x") #> + beq.s END_<#= lblName #> + + ldstr "<#= testName #>(<#= varType #>) has failed" + call void [System.Console]System.Console::WriteLine(string) + + ldc.i4.0 + stloc.0 +END_<#= lblName #>: + +<# + } +#> + ldloc.0 + ret + } +} + +<#+ + int SignExtend(int value, int sizeInBytes) + { + if ((value & (1 << (8 * sizeInBytes - 1))) != 0) + { + for (int i = 8 * sizeInBytes; i < 8 * sizeof(int); i++) + { + value |= (1 << i); + } + } + return value; + } +#>