diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index ed2f3f55ce905..235cc34ea6ed0 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -614,6 +614,8 @@ class LclVarDsc unsigned char lvSingleDefDisqualifyReason = 'H'; #endif + unsigned char lvAllDefsAreNoGc : 1; // For pinned locals: true if all defs of this local are no-gc + #if FEATURE_MULTIREG_ARGS regNumber lvRegNumForSlot(unsigned slotNum) { diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 34ef15e8ebd0e..6407458a06fee 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -1110,6 +1110,11 @@ struct GenTree return true; } + bool IsNotGcDef() const + { + return IsIntegralConst(0) || IsLocalAddrExpr(); + } + // LIR flags // These helper methods, along with the flag values they manipulate, are defined in lir.h // diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index cc12c8a3837da..d51104d1b93e4 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -4181,49 +4181,57 @@ void Compiler::lvaMarkLclRefs(GenTree* tree, BasicBlock* block, Statement* stmt, /* Is this an assignment to a local variable? */ - if (op1->gtOper == GT_LCL_VAR && op2->gtType != TYP_BOOL) + if (op1->gtOper == GT_LCL_VAR) { - /* Only simple assignments allowed for booleans */ + LclVarDsc* varDsc = lvaGetDesc(op1->AsLclVarCommon()); - if (tree->gtOper != GT_ASG) + if (varDsc->lvPinned && varDsc->lvAllDefsAreNoGc) { - goto NOT_BOOL; + if (!op2->IsNotGcDef()) + { + varDsc->lvAllDefsAreNoGc = false; + } } - /* Is the RHS clearly a boolean value? */ - - switch (op2->gtOper) + if (op2->gtType != TYP_BOOL) { - unsigned lclNum; + /* Only simple assignments allowed for booleans */ - case GT_CNS_INT: + if (tree->gtOper != GT_ASG) + { + goto NOT_BOOL; + } - if (op2->AsIntCon()->gtIconVal == 0) - { - break; - } - if (op2->AsIntCon()->gtIconVal == 1) - { - break; - } + /* Is the RHS clearly a boolean value? */ - // Not 0 or 1, fall through .... - FALLTHROUGH; + switch (op2->gtOper) + { + case GT_CNS_INT: - default: + if (op2->AsIntCon()->gtIconVal == 0) + { + break; + } + if (op2->AsIntCon()->gtIconVal == 1) + { + break; + } - if (op2->OperIsCompare()) - { - break; - } + // Not 0 or 1, fall through .... + FALLTHROUGH; - NOT_BOOL: + default: - lclNum = op1->AsLclVarCommon()->GetLclNum(); - noway_assert(lclNum < lvaCount); + if (op2->OperIsCompare()) + { + break; + } - lvaTable[lclNum].lvIsBoolean = false; - break; + NOT_BOOL: + + varDsc->lvIsBoolean = false; + break; + } } } } @@ -4278,7 +4286,8 @@ void Compiler::lvaMarkLclRefs(GenTree* tree, BasicBlock* block, Statement* stmt, { if (lvaVarAddrExposed(lclNum)) { - varDsc->lvIsBoolean = false; + varDsc->lvIsBoolean = false; + varDsc->lvAllDefsAreNoGc = false; } if (tree->gtOper == GT_LCL_FLD) @@ -4703,6 +4712,8 @@ void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) varDsc->setLvRefCnt(0); varDsc->setLvRefCntWtd(BB_ZERO_WEIGHT); + varDsc->lvAllDefsAreNoGc = true; + // Special case for some varargs params ... these must // remain unreferenced. const bool isSpecialVarargsParam = varDsc->lvIsParam && raIsVarargsStackArg(lclNum); @@ -4750,6 +4761,8 @@ void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) { varDsc->lvSingleDef = varDsc->lvIsParam; varDsc->lvSingleDefRegCandidate = varDsc->lvIsParam; + + varDsc->lvAllDefsAreNoGc = true; } } @@ -4868,6 +4881,13 @@ void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) varDsc->lvImplicitlyReferenced = 1; } } + + if (varDsc->lvPinned && varDsc->lvAllDefsAreNoGc) + { + varDsc->lvPinned = 0; + + JITDUMP("V%02u was unpinned as all def candidates were local.\n", lclNum); + } } }