diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/jit/block.cpp | 32 | ||||
-rw-r--r-- | src/jit/block.h | 8 | ||||
-rw-r--r-- | src/jit/compiler.h | 13 | ||||
-rw-r--r-- | src/jit/gentree.cpp | 127 | ||||
-rw-r--r-- | src/jit/optimizer.cpp | 6 | ||||
-rw-r--r-- | src/mscorlib/corefx/System/Globalization/CultureInfo.cs | 5 | ||||
-rw-r--r-- | src/mscorlib/src/System/Globalization/CultureInfo.cs | 5 |
7 files changed, 129 insertions, 67 deletions
diff --git a/src/jit/block.cpp b/src/jit/block.cpp index cf2a107479..ed8a103f53 100644 --- a/src/jit/block.cpp +++ b/src/jit/block.cpp @@ -568,7 +568,25 @@ void* BasicBlock::HeapPhiArg::operator new(size_t sz, Compiler* comp) return comp->compGetMem(sz, CMK_HeapPhiArg); } -void BasicBlock::CloneBlockState(Compiler* compiler, BasicBlock* to, const BasicBlock* from) +//------------------------------------------------------------------------ +// CloneBlockState: Try to populate `to` block with a copy of `from` block's statements, replacing +// uses of local `varNum` with IntCns `varVal`. +// +// Arguments: +// compiler - Jit compiler instance +// to - New/empty block to copy statements into +// from - Block to copy statements from +// varNum - lclVar uses with lclNum `varNum` will be replaced; can be ~0 to indicate no replacement. +// varVal - If replacing uses of `varNum`, replace them with int constants with value `varVal`. +// +// Return Value: +// Cloning may fail because this routine uses `gtCloneExpr` for cloning and it can't handle all +// IR nodes. If cloning of any statement fails, `false` will be returned and block `to` may be +// partially populated. If cloning of all statements succeeds, `true` will be returned and +// block `to` will be fully populated. + +bool BasicBlock::CloneBlockState( + Compiler* compiler, BasicBlock* to, const BasicBlock* from, unsigned varNum, int varVal) { assert(to->bbTreeList == nullptr); @@ -595,9 +613,17 @@ void BasicBlock::CloneBlockState(Compiler* compiler, BasicBlock* to, const Basic for (GenTreePtr fromStmt = from->bbTreeList; fromStmt != nullptr; fromStmt = fromStmt->gtNext) { - compiler->fgInsertStmtAtEnd(to, - compiler->fgNewStmtFromTree(compiler->gtCloneExpr(fromStmt->gtStmt.gtStmtExpr))); + auto newExpr = compiler->gtCloneExpr(fromStmt->gtStmt.gtStmtExpr, 0, varNum, varVal); + if (!newExpr) + { + // gtCloneExpr doesn't handle all opcodes, so may fail to clone a statement. + // When that happens, it returns nullptr; abandon the rest of this block and + // return `false` to the caller to indicate that cloning was unsuccessful. + return false; + } + compiler->fgInsertStmtAtEnd(to, compiler->fgNewStmtFromTree(newExpr)); } + return true; } // LIR helpers diff --git a/src/jit/block.h b/src/jit/block.h index 86dffe14ca..1e6d1754ab 100644 --- a/src/jit/block.h +++ b/src/jit/block.h @@ -1092,9 +1092,11 @@ public: return AllSuccs(comp, this); } - // Clone block state and statements from 'from' block to 'to' block. - // Assumes that "to" is an empty block. - static void CloneBlockState(Compiler* compiler, BasicBlock* to, const BasicBlock* from); + // Try to clone block state and statements from `from` block to `to` block (which must be new/empty), + // optionally replacing uses of local `varNum` with IntCns `varVal`. Return true if all statements + // in the block are cloned successfully, false (with partially-populated `to` block) if one fails. + static bool CloneBlockState( + Compiler* compiler, BasicBlock* to, const BasicBlock* from, unsigned varNum = (unsigned)-1, int varVal = 0); void MakeLIR(GenTree* firstNode, GenTree* lastNode); bool IsLIR(); diff --git a/src/jit/compiler.h b/src/jit/compiler.h index c1023aeedc..80dc6507ab 100644 --- a/src/jit/compiler.h +++ b/src/jit/compiler.h @@ -2021,7 +2021,18 @@ public: GenTreePtr gtClone(GenTree* tree, bool complexOK = false); - GenTreePtr gtCloneExpr(GenTree* tree, unsigned addFlags = 0, unsigned varNum = (unsigned)-1, int varVal = 0); + // If `tree` is a lclVar with lclNum `varNum`, return an IntCns with value `varVal`; otherwise, + // create a copy of `tree`, adding specified flags, replacing uses of lclVar `deepVarNum` with + // IntCnses with value `deepVarVal`. + GenTreePtr gtCloneExpr( + GenTree* tree, unsigned addFlags, unsigned varNum, int varVal, unsigned deepVarNum, int deepVarVal); + + // Create a copy of `tree`, optionally adding specifed flags, and optionally mapping uses of local + // `varNum` to int constants with value `varVal`. + GenTreePtr gtCloneExpr(GenTree* tree, unsigned addFlags = 0, unsigned varNum = (unsigned)-1, int varVal = 0) + { + return gtCloneExpr(tree, addFlags, varNum, varVal, varNum, varVal); + } GenTreePtr gtReplaceTree(GenTreePtr stmt, GenTreePtr tree, GenTreePtr replacementTree); diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp index b7059714a6..9ed1f51c35 100644 --- a/src/jit/gentree.cpp +++ b/src/jit/gentree.cpp @@ -7698,17 +7698,30 @@ GenTreePtr Compiler::gtClone(GenTree* tree, bool complexOK) return copy; } -/***************************************************************************** - * - * Clones the given tree value and returns a copy of the given tree. Any - * references to local variable varNum will be replaced with the integer - * constant varVal. - */ +//------------------------------------------------------------------------ +// gtCloneExpr: Create a copy of `tree`, adding flags `addFlags`, mapping +// local `varNum` to int constant `varVal` if it appears at +// the root, and mapping uses of local `deepVarNum` to constant +// `deepVarVal` if they occur beyond the root. +// +// Arguments: +// tree - GenTree to create a copy of +// addFlags - GTF_* flags to add to the copied tree nodes +// varNum - lclNum to replace at the root, or ~0 for no root replacement +// varVal - If replacing at root, replace local `varNum` with IntCns `varVal` +// deepVarNum - lclNum to replace uses of beyond the root, or ~0 for no replacement +// deepVarVal - If replacing beyond root, replace `deepVarNum` with IntCns `deepVarVal` +// +// Return Value: +// A copy of the given tree with the replacements and added flags specified. +// +// Notes: +// Top-level callers should generally call the overload that doesn't have +// the explicit `deepVarNum` and `deepVarVal` parameters; those are used in +// recursive invocations to avoid replacing defs. -GenTreePtr Compiler::gtCloneExpr(GenTree* tree, - unsigned addFlags, - unsigned varNum, // = (unsigned)-1 - int varVal) +GenTreePtr Compiler::gtCloneExpr( + GenTree* tree, unsigned addFlags, unsigned varNum, int varVal, unsigned deepVarNum, int deepVarVal) { if (tree == nullptr) { @@ -7764,6 +7777,10 @@ GenTreePtr Compiler::gtCloneExpr(GenTree* tree, if (tree->gtLclVarCommon.gtLclNum == varNum) { copy = gtNewIconNode(varVal, tree->gtType); + if (tree->gtFlags & GTF_VAR_ARR_INDEX) + { + copy->LabelIndex(this); + } } else { @@ -7930,8 +7947,9 @@ GenTreePtr Compiler::gtCloneExpr(GenTree* tree, case GT_ARR_INDEX: copy = new (this, GT_ARR_INDEX) - GenTreeArrIndex(tree->TypeGet(), gtCloneExpr(tree->gtArrIndex.ArrObj(), addFlags, varNum, varVal), - gtCloneExpr(tree->gtArrIndex.IndexExpr(), addFlags, varNum, varVal), + GenTreeArrIndex(tree->TypeGet(), + gtCloneExpr(tree->gtArrIndex.ArrObj(), addFlags, deepVarNum, deepVarVal), + gtCloneExpr(tree->gtArrIndex.IndexExpr(), addFlags, deepVarNum, deepVarVal), tree->gtArrIndex.gtCurrDim, tree->gtArrIndex.gtArrRank, tree->gtArrIndex.gtArrElemType); break; @@ -8030,12 +8048,20 @@ GenTreePtr Compiler::gtCloneExpr(GenTree* tree, if (tree->gtOp.gtOp1) { - copy->gtOp.gtOp1 = gtCloneExpr(tree->gtOp.gtOp1, addFlags, varNum, varVal); + if (tree->gtOper == GT_ASG) + { + // Don't replace varNum if it appears as the LHS of an assign. + copy->gtOp.gtOp1 = gtCloneExpr(tree->gtOp.gtOp1, addFlags, -1, 0, deepVarNum, deepVarVal); + } + else + { + copy->gtOp.gtOp1 = gtCloneExpr(tree->gtOp.gtOp1, addFlags, deepVarNum, deepVarVal); + } } if (tree->gtGetOp2()) { - copy->gtOp.gtOp2 = gtCloneExpr(tree->gtOp.gtOp2, addFlags, varNum, varVal); + copy->gtOp.gtOp2 = gtCloneExpr(tree->gtOp.gtOp2, addFlags, deepVarNum, deepVarVal); } /* Flags */ @@ -8097,18 +8123,6 @@ GenTreePtr Compiler::gtCloneExpr(GenTree* tree, copy->CopyReg(tree); } - // We can call gtCloneExpr() before we have called fgMorph when we expand a GT_INDEX node in fgMorphArrayIndex() - // The method gtFoldExpr() expects to be run after fgMorph so it will set the GTF_DEBUG_NODE_MORPHED - // flag on nodes that it adds/modifies. Then when we call fgMorph we will assert. - // We really only will need to fold when this method is used to replace references to - // local variable with an integer. - // - if (varNum != (unsigned)-1) - { - /* Try to do some folding */ - copy = gtFoldExpr(copy); - } - goto DONE; } @@ -8117,7 +8131,7 @@ GenTreePtr Compiler::gtCloneExpr(GenTree* tree, switch (oper) { case GT_STMT: - copy = gtCloneExpr(tree->gtStmt.gtStmtExpr, addFlags, varNum, varVal); + copy = gtCloneExpr(tree->gtStmt.gtStmtExpr, addFlags, deepVarNum, deepVarVal); copy = gtNewStmt(copy, tree->gtStmt.gtStmtILoffsx); goto DONE; @@ -8125,15 +8139,17 @@ GenTreePtr Compiler::gtCloneExpr(GenTree* tree, copy = new (this, GT_CALL) GenTreeCall(tree->TypeGet()); - copy->gtCall.gtCallObjp = - tree->gtCall.gtCallObjp ? gtCloneExpr(tree->gtCall.gtCallObjp, addFlags, varNum, varVal) : nullptr; - copy->gtCall.gtCallArgs = tree->gtCall.gtCallArgs - ? gtCloneExpr(tree->gtCall.gtCallArgs, addFlags, varNum, varVal)->AsArgList() + copy->gtCall.gtCallObjp = tree->gtCall.gtCallObjp + ? gtCloneExpr(tree->gtCall.gtCallObjp, addFlags, deepVarNum, deepVarVal) : nullptr; + copy->gtCall.gtCallArgs = + tree->gtCall.gtCallArgs + ? gtCloneExpr(tree->gtCall.gtCallArgs, addFlags, deepVarNum, deepVarVal)->AsArgList() + : nullptr; copy->gtCall.gtCallMoreFlags = tree->gtCall.gtCallMoreFlags; copy->gtCall.gtCallLateArgs = tree->gtCall.gtCallLateArgs - ? gtCloneExpr(tree->gtCall.gtCallLateArgs, addFlags, varNum, varVal)->AsArgList() + ? gtCloneExpr(tree->gtCall.gtCallLateArgs, addFlags, deepVarNum, deepVarVal)->AsArgList() : nullptr; #if !FEATURE_FIXED_OUT_ARGS @@ -8154,11 +8170,12 @@ GenTreePtr Compiler::gtCloneExpr(GenTree* tree, /* Copy the union */ if (tree->gtCall.gtCallType == CT_INDIRECT) { - copy->gtCall.gtCallCookie = tree->gtCall.gtCallCookie - ? gtCloneExpr(tree->gtCall.gtCallCookie, addFlags, varNum, varVal) - : nullptr; - copy->gtCall.gtCallAddr = - tree->gtCall.gtCallAddr ? gtCloneExpr(tree->gtCall.gtCallAddr, addFlags, varNum, varVal) : nullptr; + copy->gtCall.gtCallCookie = + tree->gtCall.gtCallCookie ? gtCloneExpr(tree->gtCall.gtCallCookie, addFlags, deepVarNum, deepVarVal) + : nullptr; + copy->gtCall.gtCallAddr = tree->gtCall.gtCallAddr + ? gtCloneExpr(tree->gtCall.gtCallAddr, addFlags, deepVarNum, deepVarVal) + : nullptr; } else if (tree->gtFlags & GTF_CALL_VIRT_STUB) { @@ -8205,8 +8222,9 @@ GenTreePtr Compiler::gtCloneExpr(GenTree* tree, copy = gtNewFieldRef(tree->TypeGet(), tree->gtField.gtFldHnd, nullptr, tree->gtField.gtFldOffset); - copy->gtField.gtFldObj = - tree->gtField.gtFldObj ? gtCloneExpr(tree->gtField.gtFldObj, addFlags, varNum, varVal) : nullptr; + copy->gtField.gtFldObj = tree->gtField.gtFldObj + ? gtCloneExpr(tree->gtField.gtFldObj, addFlags, deepVarNum, deepVarVal) + : nullptr; copy->gtField.gtFldMayOverlap = tree->gtField.gtFldMayOverlap; #ifdef FEATURE_READYTORUN_COMPILER copy->gtField.gtFieldLookup = tree->gtField.gtFieldLookup; @@ -8219,10 +8237,10 @@ GenTreePtr Compiler::gtCloneExpr(GenTree* tree, GenTreePtr inds[GT_ARR_MAX_RANK]; for (unsigned dim = 0; dim < tree->gtArrElem.gtArrRank; dim++) { - inds[dim] = gtCloneExpr(tree->gtArrElem.gtArrInds[dim], addFlags, varNum, varVal); + inds[dim] = gtCloneExpr(tree->gtArrElem.gtArrInds[dim], addFlags, deepVarNum, deepVarVal); } copy = new (this, GT_ARR_ELEM) - GenTreeArrElem(tree->TypeGet(), gtCloneExpr(tree->gtArrElem.gtArrObj, addFlags, varNum, varVal), + GenTreeArrElem(tree->TypeGet(), gtCloneExpr(tree->gtArrElem.gtArrObj, addFlags, deepVarNum, deepVarVal), tree->gtArrElem.gtArrRank, tree->gtArrElem.gtArrElemSize, tree->gtArrElem.gtArrElemType, &inds[0]); } @@ -8231,34 +8249,37 @@ GenTreePtr Compiler::gtCloneExpr(GenTree* tree, case GT_ARR_OFFSET: { copy = new (this, GT_ARR_OFFSET) - GenTreeArrOffs(tree->TypeGet(), gtCloneExpr(tree->gtArrOffs.gtOffset, addFlags, varNum, varVal), - gtCloneExpr(tree->gtArrOffs.gtIndex, addFlags, varNum, varVal), - gtCloneExpr(tree->gtArrOffs.gtArrObj, addFlags, varNum, varVal), + GenTreeArrOffs(tree->TypeGet(), gtCloneExpr(tree->gtArrOffs.gtOffset, addFlags, deepVarNum, deepVarVal), + gtCloneExpr(tree->gtArrOffs.gtIndex, addFlags, deepVarNum, deepVarVal), + gtCloneExpr(tree->gtArrOffs.gtArrObj, addFlags, deepVarNum, deepVarVal), tree->gtArrOffs.gtCurrDim, tree->gtArrOffs.gtArrRank, tree->gtArrOffs.gtArrElemType); } break; case GT_CMPXCHG: copy = new (this, GT_CMPXCHG) - GenTreeCmpXchg(tree->TypeGet(), gtCloneExpr(tree->gtCmpXchg.gtOpLocation, addFlags, varNum, varVal), - gtCloneExpr(tree->gtCmpXchg.gtOpValue, addFlags, varNum, varVal), - gtCloneExpr(tree->gtCmpXchg.gtOpComparand, addFlags, varNum, varVal)); + GenTreeCmpXchg(tree->TypeGet(), + gtCloneExpr(tree->gtCmpXchg.gtOpLocation, addFlags, deepVarNum, deepVarVal), + gtCloneExpr(tree->gtCmpXchg.gtOpValue, addFlags, deepVarNum, deepVarVal), + gtCloneExpr(tree->gtCmpXchg.gtOpComparand, addFlags, deepVarNum, deepVarVal)); break; case GT_ARR_BOUNDS_CHECK: #ifdef FEATURE_SIMD case GT_SIMD_CHK: #endif // FEATURE_SIMD - copy = new (this, oper) GenTreeBoundsChk(oper, tree->TypeGet(), - gtCloneExpr(tree->gtBoundsChk.gtArrLen, addFlags, varNum, varVal), - gtCloneExpr(tree->gtBoundsChk.gtIndex, addFlags, varNum, varVal), - tree->gtBoundsChk.gtThrowKind); + copy = new (this, oper) + GenTreeBoundsChk(oper, tree->TypeGet(), + gtCloneExpr(tree->gtBoundsChk.gtArrLen, addFlags, deepVarNum, deepVarVal), + gtCloneExpr(tree->gtBoundsChk.gtIndex, addFlags, deepVarNum, deepVarVal), + tree->gtBoundsChk.gtThrowKind); break; case GT_STORE_DYN_BLK: case GT_DYN_BLK: - copy = new (this, oper) GenTreeDynBlk(gtCloneExpr(tree->gtDynBlk.Addr(), addFlags, varNum, varVal), - gtCloneExpr(tree->gtDynBlk.gtDynamicSize, addFlags, varNum, varVal)); + copy = new (this, oper) + GenTreeDynBlk(gtCloneExpr(tree->gtDynBlk.Addr(), addFlags, deepVarNum, deepVarVal), + gtCloneExpr(tree->gtDynBlk.gtDynamicSize, addFlags, deepVarNum, deepVarVal)); break; default: diff --git a/src/jit/optimizer.cpp b/src/jit/optimizer.cpp index 36d7059443..27990e8a79 100644 --- a/src/jit/optimizer.cpp +++ b/src/jit/optimizer.cpp @@ -4663,7 +4663,11 @@ void Compiler::optCloneLoop(unsigned loopInd, LoopCloneContext* context) BasicBlock* newBlk = fgNewBBafter(blk->bbJumpKind, newPred, /*extendRegion*/ true); - BasicBlock::CloneBlockState(this, newBlk, blk); + // Call CloneBlockState to make a copy of the block's statements (and attributes), and assert that it + // has a return value indicating success, because optCanOptimizeByLoopCloningVisitor has already + // checked them to guarantee they are clonable. + bool cloneOk = BasicBlock::CloneBlockState(this, newBlk, blk); + noway_assert(cloneOk); // TODO-Cleanup: The above clones the bbNatLoopNum, which is incorrect. Eventually, we should probably insert // the cloned loop in the loop table. For now, however, we'll just make these blocks be part of the surrounding // loop, if one exists -- the parent of the loop we're cloning. diff --git a/src/mscorlib/corefx/System/Globalization/CultureInfo.cs b/src/mscorlib/corefx/System/Globalization/CultureInfo.cs index 7d44282ff5..ceee47c322 100644 --- a/src/mscorlib/corefx/System/Globalization/CultureInfo.cs +++ b/src/mscorlib/corefx/System/Globalization/CultureInfo.cs @@ -1024,7 +1024,7 @@ namespace System.Globalization { NumberFormatInfo temp = new NumberFormatInfo(this.m_cultureData); temp.isReadOnly = m_isReadOnly; - numInfo = temp; + Interlocked.CompareExchange(ref numInfo, temp, null); } return (numInfo); } @@ -1056,8 +1056,7 @@ namespace System.Globalization // Change the calendar of DTFI to the specified calendar of this CultureInfo. DateTimeFormatInfo temp = new DateTimeFormatInfo(this.m_cultureData, this.Calendar); temp._isReadOnly = m_isReadOnly; - System.Threading.Interlocked.MemoryBarrier(); - dateTimeInfo = temp; + Interlocked.CompareExchange(ref dateTimeInfo, temp, null); } return (dateTimeInfo); } diff --git a/src/mscorlib/src/System/Globalization/CultureInfo.cs b/src/mscorlib/src/System/Globalization/CultureInfo.cs index baaf334852..1ef3809e3c 100644 --- a/src/mscorlib/src/System/Globalization/CultureInfo.cs +++ b/src/mscorlib/src/System/Globalization/CultureInfo.cs @@ -1345,7 +1345,7 @@ namespace System.Globalization { if (numInfo == null) { NumberFormatInfo temp = new NumberFormatInfo(this.m_cultureData); temp.isReadOnly = m_isReadOnly; - numInfo = temp; + Interlocked.CompareExchange(ref numInfo, temp, null); } return (numInfo); } @@ -1379,8 +1379,7 @@ namespace System.Globalization { DateTimeFormatInfo temp = new DateTimeFormatInfo( this.m_cultureData, this.Calendar); temp.m_isReadOnly = m_isReadOnly; - System.Threading.Thread.MemoryBarrier(); - dateTimeInfo = temp; + Interlocked.CompareExchange(ref dateTimeInfo, temp, null); } return (dateTimeInfo); } |