From 2081dd2bb2c9a48e36e10f064b7cf0ce18453c9a Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Tue, 22 Nov 2022 13:55:35 +0100 Subject: [PATCH 1/9] JIT: Set GTF_ORDER_SIDEEFF for some nodes with invisible dependencies We have a few places where we create the pattern "COMMA(some check, some value)". In some of these cases there may not be any visible dependency (e.g. use of a defined value) which makes the dependency invisible to the JIT. If the value is safe to compute only because of the check (for example, a bounds check + indexing operation), and if the value otherwise has no side effects, then nothing prevented the backend or optimizations from reordering these nodes. Fix #78554 --- src/coreclr/jit/importer.cpp | 3 +++ src/coreclr/jit/importercalls.cpp | 1 + src/coreclr/jit/morph.cpp | 13 ++++++++++--- src/coreclr/jit/optimizer.cpp | 8 ++++++++ 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 6185804f898ff0..11efcf4b6c89d9 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -9692,6 +9692,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) } if (helperNode != nullptr) { + helperNode->gtFlags |= GTF_ORDER_SIDEEFF; op1 = gtNewOperNode(GT_COMMA, op1->TypeGet(), helperNode, op1); } } @@ -9967,6 +9968,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) } if (helperNode != nullptr) { + helperNode->gtFlags |= GTF_ORDER_SIDEEFF; op1 = gtNewOperNode(GT_COMMA, op1->TypeGet(), helperNode, op1); } } @@ -10458,6 +10460,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) GenTree* boxPayloadAddress = gtNewOperNode(GT_ADD, TYP_BYREF, cloneOperand, boxPayloadOffset); GenTree* nullcheck = gtNewNullCheck(op1, block); + nullcheck->gtFlags |= GTF_ORDER_SIDEEFF; GenTree* result = gtNewOperNode(GT_COMMA, TYP_BYREF, nullcheck, boxPayloadAddress); impPushOnStack(result, tiRetVal); break; diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index b9e8c3af9d3284..8a880af15677bd 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -2728,6 +2728,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, // Prepare result var_types resultType = JITtype2varType(sig->retType); assert(resultType == result->TypeGet()); + boundsCheck->gtFlags |= GTF_ORDER_SIDEEFF; retNode = gtNewOperNode(GT_COMMA, resultType, boundsCheck, result); break; diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index c1b827e623fd56..9cccec8c459355 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -4608,6 +4608,10 @@ GenTree* Compiler::fgMorphIndexAddr(GenTreeIndexAddr* indexAddr) // Prepend the bounds check and the assignment trees that were created (if any). if (boundsCheck != nullptr) { + // This is changing a value dependency (INDEX_ADDR node) into a flow + // dependency, so make sure this dependency remains visible. + boundsCheck->gtFlags |= GTF_ORDER_SIDEEFF; + tree = gtNewOperNode(GT_COMMA, tree->TypeGet(), boundsCheck, tree); fgSetRngChkTarget(boundsCheck); } @@ -10646,7 +10650,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA // could result in an invalid value number for the newly generated GT_IND node. if ((op1->OperGet() == GT_COMMA) && fgGlobalMorph) { - // Perform the transform IND(COMMA(x, ..., z)) == COMMA(x, ..., IND(z)). + // Perform the transform IND(COMMA(x, ..., z)) -> COMMA(x, ..., IND(z)). // TBD: this transformation is currently necessary for correctness -- it might // be good to analyze the failures that result if we don't do this, and fix them // in other ways. Ideally, this should be optional. @@ -10679,9 +10683,12 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA // TODO-1stClassStructs: we often create a struct IND without a handle, fix it. op1 = gtNewIndir(typ, addr); - // Determine flags on the indir. + // GTF_GLOB_EFFECT flags can be recomputed from the child + // nodes. GTF_ORDER_SIDEEFF may be set already and indicate no + // reordering is allowed with sibling nodes, so we cannot + // recompute that. // - op1->gtFlags |= treeFlags & ~GTF_ALL_EFFECT; + op1->gtFlags |= treeFlags & ~GTF_GLOB_EFFECT; op1->gtFlags |= (addr->gtFlags & GTF_ALL_EFFECT); // if this was a non-faulting indir, clear GTF_EXCEPT, diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index be12db114d5782..d2605416da9350 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -4691,6 +4691,14 @@ bool Compiler::optIfConvert(BasicBlock* block) return false; } + // Evaluating op1/op2 unconditionally effectively has the same effect as + // reordering them with the condition (for example, the condition could be + // an explicit bounds check and the operands could read an array element). + if ((cond->gtFlags & GTF_ORDER_SIDEEFF) == 0) + { + return false; + } + // Block where the flows merge. BasicBlock* finalBlock = block->bbNext; // The node, statement and block of the assignment. From c9d66da897f4fb3dd7bd4c708edc22f00e8e82b1 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Tue, 22 Nov 2022 15:27:47 +0100 Subject: [PATCH 2/9] Flip --- src/coreclr/jit/optimizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index d2605416da9350..2324453b0f3016 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -4694,7 +4694,7 @@ bool Compiler::optIfConvert(BasicBlock* block) // Evaluating op1/op2 unconditionally effectively has the same effect as // reordering them with the condition (for example, the condition could be // an explicit bounds check and the operands could read an array element). - if ((cond->gtFlags & GTF_ORDER_SIDEEFF) == 0) + if ((cond->gtFlags & GTF_ORDER_SIDEEFF) != 0) { return false; } From b969e778b91cfbeaefc1f660dd618f42f6591ac4 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Tue, 22 Nov 2022 15:35:05 +0100 Subject: [PATCH 3/9] Add another --- src/coreclr/jit/morph.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 9cccec8c459355..b324772e90e1a5 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -5194,6 +5194,8 @@ GenTree* Compiler::fgMorphExpandInstanceField(GenTree* tree, MorphAddrContext* m GenTree* lclVar = gtNewLclvNode(lclNum, objRefType); GenTree* nullchk = gtNewNullCheck(lclVar, compCurBB); + nullchk->gtFlags |= GTF_ORDER_SIDEEFF; + if (asg != nullptr) { // Create the "comma" node. From ddb5538bbc1ed30cfeb554de1c4c9fb4e77f80bf Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Tue, 22 Nov 2022 16:43:07 +0100 Subject: [PATCH 4/9] Run jit-format --- src/coreclr/jit/importer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 11efcf4b6c89d9..b1e2415207b530 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -10461,7 +10461,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) gtNewOperNode(GT_ADD, TYP_BYREF, cloneOperand, boxPayloadOffset); GenTree* nullcheck = gtNewNullCheck(op1, block); nullcheck->gtFlags |= GTF_ORDER_SIDEEFF; - GenTree* result = gtNewOperNode(GT_COMMA, TYP_BYREF, nullcheck, boxPayloadAddress); + GenTree* result = gtNewOperNode(GT_COMMA, TYP_BYREF, nullcheck, boxPayloadAddress); impPushOnStack(result, tiRetVal); break; } From 67ee0cb482af40b2d239c6727fef7491d1b94293 Mon Sep 17 00:00:00 2001 From: Alan Hayward Date: Fri, 18 Nov 2022 14:13:37 +0000 Subject: [PATCH 5/9] Add test --- .../JitBlue/Runtime_78554/Runtime_78554.cs | 30 +++++++++++++++++++ .../Runtime_78554/Runtime_78554.csproj | 13 ++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.csproj diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.cs b/src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.cs new file mode 100644 index 00000000000000..446b57d03b4a39 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; + +public class Runtime_78554 +{ + [MethodImpl(MethodImplOptions.NoInlining)] + static void Consume(uint op) + { + return; + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + static void ArrayIndexConsume(uint[] a, uint i) + { + if (i < a.Length) + { + i = a[i]; + } + Consume(i); + } + + public static int Main() + { + var arr = new uint[] { 1, 42, 3000 }; + ArrayIndexConsume(arr, 0xffffffff); + return 100; + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.csproj new file mode 100644 index 00000000000000..7a789ed5ed1f58 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.csproj @@ -0,0 +1,13 @@ + + + Exe + True + + + + + + + + + From c2a96d7d74e9ec39bd7085a122368699a0d5b970 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Wed, 23 Nov 2022 13:54:42 +0100 Subject: [PATCH 6/9] Make if-conversion check less conservative --- src/coreclr/jit/optimizer.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 2324453b0f3016..0e9e43aeeeabf5 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -4691,14 +4691,6 @@ bool Compiler::optIfConvert(BasicBlock* block) return false; } - // Evaluating op1/op2 unconditionally effectively has the same effect as - // reordering them with the condition (for example, the condition could be - // an explicit bounds check and the operands could read an array element). - if ((cond->gtFlags & GTF_ORDER_SIDEEFF) != 0) - { - return false; - } - // Block where the flows merge. BasicBlock* finalBlock = block->bbNext; // The node, statement and block of the assignment. @@ -4802,6 +4794,17 @@ bool Compiler::optIfConvert(BasicBlock* block) return false; } + // Evaluating op1/op2 unconditionally effectively has the same effect as + // reordering them with the condition (for example, the condition could be + // an explicit bounds check and the operand could read an array element). + // Disallow this except for some common cases that we know are always side + // effect free. + if (((cond->gtFlags & GTF_ORDER_SIDEEFF) != 0) && !asgNode->gtGetOp2()->IsInvariant() && + !asgNode->gtGetOp2()->OperIsLocal()) + { + return false; + } + #ifdef DEBUG if (verbose) { From bbcd8d5aa3fbc0b38bd8915c60218736eb3abcf5 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Wed, 23 Nov 2022 13:54:56 +0100 Subject: [PATCH 7/9] Ignore source indir when containing block store source address --- src/coreclr/jit/lower.h | 2 +- src/coreclr/jit/lowerarmarch.cpp | 11 ++++++----- src/coreclr/jit/lowerxarch.cpp | 11 ++++++----- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/coreclr/jit/lower.h b/src/coreclr/jit/lower.h index 63174ccec9ff11..4e2de370165fe4 100644 --- a/src/coreclr/jit/lower.h +++ b/src/coreclr/jit/lower.h @@ -317,7 +317,7 @@ class Lowering final : public Phase GenTree* LowerSignedDivOrMod(GenTree* node); void LowerBlockStore(GenTreeBlk* blkNode); void LowerBlockStoreCommon(GenTreeBlk* blkNode); - void ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenTree* addr); + void ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenTree* addr, GenTree* addrParent); void LowerPutArgStkOrSplit(GenTreePutArgStk* putArgNode); #ifdef TARGET_XARCH void LowerPutArgStk(GenTreePutArgStk* putArgStk); diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index 0ac3ea9d47c286..5901cba7a2870c 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -566,7 +566,7 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) src->AsIntCon()->SetIconValue(fill); - ContainBlockStoreAddress(blkNode, size, dstAddr); + ContainBlockStoreAddress(blkNode, size, dstAddr, nullptr); } else { @@ -637,10 +637,10 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) if (src->OperIs(GT_IND)) { - ContainBlockStoreAddress(blkNode, size, src->AsIndir()->Addr()); + ContainBlockStoreAddress(blkNode, size, src->AsIndir()->Addr(), src->AsIndir()); } - ContainBlockStoreAddress(blkNode, size, dstAddr); + ContainBlockStoreAddress(blkNode, size, dstAddr, nullptr); } else { @@ -658,8 +658,9 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) // blkNode - the block store node // size - the block size // addr - the address node to try to contain +// addrParent - the parent of addr, in case this is checking containment the source address. // -void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenTree* addr) +void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenTree* addr, GenTree* addrParent) { assert(blkNode->OperIs(GT_STORE_BLK) && (blkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindUnroll)); assert(size < INT32_MAX); @@ -692,7 +693,7 @@ void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenT } #endif // !TARGET_ARM - if (!IsSafeToContainMem(blkNode, addr)) + if (!IsSafeToContainMem(blkNode, addrParent, addr)) { return; } diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index 9fa8c0bf1c26bf..095cf91f61514a 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -373,7 +373,7 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) src->AsIntCon()->SetIconValue(fill); - ContainBlockStoreAddress(blkNode, size, dstAddr); + ContainBlockStoreAddress(blkNode, size, dstAddr, nullptr); } } else @@ -478,10 +478,10 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) if (src->OperIs(GT_IND)) { - ContainBlockStoreAddress(blkNode, size, src->AsIndir()->Addr()); + ContainBlockStoreAddress(blkNode, size, src->AsIndir()->Addr(), src->AsIndir()); } - ContainBlockStoreAddress(blkNode, size, dstAddr); + ContainBlockStoreAddress(blkNode, size, dstAddr, nullptr); } else { @@ -504,8 +504,9 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) // blkNode - the block store node // size - the block size // addr - the address node to try to contain +// addrParent - the parent of addr, in case this is checking containment of the source address. // -void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenTree* addr) +void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenTree* addr, GenTree* addrParent) { assert(blkNode->OperIs(GT_STORE_BLK) && (blkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindUnroll)); assert(size < INT32_MAX); @@ -536,7 +537,7 @@ void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenT // Note that the parentNode is always the block node, even if we're dealing with the source address. // The source address is not directly used by the block node but by an IND node and that IND node is // always contained. - if (!IsSafeToContainMem(blkNode, addrMode)) + if (!IsSafeToContainMem(blkNode, addrParent, addrMode)) { return; } From 2919001afdedefd49ab2fc32b0182ee982a78abf Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Wed, 23 Nov 2022 23:35:42 +0100 Subject: [PATCH 8/9] Address feedback; add more GTF_ORDER_SIDEEFF flags on other operands --- src/coreclr/jit/importer.cpp | 9 +++++++-- src/coreclr/jit/importercalls.cpp | 4 ++++ src/coreclr/jit/morph.cpp | 9 ++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index f1698f0991ee53..df7834354af195 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -9696,7 +9696,6 @@ void Compiler::impImportBlockCode(BasicBlock* block) } if (helperNode != nullptr) { - helperNode->gtFlags |= GTF_ORDER_SIDEEFF; op1 = gtNewOperNode(GT_COMMA, op1->TypeGet(), helperNode, op1); } } @@ -9972,7 +9971,6 @@ void Compiler::impImportBlockCode(BasicBlock* block) } if (helperNode != nullptr) { - helperNode->gtFlags |= GTF_ORDER_SIDEEFF; op1 = gtNewOperNode(GT_COMMA, op1->TypeGet(), helperNode, op1); } } @@ -10464,7 +10462,14 @@ void Compiler::impImportBlockCode(BasicBlock* block) GenTree* boxPayloadAddress = gtNewOperNode(GT_ADD, TYP_BYREF, cloneOperand, boxPayloadOffset); GenTree* nullcheck = gtNewNullCheck(op1, block); + // Add an ordering dependency between the null + // check and forming the byref; the JIT assumes + // in many places that the only legal null + // byref is literally 0, and since the byref + // leaks out here, we need to ensure it is + // nullchecked. nullcheck->gtFlags |= GTF_ORDER_SIDEEFF; + boxPayloadAddress->gtFlags |= GTF_ORDER_SIDEEFF; GenTree* result = gtNewOperNode(GT_COMMA, TYP_BYREF, nullcheck, boxPayloadAddress); impPushOnStack(result, tiRetVal); break; diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 8a880af15677bd..9a2149be4a9c1b 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -2728,7 +2728,11 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, // Prepare result var_types resultType = JITtype2varType(sig->retType); assert(resultType == result->TypeGet()); + // Add an ordering dependency between the bounds check and + // forming the byref to prevent these from being reordered. The + // JIT is not allowed to create arbitrary illegal byrefs. boundsCheck->gtFlags |= GTF_ORDER_SIDEEFF; + result->gtFlags |= GTF_ORDER_SIDEEFF; retNode = gtNewOperNode(GT_COMMA, resultType, boundsCheck, result); break; diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index f524ace28bda46..1177a6aef5b1f1 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -4609,8 +4609,11 @@ GenTree* Compiler::fgMorphIndexAddr(GenTreeIndexAddr* indexAddr) if (boundsCheck != nullptr) { // This is changing a value dependency (INDEX_ADDR node) into a flow - // dependency, so make sure this dependency remains visible. + // dependency, so make sure this dependency remains visible. Also, the + // JIT is not allowed to create arbitrary byrefs, so we must make sure + // the address is not reordered with the bounds check. boundsCheck->gtFlags |= GTF_ORDER_SIDEEFF; + addr->gtFlags |= GTF_ORDER_SIDEEFF; tree = gtNewOperNode(GT_COMMA, tree->TypeGet(), boundsCheck, tree); fgSetRngChkTarget(boundsCheck); @@ -5207,6 +5210,10 @@ GenTree* Compiler::fgMorphExpandInstanceField(GenTree* tree, MorphAddrContext* m } addr = gtNewLclvNode(lclNum, objRefType); // Use "tmpLcl" to create "addr" node. + + // Ensure the creation of the byref does not get reordered with the + // null check, as that could otherwise create an illegal byref. + addr->gtFlags |= GTF_ORDER_SIDEEFF; } else { From 57daa314f95d883e57d176964afe40d680cfa9b2 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Wed, 23 Nov 2022 23:50:36 +0100 Subject: [PATCH 9/9] Update src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.cs --- src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.cs b/src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.cs index 446b57d03b4a39..70445fb8f18f4e 100644 --- a/src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.cs +++ b/src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.cs @@ -8,7 +8,6 @@ public class Runtime_78554 [MethodImpl(MethodImplOptions.NoInlining)] static void Consume(uint op) { - return; } [MethodImplAttribute(MethodImplOptions.NoInlining)]