1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
19 /*****************************************************************************
21 * Helper passed to Compiler::fgWalkTreePre() to find the Asgn node for optAddCopies()
25 Compiler::fgWalkResult Compiler::optAddCopiesCallback(GenTree** pTree, fgWalkData* data)
27 GenTree* tree = *pTree;
29 if (tree->OperIsAssignment())
31 GenTree* op1 = tree->gtOp.gtOp1;
32 Compiler* comp = data->compiler;
34 if ((op1->gtOper == GT_LCL_VAR) && (op1->gtLclVarCommon.gtLclNum == comp->optAddCopyLclNum))
36 comp->optAddCopyAsgnNode = tree;
43 /*****************************************************************************
45 * Add new copies before Assertion Prop.
48 void Compiler::optAddCopies()
56 printf("\n*************** In optAddCopies()\n\n");
60 printf("Blocks/Trees at start of phase\n");
61 fgDispBasicBlocks(true);
65 // Don't add any copies if we have reached the tracking limit.
66 if (lvaHaveManyLocals())
71 for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
73 var_types typ = varDsc->TypeGet();
75 // We only add copies for non temp local variables
76 // that have a single def and that can possibly be enregistered
78 if (varDsc->lvIsTemp || !varDsc->lvSingleDef || !varTypeCanReg(typ))
83 /* For lvNormalizeOnLoad(), we need to add a cast to the copy-assignment
84 like "copyLclNum = int(varDsc)" and optAssertionGen() only
85 tracks simple assignments. The same goes for lvNormalizedOnStore as
86 the cast is generated in fgMorphSmpOpAsg. This boils down to not having
87 a copy until optAssertionGen handles this*/
88 if (varDsc->lvNormalizeOnLoad() || varDsc->lvNormalizeOnStore() || typ == TYP_BOOL)
93 if (varTypeIsSmall(varDsc->TypeGet()) || typ == TYP_BOOL)
98 // If locals must be initialized to zero, that initialization counts as a second definition.
99 // VB in particular allows usage of variables not explicitly initialized.
100 // Note that this effectively disables this optimization for all local variables
101 // as C# sets InitLocals all the time starting in Whidbey.
103 if (!varDsc->lvIsParam && info.compInitMem)
108 // On x86 we may want to add a copy for an incoming double parameter
109 // because we can ensure that the copy we make is double aligned
110 // where as we can never ensure the alignment of an incoming double parameter
112 // On all other platforms we will never need to make a copy
113 // for an incoming double parameter
115 bool isFloatParam = false;
118 isFloatParam = varDsc->lvIsParam && varTypeIsFloating(typ);
121 if (!isFloatParam && !varDsc->lvVolatileHint)
126 // We don't want to add a copy for a variable that is part of a struct
127 if (varDsc->lvIsStructField)
132 // We require that the weighted ref count be significant.
133 if (varDsc->lvRefCntWtd <= (BB_LOOP_WEIGHT * BB_UNITY_WEIGHT / 2))
138 // For parameters, we only want to add a copy for the heavier-than-average
139 // uses instead of adding a copy to cover every single use.
140 // 'paramImportantUseDom' is the set of blocks that dominate the
141 // heavier-than-average uses of a parameter.
142 // Initial value is all blocks.
144 BlockSet paramImportantUseDom(BlockSetOps::MakeFull(this));
146 // This will be threshold for determining heavier-than-average uses
147 unsigned paramAvgWtdRefDiv2 = (varDsc->lvRefCntWtd + varDsc->lvRefCnt / 2) / (varDsc->lvRefCnt * 2);
149 bool paramFoundImportantUse = false;
154 printf("Trying to add a copy for V%02u %s, avg_wtd = %s\n", lclNum,
155 varDsc->lvIsParam ? "an arg" : "a local", refCntWtd2str(paramAvgWtdRefDiv2));
160 // We must have a ref in a block that is dominated only by the entry block
163 if (BlockSetOps::MayBeUninit(varDsc->lvRefBlks))
169 bool isDominatedByFirstBB = false;
171 BlockSetOps::Iter iter(this, varDsc->lvRefBlks);
173 while (iter.NextElem(&bbNum))
175 /* Find the block 'bbNum' */
176 BasicBlock* block = fgFirstBB;
177 while (block && (block->bbNum != bbNum))
179 block = block->bbNext;
181 noway_assert(block && (block->bbNum == bbNum));
183 bool importantUseInBlock = (varDsc->lvIsParam) && (block->getBBWeight(this) > paramAvgWtdRefDiv2);
184 bool isPreHeaderBlock = ((block->bbFlags & BBF_LOOP_PREHEADER) != 0);
185 BlockSet blockDom(BlockSetOps::UninitVal());
186 BlockSet blockDomSub0(BlockSetOps::UninitVal());
188 if (block->bbIDom == nullptr && isPreHeaderBlock)
190 // Loop Preheader blocks that we insert will have a bbDom set that is nullptr
191 // but we can instead use the bNext successor block's dominator information
192 noway_assert(block->bbNext != nullptr);
193 BlockSetOps::AssignNoCopy(this, blockDom, fgGetDominatorSet(block->bbNext));
197 BlockSetOps::AssignNoCopy(this, blockDom, fgGetDominatorSet(block));
200 if (!BlockSetOps::IsEmpty(this, blockDom))
202 BlockSetOps::Assign(this, blockDomSub0, blockDom);
203 if (isPreHeaderBlock)
205 // We must clear bbNext block number from the dominator set
206 BlockSetOps::RemoveElemD(this, blockDomSub0, block->bbNext->bbNum);
208 /* Is this block dominated by fgFirstBB? */
209 if (BlockSetOps::IsMember(this, blockDomSub0, fgFirstBB->bbNum))
211 isDominatedByFirstBB = true;
218 printf(" Referenced in BB%02u, bbWeight is %s", bbNum, refCntWtd2str(block->getBBWeight(this)));
220 if (isDominatedByFirstBB)
222 printf(", which is dominated by BB01");
225 if (importantUseInBlock)
227 printf(", ImportantUse");
234 /* If this is a heavier-than-average block, then track which
235 blocks dominate this use of the parameter. */
236 if (importantUseInBlock)
238 paramFoundImportantUse = true;
239 BlockSetOps::IntersectionD(this, paramImportantUseDom,
240 blockDomSub0); // Clear blocks that do not dominate
244 // We should have found at least one heavier-than-averageDiv2 block.
245 if (varDsc->lvIsParam)
247 if (!paramFoundImportantUse)
253 // For us to add a new copy:
254 // we require that we have a floating point parameter
255 // or a lvVolatile variable that is always reached from the first BB
256 // and we have at least one block available in paramImportantUseDom
258 bool doCopy = (isFloatParam || (isDominatedByFirstBB && varDsc->lvVolatileHint)) &&
259 !BlockSetOps::IsEmpty(this, paramImportantUseDom);
261 // Under stress mode we expand the number of candidates
262 // to include parameters of any type
263 // or any variable that is always reached from the first BB
265 if (compStressCompile(STRESS_GENERIC_VARN, 30))
267 // Ensure that we preserve the invariants required by the subsequent code.
268 if (varDsc->lvIsParam || isDominatedByFirstBB)
280 unsigned copyLclNum = lvaGrabTemp(false DEBUGARG("optAddCopies"));
282 // Because lvaGrabTemp may have reallocated the lvaTable, ensure varDsc
283 // is still in sync with lvaTable[lclNum];
284 varDsc = &lvaTable[lclNum];
286 // Set lvType on the new Temp Lcl Var
287 lvaTable[copyLclNum].lvType = typ;
292 printf("\n Finding the best place to insert the assignment V%02i=V%02i\n", copyLclNum, lclNum);
296 if (varDsc->lvIsParam)
298 noway_assert(varDsc->lvDefStmt == nullptr || varDsc->lvIsStructField);
300 // Create a new copy assignment tree
301 GenTree* copyAsgn = gtNewTempAssign(copyLclNum, gtNewLclvNode(lclNum, typ));
303 /* Find the best block to insert the new assignment */
304 /* We will choose the lowest weighted block, and within */
305 /* those block, the highest numbered block which */
306 /* dominates all the uses of the local variable */
308 /* Our default is to use the first block */
309 BasicBlock* bestBlock = fgFirstBB;
310 unsigned bestWeight = bestBlock->getBBWeight(this);
311 BasicBlock* block = bestBlock;
316 printf(" Starting at BB%02u, bbWeight is %s", block->bbNum,
317 refCntWtd2str(block->getBBWeight(this)));
319 printf(", bestWeight is %s\n", refCntWtd2str(bestWeight));
323 /* We have already calculated paramImportantUseDom above. */
324 BlockSetOps::Iter iter(this, paramImportantUseDom);
326 while (iter.NextElem(&bbNum))
328 /* Advance block to point to 'bbNum' */
329 /* This assumes that the iterator returns block number is increasing lexical order. */
330 while (block && (block->bbNum != bbNum))
332 block = block->bbNext;
334 noway_assert(block && (block->bbNum == bbNum));
339 printf(" Considering BB%02u, bbWeight is %s", block->bbNum,
340 refCntWtd2str(block->getBBWeight(this)));
342 printf(", bestWeight is %s\n", refCntWtd2str(bestWeight));
346 // Does this block have a smaller bbWeight value?
347 if (block->getBBWeight(this) > bestWeight)
352 printf("bbWeight too high\n");
358 // Don't use blocks that are exception handlers because
359 // inserting a new first statement will interface with
362 if (handlerGetsXcptnObj(block->bbCatchTyp))
367 printf("Catch block\n");
373 // Don't use the BBJ_ALWAYS block marked with BBF_KEEP_BBJ_ALWAYS. These
374 // are used by EH code. The JIT can not generate code for such a block.
376 if (block->bbFlags & BBF_KEEP_BBJ_ALWAYS)
378 #if FEATURE_EH_FUNCLETS
379 // With funclets, this is only used for BBJ_CALLFINALLY/BBJ_ALWAYS pairs. For x86, it is also used
380 // as the "final step" block for leaving finallys.
381 assert((block->bbPrev != nullptr) && block->bbPrev->isBBCallAlwaysPair());
382 #endif // FEATURE_EH_FUNCLETS
386 printf("Internal EH BBJ_ALWAYS block\n");
392 // This block will be the new candidate for the insert point
393 // for the new assignment
394 CLANG_FORMAT_COMMENT_ANCHOR;
399 printf("new bestBlock\n");
404 bestWeight = block->getBBWeight(this);
407 // If there is a use of the variable in this block
408 // then we insert the assignment at the beginning
409 // otherwise we insert the statement at the end
410 CLANG_FORMAT_COMMENT_ANCHOR;
415 printf(" Insert copy at the %s of BB%02u\n",
416 (BlockSetOps::IsEmpty(this, paramImportantUseDom) ||
417 BlockSetOps::IsMember(this, varDsc->lvRefBlks, bestBlock->bbNum))
424 if (BlockSetOps::IsEmpty(this, paramImportantUseDom) ||
425 BlockSetOps::IsMember(this, varDsc->lvRefBlks, bestBlock->bbNum))
427 stmt = fgInsertStmtAtBeg(bestBlock, copyAsgn);
431 stmt = fgInsertStmtNearEnd(bestBlock, copyAsgn);
434 /* Increment its lvRefCnt and lvRefCntWtd */
435 lvaTable[lclNum].incRefCnts(fgFirstBB->getBBWeight(this), this);
437 /* Increment its lvRefCnt and lvRefCntWtd */
438 lvaTable[copyLclNum].incRefCnts(fgFirstBB->getBBWeight(this), this);
442 noway_assert(varDsc->lvDefStmt != nullptr);
444 /* Locate the assignment to varDsc in the lvDefStmt */
445 stmt = varDsc->lvDefStmt;
446 noway_assert(stmt->gtOper == GT_STMT);
448 optAddCopyLclNum = lclNum; // in
449 optAddCopyAsgnNode = nullptr; // out
451 fgWalkTreePre(&stmt->gtStmt.gtStmtExpr, Compiler::optAddCopiesCallback, (void*)this, false);
453 noway_assert(optAddCopyAsgnNode);
455 GenTree* tree = optAddCopyAsgnNode;
456 GenTree* op1 = tree->gtOp.gtOp1;
458 noway_assert(tree && op1 && tree->OperIsAssignment() && (op1->gtOper == GT_LCL_VAR) &&
459 (op1->gtLclVarCommon.gtLclNum == lclNum));
461 /* TODO-Review: BB_UNITY_WEIGHT is not the correct block weight */
462 unsigned blockWeight = BB_UNITY_WEIGHT;
464 /* Increment its lvRefCnt and lvRefCntWtd twice */
465 lvaTable[copyLclNum].incRefCnts(blockWeight, this);
466 lvaTable[copyLclNum].incRefCnts(blockWeight, this);
468 /* Assign the old expression into the new temp */
470 GenTree* newAsgn = gtNewTempAssign(copyLclNum, tree->gtOp.gtOp2);
472 /* Copy the new temp to op1 */
474 GenTree* copyAsgn = gtNewAssignNode(op1, gtNewLclvNode(copyLclNum, typ));
476 /* Change the tree to a GT_COMMA with the two assignments as child nodes */
479 tree->ChangeOper(GT_COMMA);
481 tree->gtOp.gtOp1 = newAsgn;
482 tree->gtOp.gtOp2 = copyAsgn;
484 tree->gtFlags |= (newAsgn->gtFlags & GTF_ALL_EFFECT);
485 tree->gtFlags |= (copyAsgn->gtFlags & GTF_ALL_EFFECT);
491 printf("\nIntroducing a new copy for V%02u\n", lclNum);
492 gtDispTree(stmt->gtStmt.gtStmtExpr);
499 //------------------------------------------------------------------------------
500 // GetAssertionDep: Retrieve the assertions on this local variable
503 // lclNum - The local var id.
506 // The dependent assertions (assertions using the value of the local var)
510 ASSERT_TP& Compiler::GetAssertionDep(unsigned lclNum)
512 JitExpandArray<ASSERT_TP>& dep = *optAssertionDep;
513 if (dep[lclNum] == nullptr)
515 dep[lclNum] = BitVecOps::MakeEmpty(apTraits);
520 /*****************************************************************************
522 * Initialize the assertion prop bitset traits and the default bitsets.
525 void Compiler::optAssertionTraitsInit(AssertionIndex assertionCount)
527 apTraits = new (this, CMK_AssertionProp) BitVecTraits(assertionCount, this);
528 apFull = BitVecOps::MakeFull(apTraits);
531 /*****************************************************************************
533 * Initialize the assertion prop tracking logic.
536 void Compiler::optAssertionInit(bool isLocalProp)
538 // Use a function countFunc to determine a proper maximum assertion count for the
539 // method being compiled. The function is linear to the IL size for small and
540 // moderate methods. For large methods, considering throughput impact, we track no
541 // more than 64 assertions.
542 // Note this tracks at most only 256 assertions.
543 static const AssertionIndex countFunc[] = {64, 128, 256, 64};
544 static const unsigned lowerBound = 0;
545 static const unsigned upperBound = _countof(countFunc) - 1;
546 const unsigned codeSize = info.compILCodeSize / 512;
547 optMaxAssertionCount = countFunc[isLocalProp ? lowerBound : min(upperBound, codeSize)];
549 optLocalAssertionProp = isLocalProp;
550 optAssertionTabPrivate = new (this, CMK_AssertionProp) AssertionDsc[optMaxAssertionCount];
551 optComplementaryAssertionMap =
552 new (this, CMK_AssertionProp) AssertionIndex[optMaxAssertionCount + 1](); // zero-inited (NO_ASSERTION_INDEX)
553 assert(NO_ASSERTION_INDEX == 0);
557 optValueNumToAsserts = new (getAllocator()) ValueNumToAssertsMap(getAllocator());
560 if (optAssertionDep == nullptr)
562 optAssertionDep = new (this, CMK_AssertionProp) JitExpandArray<ASSERT_TP>(getAllocator(), max(1, lvaCount));
565 optAssertionTraitsInit(optMaxAssertionCount);
566 optAssertionCount = 0;
567 optAssertionPropagated = false;
568 bbJtrueAssertionOut = nullptr;
572 void Compiler::optPrintAssertion(AssertionDsc* curAssertion, AssertionIndex assertionIndex /* =0 */)
574 if (curAssertion->op1.kind == O1K_EXACT_TYPE)
578 else if (curAssertion->op1.kind == O1K_ARR_BND)
582 else if (curAssertion->op1.kind == O1K_SUBTYPE)
586 else if (curAssertion->op2.kind == O2K_LCLVAR_COPY)
590 else if ((curAssertion->op2.kind == O2K_CONST_INT) || (curAssertion->op2.kind == O2K_CONST_LONG) ||
591 (curAssertion->op2.kind == O2K_CONST_DOUBLE))
595 else if (curAssertion->op2.kind == O2K_SUBRANGE)
601 printf("?assertion classification? ");
603 printf("Assertion: ");
604 if (!optLocalAssertionProp)
606 printf("(%d, %d) ", curAssertion->op1.vn, curAssertion->op2.vn);
609 if (!optLocalAssertionProp)
611 printf("(" STR_VN "%x," STR_VN "%x) ", curAssertion->op1.vn, curAssertion->op2.vn);
614 if ((curAssertion->op1.kind == O1K_LCLVAR) || (curAssertion->op1.kind == O1K_EXACT_TYPE) ||
615 (curAssertion->op1.kind == O1K_SUBTYPE))
617 printf("V%02u", curAssertion->op1.lcl.lclNum);
618 if (curAssertion->op1.lcl.ssaNum != SsaConfig::RESERVED_SSA_NUM)
620 printf(".%02u", curAssertion->op1.lcl.ssaNum);
623 else if (curAssertion->op1.kind == O1K_ARR_BND)
626 vnStore->vnDump(this, curAssertion->op1.bnd.vnIdx);
628 vnStore->vnDump(this, curAssertion->op1.bnd.vnLen);
631 else if (curAssertion->op1.kind == O1K_BOUND_OPER_BND)
634 vnStore->vnDump(this, curAssertion->op1.vn);
636 else if (curAssertion->op1.kind == O1K_BOUND_LOOP_BND)
639 vnStore->vnDump(this, curAssertion->op1.vn);
641 else if (curAssertion->op1.kind == O1K_CONSTANT_LOOP_BND)
644 vnStore->vnDump(this, curAssertion->op1.vn);
646 else if (curAssertion->op1.kind == O1K_VALUE_NUMBER)
648 printf("Value_Number");
649 vnStore->vnDump(this, curAssertion->op1.vn);
653 printf("?op1.kind?");
656 if (curAssertion->assertionKind == OAK_SUBRANGE)
660 else if (curAssertion->assertionKind == OAK_EQUAL)
662 if (curAssertion->op1.kind == O1K_LCLVAR)
671 else if (curAssertion->assertionKind == OAK_NO_THROW)
673 printf(" in range ");
675 else if (curAssertion->assertionKind == OAK_NOT_EQUAL)
677 if (curAssertion->op1.kind == O1K_LCLVAR)
688 printf(" ?assertionKind? ");
691 if (curAssertion->op1.kind != O1K_ARR_BND)
693 switch (curAssertion->op2.kind)
695 case O2K_LCLVAR_COPY:
696 printf("V%02u", curAssertion->op2.lcl.lclNum);
697 if (curAssertion->op1.lcl.ssaNum != SsaConfig::RESERVED_SSA_NUM)
699 printf(".%02u", curAssertion->op1.lcl.ssaNum);
704 case O2K_IND_CNS_INT:
705 if (curAssertion->op1.kind == O1K_EXACT_TYPE)
707 printf("Exact Type MT(%08X)", dspPtr(curAssertion->op2.u1.iconVal));
708 assert(curAssertion->op2.u1.iconFlags != 0);
710 else if (curAssertion->op1.kind == O1K_SUBTYPE)
712 printf("MT(%08X)", dspPtr(curAssertion->op2.u1.iconVal));
713 assert(curAssertion->op2.u1.iconFlags != 0);
715 else if (curAssertion->op1.kind == O1K_BOUND_OPER_BND)
717 assert(!optLocalAssertionProp);
718 vnStore->vnDump(this, curAssertion->op2.vn);
720 else if (curAssertion->op1.kind == O1K_BOUND_LOOP_BND)
722 assert(!optLocalAssertionProp);
723 vnStore->vnDump(this, curAssertion->op2.vn);
725 else if (curAssertion->op1.kind == O1K_CONSTANT_LOOP_BND)
727 assert(!optLocalAssertionProp);
728 vnStore->vnDump(this, curAssertion->op2.vn);
734 if (curAssertion->op1.kind == O1K_VALUE_NUMBER)
736 op1Type = vnStore->TypeOfVN(curAssertion->op1.vn);
740 unsigned lclNum = curAssertion->op1.lcl.lclNum;
741 assert(lclNum < lvaCount);
742 LclVarDsc* varDsc = lvaTable + lclNum;
743 op1Type = varDsc->lvType;
746 if (op1Type == TYP_REF)
748 assert(curAssertion->op2.u1.iconVal == 0);
753 if ((curAssertion->op2.u1.iconFlags & GTF_ICON_HDL_MASK) != 0)
755 printf("[%08p]", dspPtr(curAssertion->op2.u1.iconVal));
759 printf("%d", curAssertion->op2.u1.iconVal);
766 printf("0x%016llx", curAssertion->op2.lconVal);
769 case O2K_CONST_DOUBLE:
770 if (*((__int64*)&curAssertion->op2.dconVal) == (__int64)I64(0x8000000000000000))
776 printf("%#lg", curAssertion->op2.dconVal);
781 printf("[%d..%d]", curAssertion->op2.u2.loBound, curAssertion->op2.u2.hiBound);
785 printf("?op2.kind?");
790 if (assertionIndex > 0)
792 printf(" index=#%02u, mask=", assertionIndex);
793 printf("%s", BitVecOps::ToString(apTraits, BitVecOps::MakeSingleton(apTraits, assertionIndex - 1)));
799 /******************************************************************************
801 * Helper to retrieve the "assertIndex" assertion. Note that assertIndex 0
802 * is NO_ASSERTION_INDEX and "optAssertionCount" is the last valid index.
805 Compiler::AssertionDsc* Compiler::optGetAssertion(AssertionIndex assertIndex)
807 assert(NO_ASSERTION_INDEX == 0);
808 assert(assertIndex != NO_ASSERTION_INDEX);
809 assert(assertIndex <= optAssertionCount);
810 AssertionDsc* assertion = &optAssertionTabPrivate[assertIndex - 1];
812 optDebugCheckAssertion(assertion);
818 /*****************************************************************************
820 * A simple helper routine so not all callers need to supply a AssertionDsc*
821 * if they don't care about it. Refer overloaded method optCreateAssertion.
824 AssertionIndex Compiler::optCreateAssertion(GenTree* op1, GenTree* op2, optAssertionKind assertionKind)
826 AssertionDsc assertionDsc;
827 return optCreateAssertion(op1, op2, assertionKind, &assertionDsc);
830 /*****************************************************************************
832 * We attempt to create the following assertion:
834 * op1 assertionKind op2
836 * If we can create the assertion then update 'assertion' if we are
837 * unsuccessful assertion->assertionKind will be OAK_INVALID. If we are
838 * successful in creating the assertion we call optAddAssertion which adds
839 * the assertion to our assertion table.
841 * If we are able to create the assertion the return value is the
842 * assertionIndex for this assertion otherwise the return value is
843 * NO_ASSERTION_INDEX and we could not create the assertion.
846 AssertionIndex Compiler::optCreateAssertion(GenTree* op1,
848 optAssertionKind assertionKind,
849 AssertionDsc* assertion)
851 memset(assertion, 0, sizeof(AssertionDsc));
853 // If we cannot create an assertion using op1 and op2 then the assertionKind
854 // must be OAK_INVALID, so we initialize it to OAK_INVALID and only change it
855 // to a valid assertion when everything is good.
857 assertion->assertionKind = OAK_INVALID;
858 bool haveArgs = false;
861 if (op1->gtOper == GT_ARR_BOUNDS_CHECK)
863 if (assertionKind == OAK_NO_THROW)
865 GenTreeBoundsChk* arrBndsChk = op1->AsBoundsChk();
866 assertion->assertionKind = assertionKind;
867 assertion->op1.kind = O1K_ARR_BND;
868 assertion->op1.bnd.vnIdx = arrBndsChk->gtIndex->gtVNPair.GetConservative();
869 assertion->op1.bnd.vnLen = arrBndsChk->gtArrLen->gtVNPair.GetConservative();
875 // Did we receive Helper call args?
877 if (op1->gtOper == GT_LIST)
879 if (op2->gtOper != GT_LIST)
881 goto DONE_ASSERTION; // Don't make an assertion
883 op1 = op1->gtOp.gtOp1;
884 op2 = op2->gtOp.gtOp1;
889 // Are we trying to make a non-null assertion?
893 assert(haveArgs == false);
895 // Must an OAK_NOT_EQUAL assertion
897 noway_assert(assertionKind == OAK_NOT_EQUAL);
900 // Set op1 to the instance pointer of the indirection
904 while ((op1->gtOper == GT_ADD) && (op1->gtType == TYP_BYREF))
906 if (op1->gtGetOp2()->IsCnsIntOrI())
908 offset += op1->gtGetOp2()->gtIntCon.gtIconVal;
909 op1 = op1->gtGetOp1();
911 else if (op1->gtGetOp1()->IsCnsIntOrI())
913 offset += op1->gtGetOp1()->gtIntCon.gtIconVal;
914 op1 = op1->gtGetOp2();
922 if (fgIsBigOffset(offset) || op1->gtOper != GT_LCL_VAR)
924 goto DONE_ASSERTION; // Don't make an assertion
927 unsigned lclNum = op1->gtLclVarCommon.gtLclNum;
928 noway_assert(lclNum < lvaCount);
929 LclVarDsc* lclVar = &lvaTable[lclNum];
934 // We only perform null-checks on GC refs
935 // so only make non-null assertions about GC refs
937 if (lclVar->TypeGet() != TYP_REF)
939 if (optLocalAssertionProp || (lclVar->TypeGet() != TYP_BYREF))
941 goto DONE_ASSERTION; // Don't make an assertion
944 vn = op1->gtVNPair.GetConservative();
947 // Try to get value number corresponding to the GC ref of the indirection
948 while (vnStore->GetVNFunc(vn, &funcAttr) && (funcAttr.m_func == (VNFunc)GT_ADD) &&
949 (vnStore->TypeOfVN(vn) == TYP_BYREF))
951 if (vnStore->IsVNConstant(funcAttr.m_args[1]) &&
952 varTypeIsIntegral(vnStore->TypeOfVN(funcAttr.m_args[1])))
954 offset += vnStore->CoercedConstantValue<ssize_t>(funcAttr.m_args[1]);
955 vn = funcAttr.m_args[0];
957 else if (vnStore->IsVNConstant(funcAttr.m_args[0]) &&
958 varTypeIsIntegral(vnStore->TypeOfVN(funcAttr.m_args[0])))
960 offset += vnStore->CoercedConstantValue<ssize_t>(funcAttr.m_args[0]);
961 vn = funcAttr.m_args[1];
969 if (fgIsBigOffset(offset) || (vnStore->TypeOfVN(vn) != TYP_REF))
971 goto DONE_ASSERTION; // Don't make an assertion
974 assertion->op1.kind = O1K_VALUE_NUMBER;
978 // If the local variable has its address exposed then bail
979 if (lclVar->lvAddrExposed)
981 goto DONE_ASSERTION; // Don't make an assertion
984 assertion->op1.kind = O1K_LCLVAR;
985 assertion->op1.lcl.lclNum = lclNum;
986 assertion->op1.lcl.ssaNum = op1->AsLclVarCommon()->GetSsaNum();
987 vn = op1->gtVNPair.GetConservative();
990 assertion->op1.vn = vn;
991 assertion->assertionKind = assertionKind;
992 assertion->op2.kind = O2K_CONST_INT;
993 assertion->op2.vn = ValueNumStore::VNForNull();
994 assertion->op2.u1.iconVal = 0;
995 assertion->op2.u1.iconFlags = 0;
996 #ifdef _TARGET_64BIT_
997 assertion->op2.u1.iconFlags |= 1; // Signify that this is really TYP_LONG
998 #endif // _TARGET_64BIT_
1001 // Are we making an assertion about a local variable?
1003 else if (op1->gtOper == GT_LCL_VAR)
1005 unsigned lclNum = op1->gtLclVarCommon.gtLclNum;
1006 noway_assert(lclNum < lvaCount);
1007 LclVarDsc* lclVar = &lvaTable[lclNum];
1009 // If the local variable has its address exposed then bail
1010 if (lclVar->lvAddrExposed)
1012 goto DONE_ASSERTION; // Don't make an assertion
1018 // Must either be an OAK_EQUAL or an OAK_NOT_EQUAL assertion
1020 if ((assertionKind != OAK_EQUAL) && (assertionKind != OAK_NOT_EQUAL))
1022 goto DONE_ASSERTION; // Don't make an assertion
1025 if (op2->gtOper == GT_IND)
1027 op2 = op2->gtOp.gtOp1;
1028 assertion->op2.kind = O2K_IND_CNS_INT;
1032 assertion->op2.kind = O2K_CONST_INT;
1035 if (op2->gtOper != GT_CNS_INT)
1037 goto DONE_ASSERTION; // Don't make an assertion
1041 // TODO-CQ: Check for Sealed class and change kind to O1K_EXACT_TYPE
1042 // And consider the special cases, like CORINFO_FLG_SHAREDINST or CORINFO_FLG_VARIANCE
1043 // where a class can be sealed, but they don't behave as exact types because casts to
1044 // non-base types sometimes still succeed.
1046 assertion->op1.kind = O1K_SUBTYPE;
1047 assertion->op1.lcl.lclNum = lclNum;
1048 assertion->op1.vn = op1->gtVNPair.GetConservative();
1049 assertion->op1.lcl.ssaNum = op1->AsLclVarCommon()->GetSsaNum();
1050 assertion->op2.u1.iconVal = op2->gtIntCon.gtIconVal;
1051 assertion->op2.vn = op2->gtVNPair.GetConservative();
1052 assertion->op2.u1.iconFlags = op2->GetIconHandleFlag();
1055 // Ok everything has been set and the assertion looks good
1057 assertion->assertionKind = assertionKind;
1061 /* Skip over a GT_COMMA node(s), if necessary */
1062 while (op2->gtOper == GT_COMMA)
1064 op2 = op2->gtOp.gtOp2;
1067 assertion->op1.kind = O1K_LCLVAR;
1068 assertion->op1.lcl.lclNum = lclNum;
1069 assertion->op1.vn = op1->gtVNPair.GetConservative();
1070 assertion->op1.lcl.ssaNum = op1->AsLclVarCommon()->GetSsaNum();
1072 switch (op2->gtOper)
1079 goto DONE_ASSERTION; // Don't make an assertion
1082 // Constant Assertions
1085 op2Kind = O2K_CONST_INT;
1089 op2Kind = O2K_CONST_LONG;
1093 op2Kind = O2K_CONST_DOUBLE;
1099 // Must either be an OAK_EQUAL or an OAK_NOT_EQUAL assertion
1101 if ((assertionKind != OAK_EQUAL) && (assertionKind != OAK_NOT_EQUAL))
1103 goto DONE_ASSERTION; // Don't make an assertion
1106 // If the LclVar is a TYP_LONG then we only make
1107 // assertions where op2 is also TYP_LONG
1109 if ((lclVar->TypeGet() == TYP_LONG) && (op2->TypeGet() != TYP_LONG))
1111 goto DONE_ASSERTION; // Don't make an assertion
1114 assertion->op2.kind = op2Kind;
1115 assertion->op2.lconVal = 0;
1116 assertion->op2.vn = op2->gtVNPair.GetConservative();
1118 if (op2->gtOper == GT_CNS_INT)
1121 // Do not Constant-Prop large constants for ARM
1122 if (!codeGen->validImmForMov(op2->gtIntCon.gtIconVal))
1124 goto DONE_ASSERTION; // Don't make an assertion
1126 #endif // _TARGET_ARM_
1127 assertion->op2.u1.iconVal = op2->gtIntCon.gtIconVal;
1128 assertion->op2.u1.iconFlags = op2->GetIconHandleFlag();
1129 #ifdef _TARGET_64BIT_
1130 if (op2->TypeGet() == TYP_LONG || op2->TypeGet() == TYP_BYREF)
1132 assertion->op2.u1.iconFlags |= 1; // Signify that this is really TYP_LONG
1134 #endif // _TARGET_64BIT_
1136 else if (op2->gtOper == GT_CNS_LNG)
1138 assertion->op2.lconVal = op2->gtLngCon.gtLconVal;
1142 noway_assert(op2->gtOper == GT_CNS_DBL);
1143 /* If we have an NaN value then don't record it */
1144 if (_isnan(op2->gtDblCon.gtDconVal))
1146 goto DONE_ASSERTION; // Don't make an assertion
1148 assertion->op2.dconVal = op2->gtDblCon.gtDconVal;
1152 // Ok everything has been set and the assertion looks good
1154 assertion->assertionKind = assertionKind;
1164 // Must either be an OAK_EQUAL or an OAK_NOT_EQUAL assertion
1166 if ((assertionKind != OAK_EQUAL) && (assertionKind != OAK_NOT_EQUAL))
1168 goto DONE_ASSERTION; // Don't make an assertion
1171 unsigned lclNum2 = op2->gtLclVarCommon.gtLclNum;
1172 noway_assert(lclNum2 < lvaCount);
1173 LclVarDsc* lclVar2 = &lvaTable[lclNum2];
1175 // If the two locals are the same then bail
1176 if (lclNum == lclNum2)
1178 goto DONE_ASSERTION; // Don't make an assertion
1181 // If the types are different then bail */
1182 if (lclVar->lvType != lclVar2->lvType)
1184 goto DONE_ASSERTION; // Don't make an assertion
1187 // If the local variable has its address exposed then bail
1188 if (lclVar2->lvAddrExposed)
1190 goto DONE_ASSERTION; // Don't make an assertion
1193 assertion->op2.kind = O2K_LCLVAR_COPY;
1194 assertion->op2.lcl.lclNum = lclNum2;
1195 assertion->op2.vn = op2->gtVNPair.GetConservative();
1196 assertion->op2.lcl.ssaNum = op2->AsLclVarCommon()->GetSsaNum();
1199 // Ok everything has been set and the assertion looks good
1201 assertion->assertionKind = assertionKind;
1205 // Subrange Assertions
1213 /* Assigning the result of a RELOP, we can add a boolean subrange assertion */
1216 goto SUBRANGE_COMMON;
1220 /* Assigning the result of an indirection into a LCL_VAR, see if we can add a subrange assertion */
1222 toType = op2->gtType;
1223 goto SUBRANGE_COMMON;
1227 /* Assigning the result of an indirection into a LCL_VAR, see if we can add a subrange assertion */
1229 toType = op2->gtType;
1230 goto SUBRANGE_COMMON;
1234 /* Assigning the result of an indirection into a LCL_VAR, see if we can add a subrange assertion */
1236 toType = op2->gtType;
1237 goto SUBRANGE_COMMON;
1241 /* Assigning the result of an indirection into a LCL_VAR, see if we can add a subrange assertion */
1243 toType = op2->gtType;
1244 goto SUBRANGE_COMMON;
1248 if (lvaTable[lclNum].lvIsStructField && lvaTable[lclNum].lvNormalizeOnLoad())
1250 // Keep the cast on small struct fields.
1251 goto DONE_ASSERTION; // Don't make an assertion
1254 toType = op2->CastToType();
1256 if ((assertionKind != OAK_SUBRANGE) && (assertionKind != OAK_EQUAL))
1258 goto DONE_ASSERTION; // Don't make an assertion
1261 if (varTypeIsFloating(op1->TypeGet()))
1263 // We don't make assertions on a cast from floating point
1264 goto DONE_ASSERTION;
1274 #ifdef _TARGET_64BIT_
1277 #endif // _TARGET_64BIT_
1278 assertion->op2.u2.loBound = AssertionDsc::GetLowerBoundForIntegralType(toType);
1279 assertion->op2.u2.hiBound = AssertionDsc::GetUpperBoundForIntegralType(toType);
1283 goto DONE_ASSERTION; // Don't make an assertion
1285 assertion->op2.kind = O2K_SUBRANGE;
1286 assertion->assertionKind = OAK_SUBRANGE;
1290 } // else // !haveArgs
1291 } // if (op1->gtOper == GT_LCL_VAR)
1294 // Are we making an IsType assertion?
1296 else if (op1->gtOper == GT_IND)
1298 op1 = op1->gtOp.gtOp1;
1300 // Is this an indirection of a local variable?
1302 if (op1->gtOper == GT_LCL_VAR)
1304 unsigned lclNum = op1->gtLclVarCommon.gtLclNum;
1305 noway_assert(lclNum < lvaCount);
1306 LclVarDsc* lclVar = &lvaTable[lclNum];
1308 // If the local variable has its address exposed then bail
1309 if (fgExcludeFromSsa(lclNum))
1311 goto DONE_ASSERTION;
1314 // If we have an typeHnd indirection then op1 must be a TYP_REF
1315 // and the indirection must produce a TYP_I
1317 if (op1->gtType != TYP_REF)
1319 goto DONE_ASSERTION; // Don't make an assertion
1322 assertion->op1.kind = O1K_EXACT_TYPE;
1323 assertion->op1.lcl.lclNum = lclNum;
1324 assertion->op1.vn = op1->gtVNPair.GetConservative();
1325 assertion->op1.lcl.ssaNum = op1->AsLclVarCommon()->GetSsaNum();
1326 assert(assertion->op1.lcl.ssaNum == SsaConfig::RESERVED_SSA_NUM ||
1327 assertion->op1.vn ==
1328 lvaTable[lclNum].GetPerSsaData(assertion->op1.lcl.ssaNum)->m_vnPair.GetConservative());
1330 ssize_t cnsValue = 0;
1331 unsigned iconFlags = 0;
1333 if (op2->gtOper == GT_IND)
1335 if (!optIsTreeKnownIntValue(!optLocalAssertionProp, op2->gtOp.gtOp1, &cnsValue, &iconFlags))
1337 goto DONE_ASSERTION; // Don't make an assertion
1340 assertion->assertionKind = assertionKind;
1341 assertion->op2.kind = O2K_IND_CNS_INT;
1342 assertion->op2.u1.iconVal = cnsValue;
1343 assertion->op2.vn = op2->gtOp.gtOp1->gtVNPair.GetConservative();
1344 /* iconFlags should only contain bits in GTF_ICON_HDL_MASK */
1345 assert((iconFlags & ~GTF_ICON_HDL_MASK) == 0);
1346 assertion->op2.u1.iconFlags = iconFlags;
1347 #ifdef _TARGET_64BIT_
1348 if (op2->gtOp.gtOp1->TypeGet() == TYP_LONG)
1350 assertion->op2.u1.iconFlags |= 1; // Signify that this is really TYP_LONG
1352 #endif // _TARGET_64BIT_
1355 else if (optIsTreeKnownIntValue(!optLocalAssertionProp, op2, &cnsValue, &iconFlags))
1357 assertion->assertionKind = assertionKind;
1358 assertion->op2.kind = O2K_IND_CNS_INT;
1359 assertion->op2.u1.iconVal = cnsValue;
1360 assertion->op2.vn = op2->gtVNPair.GetConservative();
1361 /* iconFlags should only contain bits in GTF_ICON_HDL_MASK */
1362 assert((iconFlags & ~GTF_ICON_HDL_MASK) == 0);
1363 assertion->op2.u1.iconFlags = iconFlags;
1364 #ifdef _TARGET_64BIT_
1365 if (op2->TypeGet() == TYP_LONG)
1367 assertion->op2.u1.iconFlags |= 1; // Signify that this is really TYP_LONG
1369 #endif // _TARGET_64BIT_
1373 goto DONE_ASSERTION; // Don't make an assertion
1379 if (assertion->assertionKind == OAK_INVALID)
1381 return NO_ASSERTION_INDEX;
1384 if (!optLocalAssertionProp)
1386 if ((assertion->op1.vn == ValueNumStore::NoVN) || (assertion->op2.vn == ValueNumStore::NoVN) ||
1387 (assertion->op1.vn == ValueNumStore::VNForVoid()) || (assertion->op2.vn == ValueNumStore::VNForVoid()))
1389 return NO_ASSERTION_INDEX;
1392 // TODO: only copy assertions rely on valid SSA number so we could generate more assertions here
1393 if ((assertion->op1.kind != O1K_VALUE_NUMBER) && (assertion->op1.lcl.ssaNum == SsaConfig::RESERVED_SSA_NUM))
1395 return NO_ASSERTION_INDEX;
1399 // Now add the assertion to our assertion table
1400 noway_assert(assertion->op1.kind != O1K_INVALID);
1401 noway_assert(assertion->op1.kind == O1K_ARR_BND || assertion->op2.kind != O2K_INVALID);
1402 return optAddAssertion(assertion);
1405 /*****************************************************************************
1407 * If tree is a constant node holding an integral value, retrieve the value in
1408 * pConstant. If the method returns true, pConstant holds the appropriate
1409 * constant. Set "vnBased" to true to indicate local or global assertion prop.
1410 * "pFlags" indicates if the constant is a handle marked by GTF_ICON_HDL_MASK.
1412 bool Compiler::optIsTreeKnownIntValue(bool vnBased, GenTree* tree, ssize_t* pConstant, unsigned* pFlags)
1414 // Is Local assertion prop?
1417 if (tree->OperGet() == GT_CNS_INT)
1419 *pConstant = tree->gtIntCon.IconValue();
1420 *pFlags = tree->GetIconHandleFlag();
1423 #ifdef _TARGET_64BIT_
1424 // Just to be clear, get it from gtLconVal rather than
1425 // overlapping gtIconVal.
1426 else if (tree->OperGet() == GT_CNS_LNG)
1428 *pConstant = tree->gtLngCon.gtLconVal;
1429 *pFlags = tree->GetIconHandleFlag();
1436 // Global assertion prop
1437 if (!vnStore->IsVNConstant(tree->gtVNPair.GetConservative()))
1442 ValueNum vn = tree->gtVNPair.GetConservative();
1443 var_types vnType = vnStore->TypeOfVN(vn);
1444 if (vnType == TYP_INT)
1446 *pConstant = vnStore->ConstantValue<int>(vn);
1447 *pFlags = vnStore->IsVNHandle(vn) ? vnStore->GetHandleFlags(vn) : 0;
1450 #ifdef _TARGET_64BIT_
1451 else if (vnType == TYP_LONG)
1453 *pConstant = vnStore->ConstantValue<INT64>(vn);
1454 *pFlags = vnStore->IsVNHandle(vn) ? vnStore->GetHandleFlags(vn) : 0;
1462 /*****************************************************************************
1464 * Print the assertions related to a VN for all VNs.
1467 void Compiler::optPrintVnAssertionMapping()
1469 printf("\nVN Assertion Mapping\n");
1470 printf("---------------------\n");
1471 for (ValueNumToAssertsMap::KeyIterator ki = optValueNumToAsserts->Begin(); !ki.Equal(optValueNumToAsserts->End());
1474 printf("(%d => ", ki.Get());
1475 printf("%s)\n", BitVecOps::ToString(apTraits, ki.GetValue()));
1480 /*****************************************************************************
1482 * Maintain a map "optValueNumToAsserts" i.e., vn -> to set of assertions
1483 * about that VN. Given "assertions" about a "vn" add it to the previously
1484 * mapped assertions about that "vn."
1486 void Compiler::optAddVnAssertionMapping(ValueNum vn, AssertionIndex index)
1488 ASSERT_TP* cur = optValueNumToAsserts->LookupPointer(vn);
1491 optValueNumToAsserts->Set(vn, BitVecOps::MakeSingleton(apTraits, index - 1));
1495 BitVecOps::AddElemD(apTraits, *cur, index - 1);
1499 /*****************************************************************************
1500 * Statically if we know that this assertion's VN involves a NaN don't bother
1501 * wasting an assertion table slot.
1503 bool Compiler::optAssertionVnInvolvesNan(AssertionDsc* assertion)
1505 if (optLocalAssertionProp)
1510 static const int SZ = 2;
1511 ValueNum vns[SZ] = {assertion->op1.vn, assertion->op2.vn};
1512 for (int i = 0; i < SZ; ++i)
1514 if (vnStore->IsVNConstant(vns[i]))
1516 var_types type = vnStore->TypeOfVN(vns[i]);
1517 if ((type == TYP_FLOAT && _isnan(vnStore->ConstantValue<float>(vns[i])) != 0) ||
1518 (type == TYP_DOUBLE && _isnan(vnStore->ConstantValue<double>(vns[i])) != 0))
1527 /*****************************************************************************
1529 * Given an assertion add it to the assertion table
1531 * If it is already in the assertion table return the assertionIndex that
1532 * we use to refer to this element.
1533 * Otherwise add it to the assertion table ad return the assertionIndex that
1534 * we use to refer to this element.
1535 * If we need to add to the table and the table is full return the value zero
1537 AssertionIndex Compiler::optAddAssertion(AssertionDsc* newAssertion)
1539 noway_assert(newAssertion->assertionKind != OAK_INVALID);
1541 // Even though the propagation step takes care of NaN, just a check
1542 // to make sure there is no slot involving a NaN.
1543 if (optAssertionVnInvolvesNan(newAssertion))
1545 JITDUMP("Assertion involved Nan not adding\n");
1546 return NO_ASSERTION_INDEX;
1549 // Check if exists already, so we can skip adding new one. Search backwards.
1550 for (AssertionIndex index = optAssertionCount; index >= 1; index--)
1552 AssertionDsc* curAssertion = optGetAssertion(index);
1553 if (curAssertion->Equals(newAssertion, !optLocalAssertionProp))
1559 // Check if we are within max count.
1560 if (optAssertionCount >= optMaxAssertionCount)
1562 return NO_ASSERTION_INDEX;
1565 optAssertionTabPrivate[optAssertionCount] = *newAssertion;
1566 optAssertionCount++;
1571 printf("GenTreeNode creates assertion:\n");
1572 gtDispTree(optAssertionPropCurrentTree, nullptr, nullptr, true);
1573 printf(optLocalAssertionProp ? "In BB%02u New Local " : "In BB%02u New Global ", compCurBB->bbNum);
1574 optPrintAssertion(newAssertion, optAssertionCount);
1578 // Assertion mask bits are [index + 1].
1579 if (optLocalAssertionProp)
1581 assert(newAssertion->op1.kind == O1K_LCLVAR);
1583 // Mark the variables this index depends on
1584 unsigned lclNum = newAssertion->op1.lcl.lclNum;
1585 BitVecOps::AddElemD(apTraits, GetAssertionDep(lclNum), optAssertionCount - 1);
1586 if (newAssertion->op2.kind == O2K_LCLVAR_COPY)
1588 lclNum = newAssertion->op2.lcl.lclNum;
1589 BitVecOps::AddElemD(apTraits, GetAssertionDep(lclNum), optAssertionCount - 1);
1593 // If global assertion prop, then add it to the dependents map.
1595 optAddVnAssertionMapping(newAssertion->op1.vn, optAssertionCount);
1596 if (newAssertion->op2.kind == O2K_LCLVAR_COPY)
1598 optAddVnAssertionMapping(newAssertion->op2.vn, optAssertionCount);
1603 optDebugCheckAssertions(optAssertionCount);
1605 return optAssertionCount;
1609 void Compiler::optDebugCheckAssertion(AssertionDsc* assertion)
1611 assert(assertion->assertionKind < OAK_COUNT);
1612 assert(assertion->op1.kind < O1K_COUNT);
1613 assert(assertion->op2.kind < O2K_COUNT);
1614 // It would be good to check that op1.vn and op2.vn are valid value numbers.
1616 switch (assertion->op1.kind)
1619 case O1K_EXACT_TYPE:
1621 assert(assertion->op1.lcl.lclNum < lvaCount);
1622 assert(optLocalAssertionProp || ((assertion->op1.lcl.ssaNum - SsaConfig::UNINIT_SSA_NUM) <
1623 lvaTable[assertion->op1.lcl.lclNum].lvNumSsaNames));
1626 // It would be good to check that bnd.vnIdx and bnd.vnLen are valid value numbers.
1628 case O1K_BOUND_OPER_BND:
1629 case O1K_BOUND_LOOP_BND:
1630 case O1K_CONSTANT_LOOP_BND:
1631 case O1K_VALUE_NUMBER:
1632 assert(!optLocalAssertionProp);
1637 switch (assertion->op2.kind)
1639 case O2K_IND_CNS_INT:
1642 // The only flags that can be set are those in the GTF_ICON_HDL_MASK, or bit 0, which is
1643 // used to indicate a long constant.
1644 assert((assertion->op2.u1.iconFlags & ~(GTF_ICON_HDL_MASK | 1)) == 0);
1645 switch (assertion->op1.kind)
1647 case O1K_EXACT_TYPE:
1649 assert(assertion->op2.u1.iconFlags != 0);
1653 assert((lvaTable[assertion->op1.lcl.lclNum].lvType != TYP_REF) || (assertion->op2.u1.iconVal == 0));
1655 case O1K_VALUE_NUMBER:
1656 assert((vnStore->TypeOfVN(assertion->op1.vn) != TYP_REF) || (assertion->op2.u1.iconVal == 0));
1665 // for all other 'assertion->op2.kind' values we don't check anything
1670 /*****************************************************************************
1672 * Verify that assertion prop related assumptions are valid. If "index"
1673 * is 0 (i.e., NO_ASSERTION_INDEX) then verify all assertions in the table.
1674 * If "index" is between 1 and optAssertionCount, then verify the assertion
1675 * desc corresponding to "index."
1677 void Compiler::optDebugCheckAssertions(AssertionIndex index)
1679 AssertionIndex start = (index == NO_ASSERTION_INDEX) ? 1 : index;
1680 AssertionIndex end = (index == NO_ASSERTION_INDEX) ? optAssertionCount : index;
1681 for (AssertionIndex ind = start; ind <= end; ++ind)
1683 AssertionDsc* assertion = optGetAssertion(ind);
1684 optDebugCheckAssertion(assertion);
1689 /*****************************************************************************
1691 * Given a "candidateAssertion", and the assertion operands op1 and op2,
1692 * create a complementary assertion and add it to the assertion table,
1693 * which can be retrieved using optFindComplementary(index)
1697 void Compiler::optCreateComplementaryAssertion(AssertionIndex assertionIndex, GenTree* op1, GenTree* op2)
1699 if (assertionIndex == NO_ASSERTION_INDEX)
1704 AssertionDsc& candidateAssertion = *optGetAssertion(assertionIndex);
1705 if (candidateAssertion.op1.kind == O1K_BOUND_OPER_BND || candidateAssertion.op1.kind == O1K_BOUND_LOOP_BND ||
1706 candidateAssertion.op1.kind == O1K_CONSTANT_LOOP_BND)
1708 AssertionDsc dsc = candidateAssertion;
1709 dsc.assertionKind = dsc.assertionKind == OAK_EQUAL ? OAK_NOT_EQUAL : OAK_EQUAL;
1710 optAddAssertion(&dsc);
1714 if (candidateAssertion.assertionKind == OAK_EQUAL)
1716 AssertionIndex index = optCreateAssertion(op1, op2, OAK_NOT_EQUAL);
1717 optMapComplementary(index, assertionIndex);
1719 else if (candidateAssertion.assertionKind == OAK_NOT_EQUAL)
1721 AssertionIndex index = optCreateAssertion(op1, op2, OAK_EQUAL);
1722 optMapComplementary(index, assertionIndex);
1725 // Are we making a subtype or exact type assertion?
1726 if ((candidateAssertion.op1.kind == O1K_SUBTYPE) || (candidateAssertion.op1.kind == O1K_EXACT_TYPE))
1728 // Did we recieve helper call args?
1729 if (op1->gtOper == GT_LIST)
1731 op1 = op1->gtOp.gtOp1;
1733 optCreateAssertion(op1, nullptr, OAK_NOT_EQUAL);
1737 /*****************************************************************************
1739 * Create assertions for jtrue operands. Given operands "op1" and "op2" that
1740 * are used in a conditional evaluation of a jtrue stmt, create assertions
1744 AssertionIndex Compiler::optCreateJtrueAssertions(GenTree* op1, GenTree* op2, Compiler::optAssertionKind assertionKind)
1746 AssertionDsc candidateAssertion;
1747 AssertionIndex assertionIndex = optCreateAssertion(op1, op2, assertionKind, &candidateAssertion);
1748 // Don't bother if we don't have an assertion on the JTrue False path. Current implementation
1749 // allows for a complementary only if there is an assertion on the False path (tree->HasAssertion()).
1750 if (assertionIndex != NO_ASSERTION_INDEX)
1752 optCreateComplementaryAssertion(assertionIndex, op1, op2);
1754 return assertionIndex;
1757 AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
1759 GenTree* relop = tree->gtGetOp1();
1760 if ((relop->OperKind() & GTK_RELOP) == 0)
1762 return NO_ASSERTION_INDEX;
1764 GenTree* op1 = relop->gtGetOp1();
1765 GenTree* op2 = relop->gtGetOp2();
1767 ValueNum vn = op1->gtVNPair.GetConservative();
1769 ValueNumStore::UnsignedCompareCheckedBoundInfo unsignedCompareBnd;
1770 // Cases where op1 holds the upper bound arithmetic and op2 is 0.
1771 // Loop condition like: "i < bnd +/-k == 0"
1772 // Assertion: "i < bnd +/- k == 0"
1773 if (vnStore->IsVNCompareCheckedBoundArith(vn) &&
1774 op2->gtVNPair.GetConservative() == vnStore->VNZeroForType(op2->TypeGet()) &&
1775 (relop->gtOper == GT_EQ || relop->gtOper == GT_NE))
1778 dsc.assertionKind = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
1779 dsc.op1.kind = O1K_BOUND_OPER_BND;
1781 dsc.op2.kind = O2K_CONST_INT;
1782 dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
1783 dsc.op2.u1.iconVal = 0;
1784 dsc.op2.u1.iconFlags = 0;
1785 AssertionIndex index = optAddAssertion(&dsc);
1786 optCreateComplementaryAssertion(index, nullptr, nullptr);
1789 // Cases where op1 holds the upper bound and op2 is 0.
1790 // Loop condition like: "i < bnd == 0"
1791 // Assertion: "i < bnd == false"
1792 else if (vnStore->IsVNCompareCheckedBound(vn) &&
1793 (op2->gtVNPair.GetConservative() == vnStore->VNZeroForType(op2->TypeGet())) &&
1794 (relop->gtOper == GT_EQ || relop->gtOper == GT_NE))
1797 dsc.assertionKind = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
1798 dsc.op1.kind = O1K_BOUND_LOOP_BND;
1800 dsc.op2.kind = O2K_CONST_INT;
1801 dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
1802 dsc.op2.u1.iconVal = 0;
1803 dsc.op2.u1.iconFlags = 0;
1804 AssertionIndex index = optAddAssertion(&dsc);
1805 optCreateComplementaryAssertion(index, nullptr, nullptr);
1808 // Cases where op1 holds the lhs of the condition op2 holds the bound.
1809 // Loop condition like "i < bnd"
1810 // Assertion: "i < bnd != 0"
1811 else if (vnStore->IsVNCompareCheckedBound(relop->gtVNPair.GetConservative()))
1814 dsc.assertionKind = OAK_NOT_EQUAL;
1815 dsc.op1.kind = O1K_BOUND_LOOP_BND;
1816 dsc.op1.vn = relop->gtVNPair.GetConservative();
1817 dsc.op2.kind = O2K_CONST_INT;
1818 dsc.op2.vn = vnStore->VNZeroForType(TYP_INT);
1819 dsc.op2.u1.iconVal = 0;
1820 dsc.op2.u1.iconFlags = 0;
1821 AssertionIndex index = optAddAssertion(&dsc);
1822 optCreateComplementaryAssertion(index, nullptr, nullptr);
1825 // Loop condition like "(uint)i < (uint)bnd" or equivalent
1826 // Assertion: "no throw" since this condition guarantees that i is both >= 0 and < bnd (on the appropiate edge)
1827 else if (vnStore->IsVNUnsignedCompareCheckedBound(relop->gtVNPair.GetConservative(), &unsignedCompareBnd))
1829 assert(unsignedCompareBnd.vnIdx != ValueNumStore::NoVN);
1830 assert((unsignedCompareBnd.cmpOper == VNF_LT_UN) || (unsignedCompareBnd.cmpOper == VNF_GE_UN));
1831 assert(vnStore->IsVNCheckedBound(unsignedCompareBnd.vnBound));
1834 dsc.assertionKind = OAK_NO_THROW;
1835 dsc.op1.kind = O1K_ARR_BND;
1836 dsc.op1.vn = relop->gtVNPair.GetConservative();
1837 dsc.op1.bnd.vnIdx = unsignedCompareBnd.vnIdx;
1838 dsc.op1.bnd.vnLen = unsignedCompareBnd.vnBound;
1839 dsc.op2.kind = O2K_INVALID;
1840 dsc.op2.vn = ValueNumStore::NoVN;
1842 AssertionIndex index = optAddAssertion(&dsc);
1843 if (unsignedCompareBnd.cmpOper == VNF_GE_UN)
1845 // By default JTRUE generated assertions hold on the "jump" edge. We have i >= bnd but we're really
1846 // after i < bnd so we need to change the assertion edge to "next".
1847 return AssertionInfo::ForNextEdge(index);
1851 // Cases where op1 holds the condition bound check and op2 is 0.
1852 // Loop condition like: "i < 100 == 0"
1853 // Assertion: "i < 100 == false"
1854 else if (vnStore->IsVNConstantBound(vn) &&
1855 (op2->gtVNPair.GetConservative() == vnStore->VNZeroForType(op2->TypeGet())) &&
1856 (relop->gtOper == GT_EQ || relop->gtOper == GT_NE))
1859 dsc.assertionKind = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
1860 dsc.op1.kind = O1K_CONSTANT_LOOP_BND;
1862 dsc.op2.kind = O2K_CONST_INT;
1863 dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
1864 dsc.op2.u1.iconVal = 0;
1865 dsc.op2.u1.iconFlags = 0;
1866 AssertionIndex index = optAddAssertion(&dsc);
1867 optCreateComplementaryAssertion(index, nullptr, nullptr);
1870 // Cases where op1 holds the lhs of the condition op2 holds rhs.
1871 // Loop condition like "i < 100"
1872 // Assertion: "i < 100 != 0"
1873 else if (vnStore->IsVNConstantBound(relop->gtVNPair.GetConservative()))
1876 dsc.assertionKind = OAK_NOT_EQUAL;
1877 dsc.op1.kind = O1K_CONSTANT_LOOP_BND;
1878 dsc.op1.vn = relop->gtVNPair.GetConservative();
1879 dsc.op2.kind = O2K_CONST_INT;
1880 dsc.op2.vn = vnStore->VNZeroForType(TYP_INT);
1881 dsc.op2.u1.iconVal = 0;
1882 dsc.op2.u1.iconFlags = 0;
1883 AssertionIndex index = optAddAssertion(&dsc);
1884 optCreateComplementaryAssertion(index, nullptr, nullptr);
1888 return NO_ASSERTION_INDEX;
1891 /*****************************************************************************
1893 * Compute assertions for the JTrue node.
1895 AssertionInfo Compiler::optAssertionGenJtrue(GenTree* tree)
1897 // Only create assertions for JTRUE when we are in the global phase
1898 if (optLocalAssertionProp)
1900 return NO_ASSERTION_INDEX;
1903 GenTree* relop = tree->gtOp.gtOp1;
1904 if ((relop->OperKind() & GTK_RELOP) == 0)
1906 return NO_ASSERTION_INDEX;
1909 Compiler::optAssertionKind assertionKind = OAK_INVALID;
1911 GenTree* op1 = relop->gtOp.gtOp1;
1912 GenTree* op2 = relop->gtOp.gtOp2;
1914 AssertionInfo info = optCreateJTrueBoundsAssertion(tree);
1915 if (info.HasAssertion())
1920 // Find assertion kind.
1921 switch (relop->gtOper)
1924 assertionKind = OAK_EQUAL;
1927 assertionKind = OAK_NOT_EQUAL;
1930 // TODO-CQ: add other relop operands. Disabled for now to measure perf
1931 // and not occupy assertion table slots. We'll add them when used.
1932 return NO_ASSERTION_INDEX;
1935 // Check for op1 or op2 to be lcl var and if so, keep it in op1.
1936 if ((op1->gtOper != GT_LCL_VAR) && (op2->gtOper == GT_LCL_VAR))
1938 jitstd::swap(op1, op2);
1940 // If op1 is lcl and op2 is const or lcl, create assertion.
1941 if ((op1->gtOper == GT_LCL_VAR) &&
1942 ((op2->OperKind() & GTK_CONST) || (op2->gtOper == GT_LCL_VAR))) // Fix for Dev10 851483
1944 return optCreateJtrueAssertions(op1, op2, assertionKind);
1947 // Check op1 and op2 for an indirection of a GT_LCL_VAR and keep it in op1.
1948 if (((op1->gtOper != GT_IND) || (op1->gtOp.gtOp1->gtOper != GT_LCL_VAR)) &&
1949 ((op2->gtOper == GT_IND) && (op2->gtOp.gtOp1->gtOper == GT_LCL_VAR)))
1951 jitstd::swap(op1, op2);
1953 // If op1 is ind, then extract op1's oper.
1954 if ((op1->gtOper == GT_IND) && (op1->gtOp.gtOp1->gtOper == GT_LCL_VAR))
1956 return optCreateJtrueAssertions(op1, op2, assertionKind);
1959 // Look for a call to an IsInstanceOf helper compared to a nullptr
1960 if ((op2->gtOper != GT_CNS_INT) && (op1->gtOper == GT_CNS_INT))
1962 jitstd::swap(op1, op2);
1964 // Validate op1 and op2
1965 if ((op1->gtOper != GT_CALL) || (op1->gtCall.gtCallType != CT_HELPER) || (op1->TypeGet() != TYP_REF) || // op1
1966 (op2->gtOper != GT_CNS_INT) || (op2->gtIntCon.gtIconVal != 0)) // op2
1968 return NO_ASSERTION_INDEX;
1970 if (op1->gtCall.gtCallMethHnd != eeFindHelper(CORINFO_HELP_ISINSTANCEOFINTERFACE) &&
1971 op1->gtCall.gtCallMethHnd != eeFindHelper(CORINFO_HELP_ISINSTANCEOFARRAY) &&
1972 op1->gtCall.gtCallMethHnd != eeFindHelper(CORINFO_HELP_ISINSTANCEOFCLASS) &&
1973 op1->gtCall.gtCallMethHnd != eeFindHelper(CORINFO_HELP_ISINSTANCEOFANY))
1975 return NO_ASSERTION_INDEX;
1978 op2 = op1->gtCall.gtCallLateArgs->gtOp.gtOp2;
1979 op1 = op1->gtCall.gtCallLateArgs;
1981 // Reverse the assertion
1982 assert(assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL);
1983 assertionKind = (assertionKind == OAK_EQUAL) ? OAK_NOT_EQUAL : OAK_EQUAL;
1985 if (op1->gtOp.gtOp1->gtOper == GT_LCL_VAR)
1987 return optCreateJtrueAssertions(op1, op2, assertionKind);
1990 return NO_ASSERTION_INDEX;
1993 /*****************************************************************************
1995 * Create an assertion on the phi node if some information can be gleaned
1996 * from all of the constituent phi operands.
1999 AssertionIndex Compiler::optAssertionGenPhiDefn(GenTree* tree)
2001 if (!tree->IsPhiDefn())
2003 return NO_ASSERTION_INDEX;
2006 GenTree* phi = tree->gtOp.gtOp2;
2008 // Try to find if all phi arguments are known to be non-null.
2009 bool isNonNull = true;
2010 for (GenTreeArgList* args = phi->gtOp.gtOp1->AsArgList(); args != nullptr; args = args->Rest())
2012 if (!vnStore->IsKnownNonNull(args->Current()->gtVNPair.GetConservative()))
2019 // All phi arguments are non-null implies phi rhs is non-null.
2022 return optCreateAssertion(tree->gtOp.gtOp1, nullptr, OAK_NOT_EQUAL);
2024 return NO_ASSERTION_INDEX;
2027 /*****************************************************************************
2029 * If this statement creates a value assignment or assertion
2030 * then assign an index to the given value assignment by adding
2031 * it to the lookup table, if necessary.
2033 void Compiler::optAssertionGen(GenTree* tree)
2035 tree->ClearAssertion();
2037 if (tree->gtFlags & GTF_COLON_COND)
2043 optAssertionPropCurrentTree = tree;
2046 // For most of the assertions that we create below
2047 // the assertion is true after the tree is processed
2048 bool assertionProven = true;
2049 AssertionInfo assertionInfo;
2050 switch (tree->gtOper)
2053 // VN takes care of non local assertions for assignments and data flow.
2054 if (optLocalAssertionProp)
2056 assertionInfo = optCreateAssertion(tree->gtOp.gtOp1, tree->gtOp.gtOp2, OAK_EQUAL);
2060 assertionInfo = optAssertionGenPhiDefn(tree);
2069 // All indirections create non-null assertions
2070 assertionInfo = optCreateAssertion(tree->AsIndir()->Addr(), nullptr, OAK_NOT_EQUAL);
2074 // An array length is an indirection (but doesn't derive from GenTreeIndir).
2075 assertionInfo = optCreateAssertion(tree->AsArrLen()->ArrRef(), nullptr, OAK_NOT_EQUAL);
2078 case GT_ARR_BOUNDS_CHECK:
2079 if (!optLocalAssertionProp)
2081 assertionInfo = optCreateAssertion(tree, nullptr, OAK_NO_THROW);
2086 // An array element reference can create a non-null assertion
2087 assertionInfo = optCreateAssertion(tree->gtArrElem.gtArrObj, nullptr, OAK_NOT_EQUAL);
2091 // A virtual call can create a non-null assertion. We transform some virtual calls into non-virtual calls
2092 // with a GTF_CALL_NULLCHECK flag set.
2093 if ((tree->gtFlags & GTF_CALL_NULLCHECK) || tree->AsCall()->IsVirtual())
2095 // Retrieve the 'this' arg
2096 GenTree* thisArg = gtGetThisArg(tree->AsCall());
2097 #if defined(_TARGET_X86_) || defined(_TARGET_AMD64_) || defined(_TARGET_ARM_)
2098 if (thisArg == nullptr)
2100 // For tail calls we lose the this pointer in the argument list but that's OK because a null check
2101 // was made explicit, so we get the assertion when we walk the GT_IND in the argument list.
2102 noway_assert(tree->gtCall.IsTailCall());
2105 #endif // _TARGET_X86_ || _TARGET_AMD64_ || _TARGET_ARM_
2106 noway_assert(thisArg != nullptr);
2107 assertionInfo = optCreateAssertion(thisArg, nullptr, OAK_NOT_EQUAL);
2112 // We only create this assertion for global assertion prop
2113 if (!optLocalAssertionProp)
2115 // This represets an assertion that we would like to prove to be true. It is not actually a true
2117 // If we can prove this assertion true then we can eliminate this cast.
2118 assertionInfo = optCreateAssertion(tree->gtOp.gtOp1, tree, OAK_SUBRANGE);
2119 assertionProven = false;
2124 assertionInfo = optAssertionGenJtrue(tree);
2128 // All other gtOper node kinds, leave 'assertionIndex' = NO_ASSERTION_INDEX
2132 // For global assertion prop we must store the assertion number in the tree node
2133 if (assertionInfo.HasAssertion() && assertionProven && !optLocalAssertionProp)
2135 tree->SetAssertionInfo(assertionInfo);
2139 /*****************************************************************************
2141 * Maps a complementary assertion to its original assertion so it can be
2144 void Compiler::optMapComplementary(AssertionIndex assertionIndex, AssertionIndex index)
2146 if (assertionIndex == NO_ASSERTION_INDEX || index == NO_ASSERTION_INDEX)
2151 assert(assertionIndex <= optMaxAssertionCount);
2152 assert(index <= optMaxAssertionCount);
2154 optComplementaryAssertionMap[assertionIndex] = index;
2155 optComplementaryAssertionMap[index] = assertionIndex;
2158 /*****************************************************************************
2160 * Given an assertion index, return the assertion index of the complementary
2161 * assertion or 0 if one does not exist.
2163 AssertionIndex Compiler::optFindComplementary(AssertionIndex assertIndex)
2165 if (assertIndex == NO_ASSERTION_INDEX)
2167 return NO_ASSERTION_INDEX;
2169 AssertionDsc* inputAssertion = optGetAssertion(assertIndex);
2171 // Must be an equal or not equal assertion.
2172 if (inputAssertion->assertionKind != OAK_EQUAL && inputAssertion->assertionKind != OAK_NOT_EQUAL)
2174 return NO_ASSERTION_INDEX;
2177 AssertionIndex index = optComplementaryAssertionMap[assertIndex];
2178 if (index != NO_ASSERTION_INDEX && index <= optAssertionCount)
2183 optAssertionKind complementaryAssertionKind =
2184 (inputAssertion->assertionKind == OAK_EQUAL) ? OAK_NOT_EQUAL : OAK_EQUAL;
2185 for (AssertionIndex index = 1; index <= optAssertionCount; ++index)
2187 // Make sure assertion kinds are complementary and op1, op2 kinds match.
2188 AssertionDsc* curAssertion = optGetAssertion(index);
2189 if (curAssertion->Complementary(inputAssertion, !optLocalAssertionProp))
2191 optMapComplementary(assertIndex, index);
2195 return NO_ASSERTION_INDEX;
2198 /*****************************************************************************
2200 * Given a lclNum and a toType, return assertion index of the assertion that
2201 * claims that a variable's value is always a valid subrange of toType.
2202 * Thus we can discard or omit a cast to toType. Returns NO_ASSERTION_INDEX
2203 * if one such assertion could not be found in "assertions."
2206 AssertionIndex Compiler::optAssertionIsSubrange(GenTree* tree, var_types toType, ASSERT_VALARG_TP assertions)
2208 if (!optLocalAssertionProp && BitVecOps::IsEmpty(apTraits, assertions))
2210 return NO_ASSERTION_INDEX;
2213 for (AssertionIndex index = 1; index <= optAssertionCount; index++)
2215 AssertionDsc* curAssertion = optGetAssertion(index);
2216 if ((optLocalAssertionProp ||
2217 BitVecOps::IsMember(apTraits, assertions, index - 1)) && // either local prop or use propagated assertions
2218 (curAssertion->assertionKind == OAK_SUBRANGE) &&
2219 (curAssertion->op1.kind == O1K_LCLVAR))
2221 // For local assertion prop use comparison on locals, and use comparison on vns for global prop.
2222 bool isEqual = optLocalAssertionProp ? (curAssertion->op1.lcl.lclNum == tree->AsLclVarCommon()->GetLclNum())
2223 : (curAssertion->op1.vn == tree->gtVNPair.GetConservative());
2229 // Make sure the toType is within current assertion's bounds.
2236 if ((curAssertion->op2.u2.loBound < AssertionDsc::GetLowerBoundForIntegralType(toType)) ||
2237 (curAssertion->op2.u2.hiBound > AssertionDsc::GetUpperBoundForIntegralType(toType)))
2244 if (curAssertion->op2.u2.loBound < AssertionDsc::GetLowerBoundForIntegralType(toType))
2259 return NO_ASSERTION_INDEX;
2262 /**********************************************************************************
2264 * Given a "tree" that is usually arg1 of a isinst/cast kind of GT_CALL (a class
2265 * handle), and "methodTableArg" which is a const int (a class handle), then search
2266 * if there is an assertion in "assertions", that asserts the equality of the two
2267 * class handles and then returns the index of the assertion. If one such assertion
2268 * could not be found, then it returns NO_ASSERTION_INDEX.
2271 AssertionIndex Compiler::optAssertionIsSubtype(GenTree* tree, GenTree* methodTableArg, ASSERT_VALARG_TP assertions)
2273 if (!optLocalAssertionProp && BitVecOps::IsEmpty(apTraits, assertions))
2275 return NO_ASSERTION_INDEX;
2277 for (AssertionIndex index = 1; index <= optAssertionCount; index++)
2279 if (!optLocalAssertionProp && !BitVecOps::IsMember(apTraits, assertions, index - 1))
2284 AssertionDsc* curAssertion = optGetAssertion(index);
2285 if (curAssertion->assertionKind != OAK_EQUAL ||
2286 (curAssertion->op1.kind != O1K_SUBTYPE && curAssertion->op1.kind != O1K_EXACT_TYPE))
2291 // If local assertion prop use "lcl" based comparison, if global assertion prop use vn based comparison.
2292 if ((optLocalAssertionProp) ? (curAssertion->op1.lcl.lclNum != tree->AsLclVarCommon()->GetLclNum())
2293 : (curAssertion->op1.vn != tree->gtVNPair.GetConservative()))
2298 if (curAssertion->op2.kind == O2K_IND_CNS_INT)
2300 if (methodTableArg->gtOper != GT_IND)
2304 methodTableArg = methodTableArg->gtOp.gtOp1;
2306 else if (curAssertion->op2.kind != O2K_CONST_INT)
2311 ssize_t methodTableVal = 0;
2312 unsigned iconFlags = 0;
2313 if (!optIsTreeKnownIntValue(!optLocalAssertionProp, methodTableArg, &methodTableVal, &iconFlags))
2318 if (curAssertion->op2.u1.iconVal == methodTableVal)
2323 return NO_ASSERTION_INDEX;
2326 //------------------------------------------------------------------------------
2327 // optVNConstantPropOnTree: Substitutes tree with an evaluated constant while
2328 // managing ref-counts and side-effects.
2331 // block - The block containing the tree.
2332 // stmt - The statement in the block containing the tree.
2333 // tree - The tree node whose value is known at compile time.
2334 // The tree should have a constant value number.
2337 // Returns a potentially new or a transformed tree node.
2338 // Returns nullptr when no transformation is possible.
2341 // Transforms a tree node if its result evaluates to a constant. The
2342 // transformation can be a "ChangeOper" to a constant or a new constant node
2343 // with extracted side-effects.
2345 // Before replacing or substituting the "tree" with a constant, extracts any
2346 // side effects from the "tree" and creates a comma separated side effect list
2347 // and then appends the transformed node at the end of the list.
2348 // This comma separated list is then returned.
2350 // For JTrue nodes, side effects are not put into a comma separated list. If
2351 // the relop will evaluate to "true" or "false" statically, then the side-effects
2352 // will be put into new statements, presuming the JTrue will be folded away.
2354 // The ref-counts of any variables in the tree being replaced, will be
2355 // appropriately decremented. The ref-counts of variables in the side-effect
2356 // nodes will be retained.
2358 GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* stmt, GenTree* tree)
2360 if (tree->OperGet() == GT_JTRUE)
2362 // Treat JTRUE separately to extract side effects into respective statements rather
2363 // than using a COMMA separated op1.
2364 return optVNConstantPropOnJTrue(block, stmt, tree);
2366 // If relop is part of JTRUE, this should be optimized as part of the parent JTRUE.
2367 // Or if relop is part of QMARK or anything else, we simply bail here.
2368 else if (tree->OperIsCompare() && (tree->gtFlags & GTF_RELOP_JMP_USED))
2373 ValueNum vnCns = tree->gtVNPair.GetConservative();
2374 ValueNum vnLib = tree->gtVNPair.GetLiberal();
2376 // Check if node evaluates to a constant.
2377 if (!vnStore->IsVNConstant(vnCns))
2382 GenTree* newTree = tree;
2383 GenTree* sideEffList = nullptr;
2384 switch (vnStore->TypeOfVN(vnCns))
2388 float value = vnStore->ConstantValue<float>(vnCns);
2390 if (tree->TypeGet() == TYP_INT)
2392 // Same sized reinterpretation of bits to integer
2393 newTree = optPrepareTreeForReplacement(tree, tree);
2394 tree->ChangeOperConst(GT_CNS_INT);
2395 tree->gtIntCon.gtIconVal = *(reinterpret_cast<int*>(&value));
2396 tree->gtVNPair = ValueNumPair(vnLib, vnCns);
2400 // Implicit assignment conversion to float or double
2401 assert(varTypeIsFloating(tree->TypeGet()));
2403 newTree = optPrepareTreeForReplacement(tree, tree);
2404 tree->ChangeOperConst(GT_CNS_DBL);
2405 tree->gtDblCon.gtDconVal = value;
2406 tree->gtVNPair = ValueNumPair(vnLib, vnCns);
2413 double value = vnStore->ConstantValue<double>(vnCns);
2415 if (tree->TypeGet() == TYP_LONG)
2417 // Same sized reinterpretation of bits to long
2418 newTree = optPrepareTreeForReplacement(tree, tree);
2419 tree->ChangeOperConst(GT_CNS_NATIVELONG);
2420 tree->gtIntConCommon.SetLngValue(*(reinterpret_cast<INT64*>(&value)));
2421 tree->gtVNPair = ValueNumPair(vnLib, vnCns);
2425 // Implicit assignment conversion to float or double
2426 assert(varTypeIsFloating(tree->TypeGet()));
2428 newTree = optPrepareTreeForReplacement(tree, tree);
2429 tree->ChangeOperConst(GT_CNS_DBL);
2430 tree->gtDblCon.gtDconVal = value;
2431 tree->gtVNPair = ValueNumPair(vnLib, vnCns);
2438 INT64 value = vnStore->ConstantValue<INT64>(vnCns);
2439 #ifdef _TARGET_64BIT_
2440 if (vnStore->IsVNHandle(vnCns))
2442 // Don't perform constant folding that involves a handle that needs
2443 // to be recorded as a relocation with the VM.
2444 if (!opts.compReloc)
2446 newTree = gtNewIconHandleNode(value, vnStore->GetHandleFlags(vnCns));
2447 newTree->gtVNPair = ValueNumPair(vnLib, vnCns);
2448 newTree = optPrepareTreeForReplacement(tree, newTree);
2454 switch (tree->TypeGet())
2457 // Implicit assignment conversion to smaller integer
2458 newTree = optPrepareTreeForReplacement(tree, tree);
2459 tree->ChangeOperConst(GT_CNS_INT);
2460 tree->gtIntCon.gtIconVal = (int)value;
2461 tree->gtVNPair = ValueNumPair(vnLib, vnCns);
2465 // Same type no conversion required
2466 newTree = optPrepareTreeForReplacement(tree, tree);
2467 tree->ChangeOperConst(GT_CNS_NATIVELONG);
2468 tree->gtIntConCommon.SetLngValue(value);
2469 tree->gtVNPair = ValueNumPair(vnLib, vnCns);
2473 // No implicit conversions from long to float and value numbering will
2474 // not propagate through memory reinterpretations of different size.
2479 // Same sized reinterpretation of bits to double
2480 newTree = optPrepareTreeForReplacement(tree, tree);
2481 tree->ChangeOperConst(GT_CNS_DBL);
2482 tree->gtDblCon.gtDconVal = *(reinterpret_cast<double*>(&value));
2483 tree->gtVNPair = ValueNumPair(vnLib, vnCns);
2494 if (tree->TypeGet() != TYP_REF)
2499 assert(vnStore->ConstantValue<size_t>(vnCns) == 0);
2500 newTree = optPrepareTreeForReplacement(tree, tree);
2501 tree->ChangeOperConst(GT_CNS_INT);
2502 tree->gtIntCon.gtIconVal = 0;
2503 tree->ClearIconHandleMask();
2504 tree->gtVNPair = ValueNumPair(vnLib, vnCns);
2509 int value = vnStore->ConstantValue<int>(vnCns);
2510 #ifndef _TARGET_64BIT_
2511 if (vnStore->IsVNHandle(vnCns))
2513 // Don't perform constant folding that involves a handle that needs
2514 // to be recorded as a relocation with the VM.
2515 if (!opts.compReloc)
2517 newTree = gtNewIconHandleNode(value, vnStore->GetHandleFlags(vnCns));
2518 newTree->gtVNPair = ValueNumPair(vnLib, vnCns);
2519 newTree = optPrepareTreeForReplacement(tree, newTree);
2525 switch (tree->TypeGet())
2529 // Same type no conversion required
2530 newTree = optPrepareTreeForReplacement(tree, tree);
2531 tree->ChangeOperConst(GT_CNS_INT);
2532 tree->gtIntCon.gtIconVal = value;
2533 tree->ClearIconHandleMask();
2534 tree->gtVNPair = ValueNumPair(vnLib, vnCns);
2538 // Implicit assignment conversion to larger integer
2539 newTree = optPrepareTreeForReplacement(tree, tree);
2540 tree->ChangeOperConst(GT_CNS_NATIVELONG);
2541 tree->gtIntConCommon.SetLngValue(value);
2542 tree->gtVNPair = ValueNumPair(vnLib, vnCns);
2546 // Same sized reinterpretation of bits to float
2547 newTree = optPrepareTreeForReplacement(tree, tree);
2548 tree->ChangeOperConst(GT_CNS_DBL);
2549 tree->gtDblCon.gtDconVal = *(reinterpret_cast<float*>(&value));
2550 tree->gtVNPair = ValueNumPair(vnLib, vnCns);
2554 // No implicit conversions from int to double and value numbering will
2555 // not propagate through memory reinterpretations of different size.
2572 /*******************************************************************************************************
2574 * Perform constant propagation on a tree given the "curAssertion" is true at the point of the "tree."
2577 GenTree* Compiler::optConstantAssertionProp(AssertionDsc* curAssertion,
2579 GenTree* stmt DEBUGARG(AssertionIndex index))
2581 unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
2583 if (lclNumIsCSE(lclNum))
2588 GenTree* newTree = tree;
2590 // Update 'newTree' with the new value from our table
2591 // Typically newTree == tree and we are updating the node in place
2592 switch (curAssertion->op2.kind)
2594 case O2K_CONST_DOUBLE:
2595 // There could be a positive zero and a negative zero, so don't propagate zeroes.
2596 if (curAssertion->op2.dconVal == 0.0)
2600 newTree->ChangeOperConst(GT_CNS_DBL);
2601 newTree->gtDblCon.gtDconVal = curAssertion->op2.dconVal;
2604 case O2K_CONST_LONG:
2605 if (newTree->gtType == TYP_LONG)
2607 newTree->ChangeOperConst(GT_CNS_NATIVELONG);
2608 newTree->gtIntConCommon.SetLngValue(curAssertion->op2.lconVal);
2612 newTree->ChangeOperConst(GT_CNS_INT);
2613 newTree->gtIntCon.gtIconVal = (int)curAssertion->op2.lconVal;
2614 newTree->gtType = TYP_INT;
2619 if (curAssertion->op2.u1.iconFlags & GTF_ICON_HDL_MASK)
2621 // Here we have to allocate a new 'large' node to replace the old one
2622 newTree = gtNewIconHandleNode(curAssertion->op2.u1.iconVal,
2623 curAssertion->op2.u1.iconFlags & GTF_ICON_HDL_MASK);
2627 bool isArrIndex = ((tree->gtFlags & GTF_VAR_ARR_INDEX) != 0);
2628 // If we have done constant propagation of a struct type, it is only valid for zero-init,
2629 // and we have to ensure that we have the right zero for the type.
2630 if (varTypeIsStruct(tree))
2632 assert(curAssertion->op2.u1.iconVal == 0);
2635 if (varTypeIsSIMD(tree))
2637 var_types simdType = tree->TypeGet();
2638 tree->ChangeOperConst(GT_CNS_DBL);
2639 GenTree* initVal = tree;
2640 initVal->gtType = TYP_FLOAT;
2642 gtNewSIMDNode(simdType, initVal, nullptr, SIMDIntrinsicInit, TYP_FLOAT, genTypeSize(simdType));
2645 #endif // FEATURE_SIMD
2647 newTree->ChangeOperConst(GT_CNS_INT);
2648 newTree->gtIntCon.gtIconVal = curAssertion->op2.u1.iconVal;
2649 newTree->ClearIconHandleMask();
2651 // If we're doing an array index address, assume any constant propagated contributes to the index.
2654 newTree->gtIntCon.gtFieldSeq =
2655 GetFieldSeqStore()->CreateSingleton(FieldSeqStore::ConstantIndexPseudoField);
2657 newTree->gtFlags &= ~GTF_VAR_ARR_INDEX;
2660 // Constant ints are of type TYP_INT, not any of the short forms.
2661 if (varTypeIsIntegral(newTree->TypeGet()))
2663 #ifdef _TARGET_64BIT_
2664 var_types newType = (var_types)((curAssertion->op2.u1.iconFlags & 1) ? TYP_LONG : TYP_INT);
2665 if (newTree->TypeGet() != newType)
2667 noway_assert(newTree->gtType != TYP_REF);
2668 newTree->gtType = newType;
2671 if (newTree->TypeGet() != TYP_INT)
2673 noway_assert(newTree->gtType != TYP_REF && newTree->gtType != TYP_LONG);
2674 newTree->gtType = TYP_INT;
2684 if (!optLocalAssertionProp)
2686 assert(newTree->OperIsConst()); // We should have a simple Constant node for newTree
2687 assert(vnStore->IsVNConstant(curAssertion->op2.vn)); // The value number stored for op2 should be a valid
2688 // VN representing the constant
2689 newTree->gtVNPair.SetBoth(curAssertion->op2.vn); // Set the ValueNumPair to the constant VN from op2
2696 printf("\nAssertion prop in BB%02u:\n", compCurBB->bbNum);
2697 optPrintAssertion(curAssertion, index);
2698 gtDispTree(newTree, nullptr, nullptr, true);
2701 if (lvaLocalVarRefCounted)
2703 lvaTable[lclNum].decRefCnts(compCurBB->getBBWeight(this), this);
2706 return optAssertionProp_Update(newTree, tree, stmt);
2709 /*******************************************************************************************************
2711 * Called in the context of an existing copy assertion which makes an "==" assertion on "lclVar" and
2712 * "copyVar." Before substituting "copyVar" for "lclVar", we make sure using "copy" doesn't widen access.
2715 bool Compiler::optAssertionProp_LclVarTypeCheck(GenTree* tree, LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc)
2718 Small struct field locals are stored using the exact width and loaded widened
2719 (i.e. lvNormalizeOnStore==false lvNormalizeOnLoad==true),
2720 because the field locals might end up embedded in the parent struct local with the exact width.
2722 In other words, a store to a short field local should always done using an exact width store
2724 [00254538] 0x0009 ------------ const int 0x1234
2725 [002545B8] 0x000B -A--G--NR--- = short
2726 [00254570] 0x000A D------N---- lclVar short V43 tmp40
2728 mov word ptr [L_043], 0x1234
2730 Now, if we copy prop, say a short field local V43, to another short local V34
2731 for the following tree:
2733 [04E18650] 0x0001 ------------ lclVar int V34 tmp31
2734 [04E19714] 0x0002 -A---------- = int
2735 [04E196DC] 0x0001 D------N---- lclVar int V36 tmp33
2737 We will end with this tree:
2739 [04E18650] 0x0001 ------------ lclVar int V43 tmp40
2740 [04E19714] 0x0002 -A-----NR--- = int
2741 [04E196DC] 0x0001 D------N---- lclVar int V36 tmp33 EAX
2743 And eventually causing a fetch of 4-byte out from [L_043] :(
2744 mov EAX, dword ptr [L_043]
2746 The following check is to make sure we only perform the copy prop
2747 when we don't retrieve the wider value.
2750 if (copyVarDsc->lvIsStructField)
2752 var_types varType = (var_types)copyVarDsc->lvType;
2753 // Make sure we don't retrieve the wider value.
2754 return !varTypeIsSmall(varType) || (varType == tree->TypeGet());
2756 // Called in the context of a single copy assertion, so the types should have been
2757 // taken care by the assertion gen logic for other cases. Just return true.
2761 /**********************************************************************************
2763 * Perform copy assertion propagation when the lclNum and ssaNum of the "tree" match
2764 * the "curAssertion."
2767 GenTree* Compiler::optCopyAssertionProp(AssertionDsc* curAssertion,
2769 GenTree* stmt DEBUGARG(AssertionIndex index))
2771 const AssertionDsc::AssertionDscOp1& op1 = curAssertion->op1;
2772 const AssertionDsc::AssertionDscOp2& op2 = curAssertion->op2;
2774 noway_assert(op1.lcl.lclNum != op2.lcl.lclNum);
2776 unsigned lclNum = tree->gtLclVarCommon.GetLclNum();
2778 // Make sure one of the lclNum of the assertion matches with that of the tree.
2779 if (op1.lcl.lclNum != lclNum && op2.lcl.lclNum != lclNum)
2784 // Extract the matching lclNum and ssaNum.
2785 unsigned copyLclNum = (op1.lcl.lclNum == lclNum) ? op2.lcl.lclNum : op1.lcl.lclNum;
2786 unsigned copySsaNum = BAD_VAR_NUM;
2787 if (!optLocalAssertionProp)
2789 // Extract the ssaNum of the matching lclNum.
2790 unsigned ssaNum = (op1.lcl.lclNum == lclNum) ? op1.lcl.ssaNum : op2.lcl.ssaNum;
2791 copySsaNum = (op1.lcl.lclNum == lclNum) ? op2.lcl.ssaNum : op1.lcl.ssaNum;
2793 if (ssaNum != tree->AsLclVarCommon()->GetSsaNum())
2799 LclVarDsc* copyVarDsc = &lvaTable[copyLclNum];
2800 LclVarDsc* lclVarDsc = &lvaTable[lclNum];
2802 // Make sure the types are compatible.
2803 if (!optAssertionProp_LclVarTypeCheck(tree, lclVarDsc, copyVarDsc))
2808 // Make sure we can perform this copy prop.
2809 if (optCopyProp_LclVarScore(lclVarDsc, copyVarDsc, curAssertion->op1.lcl.lclNum == lclNum) <= 0)
2814 // If global assertion prop, by now we should have ref counts, fix them.
2815 if (lvaLocalVarRefCounted)
2817 lvaTable[lclNum].decRefCnts(compCurBB->getBBWeight(this), this);
2818 lvaTable[copyLclNum].incRefCnts(compCurBB->getBBWeight(this), this);
2819 tree->gtLclVarCommon.SetSsaNum(copySsaNum);
2821 tree->gtLclVarCommon.SetLclNum(copyLclNum);
2826 printf("\nAssertion prop in BB%02u:\n", compCurBB->bbNum);
2827 optPrintAssertion(curAssertion, index);
2828 gtDispTree(tree, nullptr, nullptr, true);
2832 // Update and morph the tree.
2833 return optAssertionProp_Update(tree, tree, stmt);
2836 /*****************************************************************************
2838 * Given a tree consisting of a just a LclVar and a set of available assertions
2839 * we try to propagate an assertion and modify the LclVar tree if we can.
2840 * We pass in the root of the tree via 'stmt', for local copy prop 'stmt' will
2841 * be nullptr. Returns the modified tree, or nullptr if no assertion prop took place.
2844 GenTree* Compiler::optAssertionProp_LclVar(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt)
2846 assert(tree->gtOper == GT_LCL_VAR);
2847 // If we have a var definition then bail or
2848 // If this is the address of the var then it will have the GTF_DONT_CSE
2849 // flag set and we don't want to to assertion prop on it.
2850 if (tree->gtFlags & (GTF_VAR_DEF | GTF_DONT_CSE))
2855 BitVecOps::Iter iter(apTraits, assertions);
2857 while (iter.NextElem(&index))
2859 AssertionIndex assertionIndex = GetAssertionIndex(index);
2860 if (assertionIndex > optAssertionCount)
2864 // See if the variable is equal to a constant or another variable.
2865 AssertionDsc* curAssertion = optGetAssertion(assertionIndex);
2866 if (curAssertion->assertionKind != OAK_EQUAL || curAssertion->op1.kind != O1K_LCLVAR)
2872 if (curAssertion->op2.kind == O2K_LCLVAR_COPY)
2874 // Cannot do copy prop during global assertion prop because of no knowledge
2875 // of kill sets. We will still make a == b copy assertions during the global phase to allow
2876 // for any implied assertions that can be retrieved. Because implied assertions look for
2877 // matching SSA numbers (i.e., if a0 == b1 and b1 == c0 then a0 == c0) they don't need kill sets.
2878 if (optLocalAssertionProp)
2880 // Perform copy assertion prop.
2881 GenTree* newTree = optCopyAssertionProp(curAssertion, tree, stmt DEBUGARG(assertionIndex));
2882 if (newTree == nullptr)
2884 // Skip and try next assertion.
2890 // Constant prop (for local assertion prop.)
2891 // The case where the tree type could be different than the LclVar type is caused by
2892 // gtFoldExpr, specifically the case of a cast, where the fold operation changes the type of the LclVar
2893 // node. In such a case is not safe to perform the substitution since later on the JIT will assert mismatching
2894 // types between trees.
2895 else if (curAssertion->op1.lcl.lclNum == tree->gtLclVarCommon.GetLclNum() &&
2896 tree->gtType == lvaTable[tree->gtLclVarCommon.GetLclNum()].lvType)
2898 // If local assertion prop just, perform constant prop.
2899 if (optLocalAssertionProp)
2901 return optConstantAssertionProp(curAssertion, tree, stmt DEBUGARG(assertionIndex));
2903 // If global assertion, perform constant propagation only if the VN's match and the lcl is non-CSE.
2904 else if (curAssertion->op1.vn == tree->gtVNPair.GetConservative())
2907 // Don't perform constant prop for CSE LclVars
2908 if (!lclNumIsCSE(tree->AsLclVarCommon()->GetLclNum()))
2911 return optConstantAssertionProp(curAssertion, tree, stmt DEBUGARG(assertionIndex));
2919 /*****************************************************************************
2921 * Given a set of "assertions" to search, find an assertion that matches
2922 * op1Kind and lclNum, op2Kind and the constant value and is either equal or
2923 * not equal assertion.
2925 AssertionIndex Compiler::optLocalAssertionIsEqualOrNotEqual(
2926 optOp1Kind op1Kind, unsigned lclNum, optOp2Kind op2Kind, ssize_t cnsVal, ASSERT_VALARG_TP assertions)
2928 noway_assert((op1Kind == O1K_LCLVAR) || (op1Kind == O1K_EXACT_TYPE) || (op1Kind == O1K_SUBTYPE));
2929 noway_assert((op2Kind == O2K_CONST_INT) || (op2Kind == O2K_IND_CNS_INT));
2930 if (!optLocalAssertionProp && BitVecOps::IsEmpty(apTraits, assertions))
2932 return NO_ASSERTION_INDEX;
2935 for (AssertionIndex index = 1; index <= optAssertionCount; ++index)
2937 AssertionDsc* curAssertion = optGetAssertion(index);
2938 if (optLocalAssertionProp || BitVecOps::IsMember(apTraits, assertions, index - 1))
2940 if ((curAssertion->assertionKind != OAK_EQUAL) && (curAssertion->assertionKind != OAK_NOT_EQUAL))
2945 if ((curAssertion->op1.kind == op1Kind) && (curAssertion->op1.lcl.lclNum == lclNum) &&
2946 (curAssertion->op2.kind == op2Kind))
2948 bool constantIsEqual = (curAssertion->op2.u1.iconVal == cnsVal);
2949 bool assertionIsEqual = (curAssertion->assertionKind == OAK_EQUAL);
2951 if (constantIsEqual || assertionIsEqual)
2958 return NO_ASSERTION_INDEX;
2961 /*****************************************************************************
2963 * Given a set of "assertions" to search for, find an assertion that is either
2964 * "op1" == "op2" or "op1" != "op2." Does a value number based comparison.
2967 AssertionIndex Compiler::optGlobalAssertionIsEqualOrNotEqual(ASSERT_VALARG_TP assertions, GenTree* op1, GenTree* op2)
2969 if (BitVecOps::IsEmpty(apTraits, assertions))
2971 return NO_ASSERTION_INDEX;
2973 BitVecOps::Iter iter(apTraits, assertions);
2975 while (iter.NextElem(&index))
2977 AssertionIndex assertionIndex = GetAssertionIndex(index);
2978 if (assertionIndex > optAssertionCount)
2982 AssertionDsc* curAssertion = optGetAssertion(assertionIndex);
2983 if ((curAssertion->assertionKind != OAK_EQUAL && curAssertion->assertionKind != OAK_NOT_EQUAL))
2988 if (curAssertion->op1.vn == op1->gtVNPair.GetConservative() &&
2989 curAssertion->op2.vn == op2->gtVNPair.GetConservative())
2991 return assertionIndex;
2994 return NO_ASSERTION_INDEX;
2997 /*****************************************************************************
2999 * Given a tree consisting of a RelOp and a set of available assertions
3000 * we try to propagate an assertion and modify the RelOp tree if we can.
3001 * We pass in the root of the tree via 'stmt', for local copy prop 'stmt' will be nullptr
3002 * Returns the modified tree, or nullptr if no assertion prop took place
3005 GenTree* Compiler::optAssertionProp_RelOp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt)
3007 assert(tree->OperKind() & GTK_RELOP);
3010 // Currently only GT_EQ or GT_NE are supported Relops for AssertionProp
3012 if ((tree->gtOper != GT_EQ) && (tree->gtOper != GT_NE))
3017 if (!optLocalAssertionProp)
3019 // If global assertion prop then use value numbering.
3020 return optAssertionPropGlobal_RelOp(assertions, tree, stmt);
3024 // If local assertion prop then use variable based prop.
3025 return optAssertionPropLocal_RelOp(assertions, tree, stmt);
3029 /*************************************************************************************
3031 * Given the set of "assertions" to look up a relop assertion about the relop "tree",
3032 * perform Value numbering based relop assertion propagation on the tree.
3035 GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt)
3037 assert(tree->OperGet() == GT_EQ || tree->OperGet() == GT_NE);
3039 GenTree* newTree = tree;
3040 GenTree* op1 = tree->gtOp.gtOp1;
3041 GenTree* op2 = tree->gtOp.gtOp2;
3043 if (op1->gtOper != GT_LCL_VAR)
3048 // Find an equal or not equal assertion involving "op1" and "op2".
3049 AssertionIndex index = optGlobalAssertionIsEqualOrNotEqual(assertions, op1, op2);
3050 if (index == NO_ASSERTION_INDEX)
3055 AssertionDsc* curAssertion = optGetAssertion(index);
3057 // Allow or not to reverse condition for OAK_NOT_EQUAL assertions.
3058 bool allowReverse = true;
3060 // If the assertion involves "op2" and it is a constant, then check if "op1" also has a constant value.
3061 if (vnStore->IsVNConstant(op2->gtVNPair.GetConservative()))
3063 ValueNum vnCns = op2->gtVNPair.GetConservative();
3067 printf("\nVN relop based constant assertion prop in BB%02u:\n", compCurBB->bbNum);
3068 printf("Assertion index=#%02u: ", index);
3070 printf(" %s ", (curAssertion->assertionKind == OAK_EQUAL) ? "==" : "!=");
3071 if (genActualType(op1->TypeGet()) == TYP_INT)
3073 printf("%d\n", vnStore->ConstantValue<int>(vnCns));
3075 else if (op1->TypeGet() == TYP_LONG)
3077 printf("%I64d\n", vnStore->ConstantValue<INT64>(vnCns));
3079 else if (op1->TypeGet() == TYP_DOUBLE)
3081 printf("%f\n", vnStore->ConstantValue<double>(vnCns));
3083 else if (op1->TypeGet() == TYP_FLOAT)
3085 printf("%f\n", vnStore->ConstantValue<float>(vnCns));
3087 else if (op1->TypeGet() == TYP_REF)
3089 // The only constant of TYP_REF that ValueNumbering supports is 'null'
3090 assert(vnStore->ConstantValue<size_t>(vnCns) == 0);
3095 printf("??unknown\n");
3097 gtDispTree(tree, nullptr, nullptr, true);
3100 // Decrement the ref counts, before we change the oper.
3101 lvaTable[op1->gtLclVar.gtLclNum].decRefCnts(compCurBB->getBBWeight(this), this);
3103 // Change the oper to const.
3104 if (genActualType(op1->TypeGet()) == TYP_INT)
3106 op1->ChangeOperConst(GT_CNS_INT);
3107 op1->gtIntCon.gtIconVal = vnStore->ConstantValue<int>(vnCns);
3109 else if (op1->TypeGet() == TYP_LONG)
3111 op1->ChangeOperConst(GT_CNS_NATIVELONG);
3112 op1->gtIntConCommon.SetLngValue(vnStore->ConstantValue<INT64>(vnCns));
3114 else if (op1->TypeGet() == TYP_DOUBLE)
3116 double constant = vnStore->ConstantValue<double>(vnCns);
3117 op1->ChangeOperConst(GT_CNS_DBL);
3118 op1->gtDblCon.gtDconVal = constant;
3120 // Nothing can be equal to NaN. So if IL had "op1 == NaN", then we already made op1 NaN,
3121 // which will yield a false correctly. Instead if IL had "op1 != NaN", then we already
3122 // made op1 NaN which will yield a true correctly. Note that this is irrespective of the
3123 // assertion we have made.
3124 allowReverse = (_isnan(constant) == 0);
3126 else if (op1->TypeGet() == TYP_FLOAT)
3128 float constant = vnStore->ConstantValue<float>(vnCns);
3129 op1->ChangeOperConst(GT_CNS_DBL);
3130 op1->gtDblCon.gtDconVal = constant;
3131 // See comments for TYP_DOUBLE.
3132 allowReverse = (_isnan(constant) == 0);
3134 else if (op1->TypeGet() == TYP_REF)
3136 op1->ChangeOperConst(GT_CNS_INT);
3137 // The only constant of TYP_REF that ValueNumbering supports is 'null'
3138 noway_assert(vnStore->ConstantValue<size_t>(vnCns) == 0);
3139 op1->gtIntCon.gtIconVal = 0;
3143 noway_assert(!"unknown type in Global_RelOp");
3146 op1->gtVNPair.SetBoth(vnCns); // Preserve the ValueNumPair, as ChangeOperConst/SetOper will clear it.
3148 // If the assertion involves "op2" and "op1" is also a local var, then just morph the tree.
3149 else if (op2->gtOper == GT_LCL_VAR)
3154 printf("\nVN relop based copy assertion prop in BB%02u:\n", compCurBB->bbNum);
3155 printf("Assertion index=#%02u: V%02d.%02d %s V%02d.%02d\n", index, op1->gtLclVar.gtLclNum,
3156 op1->gtLclVar.gtSsaNum, (curAssertion->assertionKind == OAK_EQUAL) ? "==" : "!=",
3157 op2->gtLclVar.gtLclNum, op2->gtLclVar.gtSsaNum);
3158 gtDispTree(tree, nullptr, nullptr, true);
3161 lvaTable[op1->gtLclVar.gtLclNum].decRefCnts(compCurBB->getBBWeight(this), this);
3163 // If floating point, don't just substitute op1 with op2, this won't work if
3164 // op2 is NaN. Just turn it into a "true" or "false" yielding expression.
3165 if (op1->TypeGet() == TYP_DOUBLE || op1->TypeGet() == TYP_FLOAT)
3167 // Note we can't trust the OAK_EQUAL as the value could end up being a NaN
3168 // violating the assertion. However, we create OAK_EQUAL assertions for floating
3169 // point only on JTrue nodes, so if the condition held earlier, it will hold
3170 // now. We don't create OAK_EQUAL assertion on floating point from GT_ASG
3171 // because we depend on value num which would constant prop the NaN.
3172 lvaTable[op2->gtLclVar.gtLclNum].decRefCnts(compCurBB->getBBWeight(this), this);
3173 op1->ChangeOperConst(GT_CNS_DBL);
3174 op1->gtDblCon.gtDconVal = 0;
3175 op2->ChangeOperConst(GT_CNS_DBL);
3176 op2->gtDblCon.gtDconVal = 0;
3178 // Change the op1 LclVar to the op2 LclVar
3181 noway_assert(varTypeIsIntegralOrI(op1->TypeGet()));
3182 lvaTable[op2->gtLclVar.gtLclNum].incRefCnts(compCurBB->getBBWeight(this), this);
3183 op1->AsLclVarCommon()->SetLclNum(op2->AsLclVarCommon()->GetLclNum());
3184 op1->AsLclVarCommon()->SetSsaNum(op2->AsLclVarCommon()->GetSsaNum());
3192 // Finally reverse the condition, if we have a not equal assertion.
3193 if (allowReverse && curAssertion->assertionKind == OAK_NOT_EQUAL)
3195 gtReverseCond(tree);
3198 newTree = fgMorphTree(tree);
3203 gtDispTree(newTree, nullptr, nullptr, true);
3207 return optAssertionProp_Update(newTree, tree, stmt);
3210 /*************************************************************************************
3212 * Given the set of "assertions" to look up a relop assertion about the relop "tree",
3213 * perform local variable name based relop assertion propagation on the tree.
3216 GenTree* Compiler::optAssertionPropLocal_RelOp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt)
3218 assert(tree->OperGet() == GT_EQ || tree->OperGet() == GT_NE);
3220 GenTree* op1 = tree->gtOp.gtOp1;
3221 GenTree* op2 = tree->gtOp.gtOp2;
3223 // For Local AssertionProp we only can fold when op1 is a GT_LCL_VAR
3224 if (op1->gtOper != GT_LCL_VAR)
3229 // For Local AssertionProp we only can fold when op2 is a GT_CNS_INT
3230 if (op2->gtOper != GT_CNS_INT)
3235 optOp1Kind op1Kind = O1K_LCLVAR;
3236 optOp2Kind op2Kind = O2K_CONST_INT;
3237 ssize_t cnsVal = op2->gtIntCon.gtIconVal;
3238 var_types cmpType = op1->TypeGet();
3240 // Don't try to fold/optimize Floating Compares; there are multiple zero values.
3241 if (varTypeIsFloating(cmpType))
3246 // Find an equal or not equal assertion about op1 var.
3247 unsigned lclNum = op1->gtLclVarCommon.gtLclNum;
3248 noway_assert(lclNum < lvaCount);
3249 AssertionIndex index = optLocalAssertionIsEqualOrNotEqual(op1Kind, lclNum, op2Kind, cnsVal, assertions);
3251 if (index == NO_ASSERTION_INDEX)
3256 AssertionDsc* curAssertion = optGetAssertion(index);
3258 bool assertionKindIsEqual = (curAssertion->assertionKind == OAK_EQUAL);
3259 bool constantIsEqual = false;
3261 if (genTypeSize(cmpType) == TARGET_POINTER_SIZE)
3263 constantIsEqual = (curAssertion->op2.u1.iconVal == cnsVal);
3265 #ifdef _TARGET_64BIT_
3266 else if (genTypeSize(cmpType) == sizeof(INT32))
3268 // Compare the low 32-bits only
3269 constantIsEqual = (((INT32)curAssertion->op2.u1.iconVal) == ((INT32)cnsVal));
3274 // We currently don't fold/optimze when the GT_LCL_VAR has been cast to a small type
3278 noway_assert(constantIsEqual || assertionKindIsEqual);
3283 printf("\nAssertion prop for index #%02u in BB%02u:\n", index, compCurBB->bbNum);
3284 gtDispTree(tree, nullptr, nullptr, true);
3288 // Return either CNS_INT 0 or CNS_INT 1.
3289 bool foldResult = (constantIsEqual == assertionKindIsEqual);
3290 if (tree->gtOper == GT_NE)
3292 foldResult = !foldResult;
3295 op2->gtIntCon.gtIconVal = foldResult;
3296 op2->gtType = TYP_INT;
3298 return optAssertionProp_Update(op2, tree, stmt);
3301 /*****************************************************************************
3303 * Given a tree consisting of a Cast and a set of available assertions
3304 * we try to propagate an assertion and modify the Cast tree if we can.
3305 * We pass in the root of the tree via 'stmt', for local copy prop 'stmt'
3308 * Returns the modified tree, or nullptr if no assertion prop took place.
3310 GenTree* Compiler::optAssertionProp_Cast(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt)
3312 assert(tree->gtOper == GT_CAST);
3314 var_types toType = tree->gtCast.gtCastType;
3315 GenTree* op1 = tree->gtCast.CastOp();
3317 // If we have a cast involving floating point types, then bail.
3318 if (varTypeIsFloating(toType) || varTypeIsFloating(op1->TypeGet()))
3323 // Skip over a GT_COMMA node(s), if necessary to get to the lcl.
3325 while (lcl->gtOper == GT_COMMA)
3327 lcl = lcl->gtOp.gtOp2;
3330 // If we don't have a cast of a LCL_VAR then bail.
3331 if (lcl->gtOper != GT_LCL_VAR)
3336 AssertionIndex index = optAssertionIsSubrange(lcl, toType, assertions);
3337 if (index != NO_ASSERTION_INDEX)
3339 LclVarDsc* varDsc = &lvaTable[lcl->gtLclVarCommon.gtLclNum];
3340 if (varDsc->lvNormalizeOnLoad() || varTypeIsLong(varDsc->TypeGet()))
3342 // For normalize on load variables it must be a narrowing cast to remove
3343 if (genTypeSize(toType) > genTypeSize(varDsc->TypeGet()))
3345 // Can we just remove the GTF_OVERFLOW flag?
3346 if ((tree->gtFlags & GTF_OVERFLOW) == 0)
3356 printf("\nSubrange prop for index #%02u in BB%02u:\n", index, compCurBB->bbNum);
3357 gtDispTree(tree, nullptr, nullptr, true);
3360 tree->gtFlags &= ~GTF_OVERFLOW; // This cast cannot overflow
3361 return optAssertionProp_Update(tree, tree, stmt);
3365 // GT_CAST long -> uint -> int
3369 // Where the lclvar is known to be in the range of [0..MAX_UINT]
3371 // A load of a 32-bit unsigned int is the same as a load of a 32-bit signed int
3373 if (toType == TYP_UINT)
3378 // Change the "lcl" type to match what the cast wanted, by propagating the type
3379 // change down the comma nodes leading to the "lcl", if we skipped them earlier.
3381 while (tmp->gtOper == GT_COMMA)
3383 tmp->gtType = toType;
3384 tmp = tmp->gtOp.gtOp2;
3386 noway_assert(tmp == lcl);
3387 tmp->gtType = toType;
3393 printf("\nSubrange prop for index #%02u in BB%02u:\n", index, compCurBB->bbNum);
3394 gtDispTree(tree, nullptr, nullptr, true);
3397 return optAssertionProp_Update(op1, tree, stmt);
3402 /*****************************************************************************
3404 * Given a tree with an array bounds check node, eliminate it because it was
3405 * checked already in the program.
3407 GenTree* Compiler::optAssertionProp_Comma(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt)
3409 // Remove the bounds check as part of the GT_COMMA node since we need parent pointer to remove nodes.
3410 // When processing visits the bounds check, it sets the throw kind to None if the check is redundant.
3411 if ((tree->gtGetOp1()->OperGet() == GT_ARR_BOUNDS_CHECK) &&
3412 ((tree->gtGetOp1()->gtFlags & GTF_ARR_BOUND_INBND) != 0))
3414 optRemoveRangeCheck(tree, stmt);
3415 return optAssertionProp_Update(tree, tree, stmt);
3420 /*****************************************************************************
3422 * Given a tree consisting of a Ind and a set of available assertions, we try
3423 * to propagate an assertion and modify the Ind tree if we can. We pass in the
3424 * root of the tree via 'stmt', for local copy prop 'stmt' will be nullptr.
3426 * Returns the modified tree, or nullptr if no assertion prop took place.
3430 GenTree* Compiler::optAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt)
3432 assert(tree->OperIsIndir());
3434 if (!(tree->gtFlags & GTF_EXCEPT))
3439 // Check for add of a constant.
3440 GenTree* op1 = tree->AsIndir()->Addr();
3441 if ((op1->gtOper == GT_ADD) && (op1->gtOp.gtOp2->gtOper == GT_CNS_INT))
3443 op1 = op1->gtOp.gtOp1;
3446 if (op1->gtOper != GT_LCL_VAR)
3451 unsigned lclNum = op1->gtLclVarCommon.gtLclNum;
3454 bool vnBased = false;
3455 AssertionIndex index = NO_ASSERTION_INDEX;
3457 if (optAssertionIsNonNull(op1, assertions DEBUGARG(&vnBased) DEBUGARG(&index)))
3462 (vnBased) ? printf("\nVN based non-null prop in BB%02u:\n", compCurBB->bbNum)
3463 : printf("\nNon-null prop for index #%02u in BB%02u:\n", index, compCurBB->bbNum);
3464 gtDispTree(tree, nullptr, nullptr, true);
3467 tree->gtFlags &= ~GTF_EXCEPT;
3468 tree->gtFlags |= GTF_IND_NONFAULTING;
3470 // Set this flag to prevent reordering
3471 tree->gtFlags |= GTF_ORDER_SIDEEFF;
3473 return optAssertionProp_Update(tree, tree, stmt);
3479 /*****************************************************************************
3480 * Check if a non-null assertion can be made about the input operand "op"
3481 * from the set of "assertions," or implicitly from the value number on "op."
3483 * Sets "pVnBased" if the assertion is value number based. If no matching
3484 * assertions are found from the table, then returns "NO_ASSERTION_INDEX."
3486 * Note: If both VN and assertion table yield a matching assertion, "pVnBased"
3487 * is only set and the return value is "NO_ASSERTION_INDEX."
3489 bool Compiler::optAssertionIsNonNull(GenTree* op,
3490 ASSERT_VALARG_TP assertions DEBUGARG(bool* pVnBased)
3491 DEBUGARG(AssertionIndex* pIndex))
3493 bool vnBased = (!optLocalAssertionProp && vnStore->IsKnownNonNull(op->gtVNPair.GetConservative()));
3495 *pVnBased = vnBased;
3501 *pIndex = NO_ASSERTION_INDEX;
3506 AssertionIndex index = optAssertionIsNonNullInternal(op, assertions);
3510 return index != NO_ASSERTION_INDEX;
3513 /*****************************************************************************
3514 * Check if a non-null assertion can be made about the input operand "op"
3515 * from the set of "assertions."
3518 AssertionIndex Compiler::optAssertionIsNonNullInternal(GenTree* op, ASSERT_VALARG_TP assertions)
3520 // If local assertion prop use lcl comparison, else use VN comparison.
3521 if (!optLocalAssertionProp)
3523 if (BitVecOps::MayBeUninit(assertions) || BitVecOps::IsEmpty(apTraits, assertions))
3525 return NO_ASSERTION_INDEX;
3528 ValueNum vn = op->gtVNPair.GetConservative();
3530 // Check each assertion to find if we have a vn == or != null assertion.
3531 BitVecOps::Iter iter(apTraits, assertions);
3533 while (iter.NextElem(&index))
3535 AssertionIndex assertionIndex = GetAssertionIndex(index);
3536 if (assertionIndex > optAssertionCount)
3540 AssertionDsc* curAssertion = optGetAssertion(assertionIndex);
3541 if (curAssertion->assertionKind != OAK_NOT_EQUAL)
3545 if (curAssertion->op1.vn != vn || curAssertion->op2.vn != ValueNumStore::VNForNull())
3549 return assertionIndex;
3554 unsigned lclNum = op->AsLclVarCommon()->GetLclNum();
3555 // Check each assertion to find if we have a variable == or != null assertion.
3556 for (AssertionIndex index = 1; index <= optAssertionCount; index++)
3558 AssertionDsc* curAssertion = optGetAssertion(index);
3559 if ((curAssertion->assertionKind == OAK_NOT_EQUAL) && // kind
3560 (curAssertion->op1.kind == O1K_LCLVAR) && // op1
3561 (curAssertion->op2.kind == O2K_CONST_INT) && // op2
3562 (curAssertion->op1.lcl.lclNum == lclNum) && (curAssertion->op2.u1.iconVal == 0))
3568 return NO_ASSERTION_INDEX;
3570 /*****************************************************************************
3572 * Given a tree consisting of a call and a set of available assertions, we
3573 * try to propagate a non-null assertion and modify the Call tree if we can.
3574 * Returns the modified tree, or nullptr if no assertion prop took place.
3577 GenTree* Compiler::optNonNullAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, GenTree* stmt)
3579 if ((call->gtFlags & GTF_CALL_NULLCHECK) == 0)
3583 GenTree* op1 = gtGetThisArg(call);
3584 noway_assert(op1 != nullptr);
3585 if (op1->gtOper != GT_LCL_VAR)
3591 bool vnBased = false;
3592 AssertionIndex index = NO_ASSERTION_INDEX;
3594 if (optAssertionIsNonNull(op1, assertions DEBUGARG(&vnBased) DEBUGARG(&index)))
3599 (vnBased) ? printf("\nVN based non-null prop in BB%02u:\n", compCurBB->bbNum)
3600 : printf("\nNon-null prop for index #%02u in BB%02u:\n", index, compCurBB->bbNum);
3601 gtDispTree(call, nullptr, nullptr, true);
3604 call->gtFlags &= ~GTF_CALL_NULLCHECK;
3605 call->gtFlags &= ~GTF_EXCEPT;
3606 noway_assert(call->gtFlags & GTF_SIDE_EFFECT);
3612 /*****************************************************************************
3614 * Given a tree consisting of a call and a set of available assertions, we
3615 * try to propagate an assertion and modify the Call tree if we can. Our
3616 * current modifications are limited to removing the nullptrCHECK flag from
3618 * We pass in the root of the tree via 'stmt', for local copy prop 'stmt'
3619 * will be nullptr. Returns the modified tree, or nullptr if no assertion prop
3624 GenTree* Compiler::optAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, GenTree* stmt)
3626 if (optNonNullAssertionProp_Call(assertions, call, stmt))
3628 return optAssertionProp_Update(call, call, stmt);
3630 else if (!optLocalAssertionProp && (call->gtCallType == CT_HELPER))
3632 if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_ISINSTANCEOFINTERFACE) ||
3633 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_ISINSTANCEOFARRAY) ||
3634 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_ISINSTANCEOFCLASS) ||
3635 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_ISINSTANCEOFANY) ||
3636 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_CHKCASTINTERFACE) ||
3637 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_CHKCASTARRAY) ||
3638 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_CHKCASTCLASS) ||
3639 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_CHKCASTANY) ||
3640 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_CHKCASTCLASS_SPECIAL))
3642 GenTree* arg1 = gtArgEntryByArgNum(call, 1)->node;
3643 if (arg1->gtOper != GT_LCL_VAR)
3648 GenTree* arg2 = gtArgEntryByArgNum(call, 0)->node;
3650 unsigned index = optAssertionIsSubtype(arg1, arg2, assertions);
3651 if (index != NO_ASSERTION_INDEX)
3656 printf("\nDid VN based subtype prop for index #%02u in BB%02u:\n", index, compCurBB->bbNum);
3657 gtDispTree(call, nullptr, nullptr, true);
3660 GenTree* list = nullptr;
3661 gtExtractSideEffList(call, &list, GTF_SIDE_EFFECT, true);
3662 if (list != nullptr)
3664 arg1 = gtNewOperNode(GT_COMMA, call->TypeGet(), list, arg1);
3668 return optAssertionProp_Update(arg1, call, stmt);
3676 /*****************************************************************************
3678 * Given a tree consisting of a comma node with a bounds check, remove any
3679 * redundant bounds check that has already been checked in the program flow.
3681 GenTree* Compiler::optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt)
3683 if (optLocalAssertionProp)
3688 assert(tree->gtOper == GT_ARR_BOUNDS_CHECK);
3690 #ifdef FEATURE_ENABLE_NO_RANGE_CHECKS
3691 if (JitConfig.JitNoRangeChks())
3696 printf("\nFlagging check redundant due to JitNoRangeChks in BB%02u:\n", compCurBB->bbNum);
3697 gtDispTree(tree, nullptr, nullptr, true);
3700 tree->gtFlags |= GTF_ARR_BOUND_INBND;
3703 #endif // FEATURE_ENABLE_NO_RANGE_CHECKS
3705 BitVecOps::Iter iter(apTraits, assertions);
3707 while (iter.NextElem(&index))
3709 AssertionIndex assertionIndex = GetAssertionIndex(index);
3710 if (assertionIndex > optAssertionCount)
3714 // If it is not a nothrow assertion, skip.
3715 AssertionDsc* curAssertion = optGetAssertion(assertionIndex);
3716 if (!curAssertion->IsBoundsCheckNoThrow())
3721 GenTreeBoundsChk* arrBndsChk = tree->AsBoundsChk();
3723 // Set 'isRedundant' to true if we can determine that 'arrBndsChk' can be
3724 // classified as a redundant bounds check using 'curAssertion'
3725 bool isRedundant = false;
3727 const char* dbgMsg = "Not Set";
3730 // Do we have a previous range check involving the same 'vnLen' upper bound?
3731 if (curAssertion->op1.bnd.vnLen == arrBndsChk->gtArrLen->gtVNPair.GetConservative())
3733 ValueNum vnCurIdx = arrBndsChk->gtIndex->gtVNPair.GetConservative();
3735 // Do we have the exact same lower bound 'vnIdx'?
3736 // a[i] followed by a[i]
3737 if (curAssertion->op1.bnd.vnIdx == vnCurIdx)
3741 dbgMsg = "a[i] followed by a[i]";
3744 // Are we using zero as the index?
3745 // It can always be considered as redundant with any previous value
3746 // a[*] followed by a[0]
3747 else if (vnCurIdx == vnStore->VNZeroForType(arrBndsChk->gtIndex->TypeGet()))
3751 dbgMsg = "a[*] followed by a[0]";
3754 // Do we have two constant indexes?
3755 else if (vnStore->IsVNConstant(curAssertion->op1.bnd.vnIdx) && vnStore->IsVNConstant(vnCurIdx))
3757 // Make sure the types match.
3758 var_types type1 = vnStore->TypeOfVN(curAssertion->op1.bnd.vnIdx);
3759 var_types type2 = vnStore->TypeOfVN(vnCurIdx);
3761 if (type1 == type2 && type1 == TYP_INT)
3763 int index1 = vnStore->ConstantValue<int>(curAssertion->op1.bnd.vnIdx);
3764 int index2 = vnStore->ConstantValue<int>(vnCurIdx);
3766 // the case where index1 == index2 should have been handled above
3767 assert(index1 != index2);
3769 // It can always be considered as redundant with any previous higher constant value
3770 // a[K1] followed by a[K2], with K2 >= 0 and K1 >= K2
3771 if (index2 >= 0 && index1 >= index2)
3775 dbgMsg = "a[K1] followed by a[K2], with K2 >= 0 and K1 >= K2";
3780 // Extend this to remove additional redundant bounds checks:
3781 // i.e. a[i+1] followed by a[i] by using the VN(i+1) >= VN(i)
3782 // a[i] followed by a[j] when j is known to be >= i
3783 // a[i] followed by a[5] when i is known to be >= 5
3794 printf("\nVN based redundant (%s) bounds check assertion prop for index #%02u in BB%02u:\n", dbgMsg,
3795 assertionIndex, compCurBB->bbNum);
3796 gtDispTree(tree, nullptr, nullptr, true);
3800 // Defer actually removing the tree until processing reaches its parent comma, since
3801 // optRemoveRangeCheck needs to rewrite the whole comma tree.
3802 arrBndsChk->gtFlags |= GTF_ARR_BOUND_INBND;
3808 /*****************************************************************************
3810 * Called when we have a successfully performed an assertion prop. We have
3811 * the newTree in hand. This method will replace the existing tree in the
3812 * stmt with the newTree.
3816 GenTree* Compiler::optAssertionProp_Update(GenTree* newTree, GenTree* tree, GenTree* stmt)
3818 noway_assert(newTree != nullptr);
3820 if (stmt == nullptr)
3822 noway_assert(optLocalAssertionProp);
3826 noway_assert(!optLocalAssertionProp);
3828 // If newTree == tree then we modified the tree in-place otherwise we have to
3829 // locate our parent node and update it so that it points to newTree
3830 if (newTree != tree)
3832 GenTree** link = gtFindLink(stmt, tree);
3834 if (link == nullptr)
3836 noway_assert(!"gtFindLink failed!");
3837 printf("\nCould not find parent of:\n");
3839 printf("\nIn this stmt:\n");
3843 noway_assert(link != nullptr);
3844 noway_assert(tree != nullptr);
3845 if (link != nullptr)
3847 // Replace the old operand with the newTree
3850 // We only need to ensure that the gtNext field is set as it is used to traverse
3851 // to the next node in the tree. We will re-morph this entire statement in
3852 // optAssertionPropMain(). It will reset the gtPrev and gtNext links for all nodes.
3854 newTree->gtNext = tree->gtNext;
3859 // Record that we propagated the assertion.
3860 optAssertionPropagated = true;
3861 optAssertionPropagatedCurrentStmt = true;
3866 /*****************************************************************************
3868 * Given a tree and a set of available assertions we try to propagate an
3869 * assertion and modify 'tree' if we can. We pass in the root of the tree
3870 * via 'stmt', for local copy prop 'stmt' will be nullptr.
3872 * Returns the modified tree, or nullptr if no assertion prop took place.
3875 GenTree* Compiler::optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt)
3877 switch (tree->gtOper)
3880 return optAssertionProp_LclVar(assertions, tree, stmt);
3887 return optAssertionProp_Ind(assertions, tree, stmt);
3889 case GT_ARR_BOUNDS_CHECK:
3890 return optAssertionProp_BndsChk(assertions, tree, stmt);
3893 return optAssertionProp_Comma(assertions, tree, stmt);
3896 return optAssertionProp_Cast(assertions, tree, stmt);
3899 return optAssertionProp_Call(assertions, tree->AsCall(), stmt);
3908 return optAssertionProp_RelOp(assertions, tree, stmt);
3915 //------------------------------------------------------------------------
3916 // optImpliedAssertions: Given a tree node that makes an assertion this
3917 // method computes the set of implied assertions
3918 // that are also true. The updated assertions are
3919 // maintained on the Compiler object.
3922 // assertionIndex : The id of the assertion.
3923 // activeAssertions : The assertions that are already true at this point.
3925 void Compiler::optImpliedAssertions(AssertionIndex assertionIndex, ASSERT_TP& activeAssertions)
3927 noway_assert(!optLocalAssertionProp);
3928 noway_assert(assertionIndex != 0);
3929 noway_assert(assertionIndex <= optAssertionCount);
3931 AssertionDsc* curAssertion = optGetAssertion(assertionIndex);
3932 if (!BitVecOps::IsEmpty(apTraits, activeAssertions))
3934 const ASSERT_TP mappedAssertions = optGetVnMappedAssertions(curAssertion->op1.vn);
3935 if (mappedAssertions == nullptr)
3940 ASSERT_TP chkAssertions = BitVecOps::MakeCopy(apTraits, mappedAssertions);
3942 if (curAssertion->op2.kind == O2K_LCLVAR_COPY)
3944 const ASSERT_TP op2Assertions = optGetVnMappedAssertions(curAssertion->op2.vn);
3945 if (op2Assertions != nullptr)
3947 BitVecOps::UnionD(apTraits, chkAssertions, op2Assertions);
3950 BitVecOps::IntersectionD(apTraits, chkAssertions, activeAssertions);
3952 if (BitVecOps::IsEmpty(apTraits, chkAssertions))
3957 // Check each assertion in chkAssertions to see if it can be applied to curAssertion
3958 BitVecOps::Iter chkIter(apTraits, chkAssertions);
3959 unsigned chkIndex = 0;
3960 while (chkIter.NextElem(&chkIndex))
3962 AssertionIndex chkAssertionIndex = GetAssertionIndex(chkIndex);
3963 if (chkAssertionIndex > optAssertionCount)
3967 if (chkAssertionIndex == assertionIndex)
3972 // Determine which one is a copy assertion and use the other to check for implied assertions.
3973 AssertionDsc* iterAssertion = optGetAssertion(chkAssertionIndex);
3974 if (curAssertion->IsCopyAssertion())
3976 optImpliedByCopyAssertion(curAssertion, iterAssertion, activeAssertions);
3978 else if (iterAssertion->IsCopyAssertion())
3980 optImpliedByCopyAssertion(iterAssertion, curAssertion, activeAssertions);
3984 // Is curAssertion a constant assignment of a 32-bit integer?
3985 // (i.e GT_LVL_VAR X == GT_CNS_INT)
3986 else if ((curAssertion->assertionKind == OAK_EQUAL) && (curAssertion->op1.kind == O1K_LCLVAR) &&
3987 (curAssertion->op2.kind == O2K_CONST_INT))
3989 optImpliedByConstAssertion(curAssertion, activeAssertions);
3993 /*****************************************************************************
3995 * Given a set of active assertions this method computes the set
3996 * of non-Null implied assertions that are also true
3999 void Compiler::optImpliedByTypeOfAssertions(ASSERT_TP& activeAssertions)
4001 if (BitVecOps::IsEmpty(apTraits, activeAssertions))
4006 // Check each assertion in activeAssertions to see if it can be applied to constAssertion
4007 BitVecOps::Iter chkIter(apTraits, activeAssertions);
4008 unsigned chkIndex = 0;
4009 while (chkIter.NextElem(&chkIndex))
4011 AssertionIndex chkAssertionIndex = GetAssertionIndex(chkIndex);
4012 if (chkAssertionIndex > optAssertionCount)
4016 // chkAssertion must be Type/Subtype is equal assertion
4017 AssertionDsc* chkAssertion = optGetAssertion(chkAssertionIndex);
4018 if ((chkAssertion->op1.kind != O1K_SUBTYPE && chkAssertion->op1.kind != O1K_EXACT_TYPE) ||
4019 (chkAssertion->assertionKind != OAK_EQUAL))
4024 // Search the assertion table for a non-null assertion on op1 that matches chkAssertion
4025 for (AssertionIndex impIndex = 1; impIndex <= optAssertionCount; impIndex++)
4027 AssertionDsc* impAssertion = optGetAssertion(impIndex);
4029 // The impAssertion must be different from the chkAssertion
4030 if (impIndex == chkAssertionIndex)
4035 // impAssertion must be a Non Null assertion on lclNum
4036 if ((impAssertion->assertionKind != OAK_NOT_EQUAL) ||
4037 ((impAssertion->op1.kind != O1K_LCLVAR) && (impAssertion->op1.kind != O1K_VALUE_NUMBER)) ||
4038 (impAssertion->op2.kind != O2K_CONST_INT) || (impAssertion->op1.vn != chkAssertion->op1.vn))
4043 // The bit may already be in the result set
4044 if (!BitVecOps::IsMember(apTraits, activeAssertions, impIndex - 1))
4046 BitVecOps::AddElemD(apTraits, activeAssertions, impIndex - 1);
4050 printf("\nCompiler::optImpliedByTypeOfAssertions: %s Assertion #%02d, implies assertion #%02d",
4051 (chkAssertion->op1.kind == O1K_SUBTYPE) ? "Subtype" : "Exact-type", chkAssertionIndex,
4057 // There is at most one non-null assertion that is implied by the current chkIndex assertion
4063 //------------------------------------------------------------------------
4064 // optGetVnMappedAssertions: Given a value number, get the assertions
4065 // we have about the value number.
4068 // vn - The given value number.
4071 // The assertions we have about the value number.
4074 ASSERT_VALRET_TP Compiler::optGetVnMappedAssertions(ValueNum vn)
4076 ASSERT_TP set = BitVecOps::UninitVal();
4077 if (optValueNumToAsserts->Lookup(vn, &set))
4081 return BitVecOps::UninitVal();
4084 /*****************************************************************************
4086 * Given a const assertion this method computes the set of implied assertions
4087 * that are also true
4090 void Compiler::optImpliedByConstAssertion(AssertionDsc* constAssertion, ASSERT_TP& result)
4092 noway_assert(constAssertion->assertionKind == OAK_EQUAL);
4093 noway_assert(constAssertion->op1.kind == O1K_LCLVAR);
4094 noway_assert(constAssertion->op2.kind == O2K_CONST_INT);
4096 ssize_t iconVal = constAssertion->op2.u1.iconVal;
4098 const ASSERT_TP chkAssertions = optGetVnMappedAssertions(constAssertion->op1.vn);
4099 if (chkAssertions == nullptr || BitVecOps::IsEmpty(apTraits, chkAssertions))
4104 // Check each assertion in chkAssertions to see if it can be applied to constAssertion
4105 BitVecOps::Iter chkIter(apTraits, chkAssertions);
4106 unsigned chkIndex = 0;
4107 while (chkIter.NextElem(&chkIndex))
4109 AssertionIndex chkAssertionIndex = GetAssertionIndex(chkIndex);
4110 if (chkAssertionIndex > optAssertionCount)
4114 // The impAssertion must be different from the const assertion.
4115 AssertionDsc* impAssertion = optGetAssertion(chkAssertionIndex);
4116 if (impAssertion == constAssertion)
4121 // The impAssertion must be an assertion about the same local var.
4122 if (impAssertion->op1.vn != constAssertion->op1.vn)
4127 bool usable = false;
4128 switch (impAssertion->op2.kind)
4131 // Is the const assertion's constant, within implied assertion's bounds?
4132 usable = ((iconVal >= impAssertion->op2.u2.loBound) && (iconVal <= impAssertion->op2.u2.hiBound));
4136 // Is the const assertion's constant equal/not equal to the implied assertion?
4137 usable = ((impAssertion->assertionKind == OAK_EQUAL) && (impAssertion->op2.u1.iconVal == iconVal)) ||
4138 ((impAssertion->assertionKind == OAK_NOT_EQUAL) && (impAssertion->op2.u1.iconVal != iconVal));
4142 // leave 'usable' = false;
4148 BitVecOps::AddElemD(apTraits, result, chkIndex);
4152 AssertionDsc* firstAssertion = optGetAssertion(1);
4153 printf("\nCompiler::optImpliedByConstAssertion: constAssertion #%02d , implies assertion #%02d",
4154 (constAssertion - firstAssertion) + 1, (impAssertion - firstAssertion) + 1);
4161 /*****************************************************************************
4163 * Given a copy assertion and a dependent assertion this method computes the
4164 * set of implied assertions that are also true.
4165 * For copy assertions, exact SSA num and LCL nums should match, because
4166 * we don't have kill sets and we depend on their value num for dataflow.
4169 void Compiler::optImpliedByCopyAssertion(AssertionDsc* copyAssertion, AssertionDsc* depAssertion, ASSERT_TP& result)
4171 noway_assert(copyAssertion->IsCopyAssertion());
4173 // Get the copyAssert's lcl/ssa nums.
4174 unsigned copyAssertLclNum = BAD_VAR_NUM;
4175 unsigned copyAssertSsaNum = SsaConfig::RESERVED_SSA_NUM;
4177 // Check if copyAssertion's op1 or op2 matches the depAssertion's op1.
4178 if (depAssertion->op1.lcl.lclNum == copyAssertion->op1.lcl.lclNum)
4180 copyAssertLclNum = copyAssertion->op2.lcl.lclNum;
4181 copyAssertSsaNum = copyAssertion->op2.lcl.ssaNum;
4183 else if (depAssertion->op1.lcl.lclNum == copyAssertion->op2.lcl.lclNum)
4185 copyAssertLclNum = copyAssertion->op1.lcl.lclNum;
4186 copyAssertSsaNum = copyAssertion->op1.lcl.ssaNum;
4188 // Check if copyAssertion's op1 or op2 matches the depAssertion's op2.
4189 else if (depAssertion->op2.kind == O2K_LCLVAR_COPY)
4191 if (depAssertion->op2.lcl.lclNum == copyAssertion->op1.lcl.lclNum)
4193 copyAssertLclNum = copyAssertion->op2.lcl.lclNum;
4194 copyAssertSsaNum = copyAssertion->op2.lcl.ssaNum;
4196 else if (depAssertion->op2.lcl.lclNum == copyAssertion->op2.lcl.lclNum)
4198 copyAssertLclNum = copyAssertion->op1.lcl.lclNum;
4199 copyAssertSsaNum = copyAssertion->op1.lcl.ssaNum;
4203 if (copyAssertLclNum == BAD_VAR_NUM || copyAssertSsaNum == SsaConfig::RESERVED_SSA_NUM)
4208 // Get the depAssert's lcl/ssa nums.
4209 unsigned depAssertLclNum = BAD_VAR_NUM;
4210 unsigned depAssertSsaNum = SsaConfig::RESERVED_SSA_NUM;
4211 if ((depAssertion->op1.kind == O1K_LCLVAR) && (depAssertion->op2.kind == O2K_LCLVAR_COPY))
4213 if ((depAssertion->op1.lcl.lclNum == copyAssertion->op1.lcl.lclNum) ||
4214 (depAssertion->op1.lcl.lclNum == copyAssertion->op2.lcl.lclNum))
4216 depAssertLclNum = depAssertion->op2.lcl.lclNum;
4217 depAssertSsaNum = depAssertion->op2.lcl.ssaNum;
4219 else if ((depAssertion->op2.lcl.lclNum == copyAssertion->op1.lcl.lclNum) ||
4220 (depAssertion->op2.lcl.lclNum == copyAssertion->op2.lcl.lclNum))
4222 depAssertLclNum = depAssertion->op1.lcl.lclNum;
4223 depAssertSsaNum = depAssertion->op1.lcl.ssaNum;
4227 if (depAssertLclNum == BAD_VAR_NUM || depAssertSsaNum == SsaConfig::RESERVED_SSA_NUM)
4232 // Is depAssertion a constant assignment of a 32-bit integer?
4233 // (i.e GT_LVL_VAR X == GT_CNS_INT)
4234 bool depIsConstAssertion = ((depAssertion->assertionKind == OAK_EQUAL) && (depAssertion->op1.kind == O1K_LCLVAR) &&
4235 (depAssertion->op2.kind == O2K_CONST_INT));
4237 // Search the assertion table for an assertion on op1 that matches depAssertion
4238 // The matching assertion is the implied assertion.
4239 for (AssertionIndex impIndex = 1; impIndex <= optAssertionCount; impIndex++)
4241 AssertionDsc* impAssertion = optGetAssertion(impIndex);
4243 // The impAssertion must be different from the copy and dependent assertions
4244 if (impAssertion == copyAssertion || impAssertion == depAssertion)
4249 if (!AssertionDsc::SameKind(depAssertion, impAssertion))
4254 bool op1MatchesCopy =
4255 (copyAssertLclNum == impAssertion->op1.lcl.lclNum) && (copyAssertSsaNum == impAssertion->op1.lcl.ssaNum);
4257 bool usable = false;
4258 switch (impAssertion->op2.kind)
4261 usable = op1MatchesCopy && ((impAssertion->op2.u2.loBound <= depAssertion->op2.u2.loBound) &&
4262 (impAssertion->op2.u2.hiBound >= depAssertion->op2.u2.hiBound));
4265 case O2K_CONST_LONG:
4266 usable = op1MatchesCopy && (impAssertion->op2.lconVal == depAssertion->op2.lconVal);
4269 case O2K_CONST_DOUBLE:
4270 // Exact memory match because of positive and negative zero
4271 usable = op1MatchesCopy &&
4272 (memcmp(&impAssertion->op2.dconVal, &depAssertion->op2.dconVal, sizeof(double)) == 0);
4275 case O2K_IND_CNS_INT:
4276 // This is the ngen case where we have an indirection of an address.
4277 noway_assert((impAssertion->op1.kind == O1K_EXACT_TYPE) || (impAssertion->op1.kind == O1K_SUBTYPE));
4282 usable = op1MatchesCopy && (impAssertion->op2.u1.iconVal == depAssertion->op2.u1.iconVal);
4285 case O2K_LCLVAR_COPY:
4286 // Check if op1 of impAssertion matches copyAssertion and also op2 of impAssertion matches depAssertion.
4287 if (op1MatchesCopy && (depAssertLclNum == impAssertion->op2.lcl.lclNum &&
4288 depAssertSsaNum == impAssertion->op2.lcl.ssaNum))
4294 // Otherwise, op2 of impAssertion should match copyAssertion and also op1 of impAssertion matches
4296 usable = ((copyAssertLclNum == impAssertion->op2.lcl.lclNum &&
4297 copyAssertSsaNum == impAssertion->op2.lcl.ssaNum) &&
4298 (depAssertLclNum == impAssertion->op1.lcl.lclNum &&
4299 depAssertSsaNum == impAssertion->op1.lcl.ssaNum));
4304 // leave 'usable' = false;
4310 BitVecOps::AddElemD(apTraits, result, impIndex - 1);
4315 AssertionDsc* firstAssertion = optGetAssertion(1);
4316 printf("\nCompiler::optImpliedByCopyAssertion: copyAssertion #%02d and depAssertion #%02d, implies "
4318 (copyAssertion - firstAssertion) + 1, (depAssertion - firstAssertion) + 1,
4319 (impAssertion - firstAssertion) + 1);
4322 // If the depAssertion is a const assertion then any other assertions that it implies could also imply a
4323 // subrange assertion.
4324 if (depIsConstAssertion)
4326 optImpliedByConstAssertion(impAssertion, result);
4332 #include "dataflow.h"
4334 /*****************************************************************************
4336 * Dataflow visitor like callback so that all dataflow is in a single place
4339 class AssertionPropFlowCallback
4342 ASSERT_TP preMergeOut;
4343 ASSERT_TP preMergeJumpDestOut;
4345 ASSERT_TP* mJumpDestOut;
4346 ASSERT_TP* mJumpDestGen;
4348 Compiler* m_pCompiler;
4349 BitVecTraits* apTraits;
4352 AssertionPropFlowCallback(Compiler* pCompiler, ASSERT_TP* jumpDestOut, ASSERT_TP* jumpDestGen)
4353 : preMergeOut(BitVecOps::UninitVal())
4354 , preMergeJumpDestOut(BitVecOps::UninitVal())
4355 , mJumpDestOut(jumpDestOut)
4356 , mJumpDestGen(jumpDestGen)
4357 , m_pCompiler(pCompiler)
4358 , apTraits(pCompiler->apTraits)
4362 // At the start of the merge function of the dataflow equations, initialize premerge state (to detect change.)
4363 void StartMerge(BasicBlock* block)
4365 JITDUMP("AssertionPropCallback::StartMerge: BB%02d in -> %s\n", block->bbNum,
4366 BitVecOps::ToString(apTraits, block->bbAssertionIn));
4367 BitVecOps::Assign(apTraits, preMergeOut, block->bbAssertionOut);
4368 BitVecOps::Assign(apTraits, preMergeJumpDestOut, mJumpDestOut[block->bbNum]);
4371 // During merge, perform the actual merging of the predecessor's (since this is a forward analysis) dataflow flags.
4372 void Merge(BasicBlock* block, BasicBlock* predBlock, flowList* preds)
4374 ASSERT_TP pAssertionOut = ((predBlock->bbJumpKind == BBJ_COND) && (predBlock->bbJumpDest == block))
4375 ? mJumpDestOut[predBlock->bbNum]
4376 : predBlock->bbAssertionOut;
4377 JITDUMP("AssertionPropCallback::Merge : BB%02d in -> %s, predBlock BB%02d out -> %s\n", block->bbNum,
4378 BitVecOps::ToString(apTraits, block->bbAssertionIn), predBlock->bbNum,
4379 BitVecOps::ToString(apTraits, predBlock->bbAssertionOut));
4380 BitVecOps::IntersectionD(apTraits, block->bbAssertionIn, pAssertionOut);
4383 // At the end of the merge store results of the dataflow equations, in a postmerge state.
4384 bool EndMerge(BasicBlock* block)
4386 JITDUMP("AssertionPropCallback::EndMerge : BB%02d in -> %s\n\n", block->bbNum,
4387 BitVecOps::ToString(apTraits, block->bbAssertionIn));
4389 BitVecOps::DataFlowD(apTraits, block->bbAssertionOut, block->bbAssertionGen, block->bbAssertionIn);
4390 BitVecOps::DataFlowD(apTraits, mJumpDestOut[block->bbNum], mJumpDestGen[block->bbNum], block->bbAssertionIn);
4392 bool changed = (!BitVecOps::Equal(apTraits, preMergeOut, block->bbAssertionOut) ||
4393 !BitVecOps::Equal(apTraits, preMergeJumpDestOut, mJumpDestOut[block->bbNum]));
4397 JITDUMP("AssertionPropCallback::Changed : BB%02d before out -> %s; after out -> %s;\n"
4398 "\t\tjumpDest before out -> %s; jumpDest after out -> %s;\n\n",
4399 block->bbNum, BitVecOps::ToString(apTraits, preMergeOut),
4400 BitVecOps::ToString(apTraits, block->bbAssertionOut),
4401 BitVecOps::ToString(apTraits, preMergeJumpDestOut),
4402 BitVecOps::ToString(apTraits, mJumpDestOut[block->bbNum]));
4406 JITDUMP("AssertionPropCallback::Unchanged : BB%02d out -> %s; \t\tjumpDest out -> %s\n\n", block->bbNum,
4407 BitVecOps::ToString(apTraits, block->bbAssertionOut),
4408 BitVecOps::ToString(apTraits, mJumpDestOut[block->bbNum]));
4415 /*****************************************************************************
4417 * Compute the assertions generated by each block.
4419 ASSERT_TP* Compiler::optComputeAssertionGen()
4421 ASSERT_TP* jumpDestGen = fgAllocateTypeForEachBlk<ASSERT_TP>();
4423 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
4425 ASSERT_TP valueGen = BitVecOps::MakeEmpty(apTraits);
4426 GenTree* jtrue = nullptr;
4428 // Walk the statement trees in this basic block.
4429 for (GenTree* stmt = block->bbTreeList; stmt; stmt = stmt->gtNext)
4431 noway_assert(stmt->gtOper == GT_STMT);
4433 for (GenTree* tree = stmt->gtStmt.gtStmtList; tree; tree = tree->gtNext)
4435 if (tree->gtOper == GT_JTRUE)
4437 // A GT_TRUE is always the last node in a tree, so we can break here
4438 assert((tree->gtNext == nullptr) && (stmt->gtNext == nullptr));
4443 if (tree->GeneratesAssertion())
4445 AssertionInfo info = tree->GetAssertionInfo();
4446 optImpliedAssertions(info.GetAssertionIndex(), valueGen);
4447 BitVecOps::AddElemD(apTraits, valueGen, info.GetAssertionIndex() - 1);
4452 if (jtrue != nullptr)
4454 // Copy whatever we have accumulated into jumpDest edge's valueGen.
4455 ASSERT_TP jumpDestValueGen = BitVecOps::MakeCopy(apTraits, valueGen);
4457 if (jtrue->GeneratesAssertion())
4459 AssertionInfo info = jtrue->GetAssertionInfo();
4460 AssertionIndex valueAssertionIndex;
4461 AssertionIndex jumpDestAssertionIndex;
4463 if (info.IsNextEdgeAssertion())
4465 valueAssertionIndex = info.GetAssertionIndex();
4466 jumpDestAssertionIndex = optFindComplementary(info.GetAssertionIndex());
4468 else // is jump edge assertion
4470 valueAssertionIndex = optFindComplementary(info.GetAssertionIndex());
4471 jumpDestAssertionIndex = info.GetAssertionIndex();
4474 if (valueAssertionIndex != NO_ASSERTION_INDEX)
4476 // Update valueGen if we have an assertion for the bbNext edge
4477 optImpliedAssertions(valueAssertionIndex, valueGen);
4478 BitVecOps::AddElemD(apTraits, valueGen, valueAssertionIndex - 1);
4481 if (jumpDestAssertionIndex != NO_ASSERTION_INDEX)
4483 // Update jumpDestValueGen if we have an assertion for the bbJumpDest edge
4484 optImpliedAssertions(jumpDestAssertionIndex, jumpDestValueGen);
4485 BitVecOps::AddElemD(apTraits, jumpDestValueGen, jumpDestAssertionIndex - 1);
4489 jumpDestGen[block->bbNum] = jumpDestValueGen;
4493 jumpDestGen[block->bbNum] = BitVecOps::MakeEmpty(apTraits);
4496 block->bbAssertionGen = valueGen;
4501 printf("\nBB%02u valueGen = %s", block->bbNum, BitVecOps::ToString(apTraits, block->bbAssertionGen));
4502 if (block->bbJumpKind == BBJ_COND)
4504 printf(" => BB%02u valueGen = %s,", block->bbJumpDest->bbNum,
4505 BitVecOps::ToString(apTraits, jumpDestGen[block->bbNum]));
4513 /*****************************************************************************
4515 * Initialize the assertion data flow flags that will be propagated.
4518 ASSERT_TP* Compiler::optInitAssertionDataflowFlags()
4520 ASSERT_TP* jumpDestOut = fgAllocateTypeForEachBlk<ASSERT_TP>();
4522 // The local assertion gen phase may have created unreachable blocks.
4523 // They will never be visited in the dataflow propagation phase, so they need to
4524 // be initialized correctly. This means that instead of setting their sets to
4525 // apFull (i.e. all possible bits set), we need to set the bits only for valid
4526 // assertions (note that at this point we are not creating any new assertions).
4527 // Also note that assertion indices start from 1.
4528 ASSERT_TP apValidFull = BitVecOps::MakeEmpty(apTraits);
4529 for (int i = 1; i <= optAssertionCount; i++)
4531 BitVecOps::AddElemD(apTraits, apValidFull, i - 1);
4534 // Initially estimate the OUT sets to everything except killed expressions
4535 // Also set the IN sets to 1, so that we can perform the intersection.
4536 // Also, zero-out the flags for handler blocks, as we could be in the
4537 // handler due to an exception bypassing the regular program flow which
4538 // actually generates assertions along the bbAssertionOut/jumpDestOut
4540 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
4542 if (bbIsHandlerBeg(block))
4544 block->bbAssertionIn = BitVecOps::MakeEmpty(apTraits);
4548 block->bbAssertionIn = BitVecOps::MakeCopy(apTraits, apValidFull);
4550 block->bbAssertionGen = BitVecOps::MakeEmpty(apTraits);
4551 block->bbAssertionOut = BitVecOps::MakeCopy(apTraits, apValidFull);
4552 jumpDestOut[block->bbNum] = BitVecOps::MakeCopy(apTraits, apValidFull);
4554 // Compute the data flow values for all tracked expressions
4555 // IN and OUT never change for the initial basic block B1
4556 BitVecOps::ClearD(apTraits, fgFirstBB->bbAssertionIn);
4560 // Callback data for the VN based constant prop visitor.
4561 struct VNAssertionPropVisitorInfo
4566 VNAssertionPropVisitorInfo(Compiler* pThis, BasicBlock* block, GenTree* stmt)
4567 : pThis(pThis), stmt(stmt), block(block)
4572 //------------------------------------------------------------------------------
4573 // optPrepareTreeForReplacement
4574 // Updates ref counts and extracts side effects from a tree so it can be
4575 // replaced with a comma separated list of side effects + a new tree.
4578 // The old and new trees may be the same. In this case, the tree will be
4579 // appended to the side-effect list (if present) and returned.
4582 // oldTree - The tree node to be dropped from the stmt expr.
4583 // newTree - The tree node to append to the side effect list from "oldTree".
4586 // Returns a comma separated list of side-effects present in the "oldTree".
4587 // When "newTree" is non-null:
4588 // 1. When side-effects are present in oldTree, newTree will be appended to the
4589 // comma separated list.
4590 // 2. When no side effects are present, then returns the "newTree" without
4592 // When "newTree" is null:
4593 // 1. Returns the extracted side-effects from "oldTree"
4594 // 2. When no side-effects are present, returns null.
4597 // Decrements ref counts for the "oldTree" that is going to be replaced. If there
4598 // are side effects in the tree, then ref counts for variables in the side effects
4599 // are incremented because they need to be kept in the stmt expr.
4601 // Either the "newTree" is returned when no side effects are present or a comma
4602 // separated side effect list with "newTree" is returned.
4604 GenTree* Compiler::optPrepareTreeForReplacement(GenTree* oldTree, GenTree* newTree)
4606 // If we have side effects, extract them and append newTree to the list.
4607 GenTree* sideEffList = nullptr;
4608 if (oldTree->gtFlags & GTF_PERSISTENT_SIDE_EFFECTS)
4610 gtExtractSideEffList(oldTree, &sideEffList, GTF_PERSISTENT_SIDE_EFFECTS_IN_CSE);
4614 noway_assert(sideEffList->gtFlags & GTF_SIDE_EFFECT);
4616 // Increment the ref counts as we want to keep the side effects.
4617 lvaRecursiveIncRefCounts(sideEffList);
4621 newTree = gtNewOperNode(GT_COMMA, newTree->TypeGet(), sideEffList, newTree);
4625 newTree = sideEffList;
4629 // Decrement the ref counts as the oldTree is going to be dropped.
4630 lvaRecursiveDecRefCounts(oldTree);
4634 //------------------------------------------------------------------------------
4635 // optVNConstantPropOnJTrue
4636 // Constant propagate on the JTrue node by extracting side effects and moving
4637 // them into their own statements. The relop node is then modified to yield
4638 // true or false, so the branch can be folded.
4641 // block - The block that contains the JTrue.
4642 // stmt - The JTrue stmt which can be evaluated to a constant.
4643 // tree - The JTrue node whose relop evaluates to 0 or non-zero value.
4646 // The jmpTrue tree node that has relop of the form "0 =/!= 0".
4647 // If "tree" evaluates to "true" relop is "0 == 0". Else relop is "0 != 0".
4650 // Special treatment for JTRUE nodes' constant propagation. This is because
4651 // for JTRUE(1) or JTRUE(0), if there are side effects they need to be put
4652 // in separate statements. This is to prevent relop's constant
4653 // propagation from doing a simple minded conversion from
4654 // (1) STMT(JTRUE(RELOP(COMMA(sideEffect, OP1), OP2)), S.T. op1 =/!= op2 to
4655 // (2) STMT(JTRUE(COMMA(sideEffect, 1/0)).
4657 // fgFoldConditional doesn't fold (2), a side-effecting JTRUE's op1. So, let us,
4658 // here, convert (1) as two statements: STMT(sideEffect), STMT(JTRUE(1/0)),
4659 // so that the JTRUE will get folded by fgFoldConditional.
4661 // Note: fgFoldConditional is called from other places as well, which may be
4662 // sensitive to adding new statements. Hence the change is not made directly
4663 // into fgFoldConditional.
4665 GenTree* Compiler::optVNConstantPropOnJTrue(BasicBlock* block, GenTree* stmt, GenTree* test)
4667 GenTree* relop = test->gtGetOp1();
4669 // VN based assertion non-null on this relop has been performed.
4670 if (!relop->OperIsCompare())
4676 // Make sure GTF_RELOP_JMP_USED flag is set so that we can later skip constant
4677 // prop'ing a JTRUE's relop child node for a second time in the pre-order
4680 assert((relop->gtFlags & GTF_RELOP_JMP_USED) != 0);
4682 if (!vnStore->IsVNConstant(relop->gtVNPair.GetConservative()))
4687 // Prepare the tree for replacement so any side effects can be extracted.
4688 GenTree* sideEffList = optPrepareTreeForReplacement(test, nullptr);
4693 if (sideEffList->OperGet() == GT_COMMA)
4695 newStmt = fgInsertStmtNearEnd(block, sideEffList->gtGetOp1());
4696 sideEffList = sideEffList->gtGetOp2();
4700 newStmt = fgInsertStmtNearEnd(block, sideEffList);
4701 sideEffList = nullptr;
4704 fgMorphBlockStmt(block, newStmt->AsStmt() DEBUGARG(__FUNCTION__));
4707 // Transform the relop's operands to be both zeroes.
4708 ValueNum vnZero = vnStore->VNZeroForType(TYP_INT);
4709 relop->gtOp.gtOp1 = gtNewIconNode(0);
4710 relop->gtOp.gtOp1->gtVNPair = ValueNumPair(vnZero, vnZero);
4711 relop->gtOp.gtOp2 = gtNewIconNode(0);
4712 relop->gtOp.gtOp2->gtVNPair = ValueNumPair(vnZero, vnZero);
4714 // Update the oper and restore the value numbers.
4715 ValueNum vnCns = relop->gtVNPair.GetConservative();
4716 ValueNum vnLib = relop->gtVNPair.GetLiberal();
4717 bool evalsToTrue = vnStore->CoercedConstantValue<INT64>(vnCns) != 0;
4718 relop->SetOper(evalsToTrue ? GT_EQ : GT_NE);
4719 relop->gtVNPair = ValueNumPair(vnLib, vnCns);
4724 //------------------------------------------------------------------------------
4725 // optVNConstantPropCurStmt
4726 // Performs constant prop on the current statement's tree nodes.
4729 // This function is called as part of a pre-order tree walk.
4732 // tree - The currently visited tree node.
4733 // stmt - The statement node in which the "tree" is present.
4734 // block - The block that contains the statement that contains the tree.
4737 // Returns the standard visitor walk result.
4740 // Checks if a node is an R-value and evaluates to a constant. If the node
4741 // evaluates to constant, then the tree is replaced by its side effects and
4742 // the constant node.
4744 Compiler::fgWalkResult Compiler::optVNConstantPropCurStmt(BasicBlock* block, GenTree* stmt, GenTree* tree)
4746 // Don't propagate floating-point constants into a TYP_STRUCT LclVar
4747 // This can occur for HFA return values (see hfa_sf3E_r.exe)
4748 if (tree->TypeGet() == TYP_STRUCT)
4750 return WALK_CONTINUE;
4753 switch (tree->OperGet())
4755 // Make sure we have an R-value.
4775 #ifdef LEGACY_BACKEND
4783 assert(false && "Unexpected GT_MULHI node encountered before lowering");
4790 // Don't transform long multiplies.
4791 if (tree->gtFlags & GTF_MUL_64RSLT)
4793 return WALK_SKIP_SUBTREES;
4798 // Make sure the local variable is an R-value.
4799 if ((tree->gtFlags & (GTF_VAR_DEF | GTF_DONT_CSE)))
4801 return WALK_CONTINUE;
4804 // Let's not conflict with CSE (to save the movw/movt).
4805 if (lclNumIsCSE(tree->AsLclVarCommon()->GetLclNum()))
4807 return WALK_CONTINUE;
4813 // Unknown node, continue to walk.
4814 return WALK_CONTINUE;
4817 // Perform the constant propagation
4818 GenTree* newTree = optVNConstantPropOnTree(block, stmt, tree);
4819 if (newTree == nullptr)
4821 // Not propagated, keep going.
4822 return WALK_CONTINUE;
4825 // Successful propagation, mark as assertion propagated and skip
4826 // sub-tree (with side-effects) visits.
4827 optAssertionProp_Update(newTree, tree, stmt);
4829 JITDUMP("After constant propagation on [%06u]:\n", tree->gtTreeID);
4830 DBEXEC(VERBOSE, gtDispTree(stmt));
4832 return WALK_SKIP_SUBTREES;
4835 //------------------------------------------------------------------------------
4836 // optVnNonNullPropCurStmt
4837 // Performs VN based non-null propagation on the tree node.
4840 // This function is called as part of a pre-order tree walk.
4843 // block - The block that contains the statement that contains the tree.
4844 // stmt - The statement node in which the "tree" is present.
4845 // tree - The currently visited tree node.
4851 // Performs value number based non-null propagation on GT_CALL and
4852 // indirections. This is different from flow based assertions and helps
4853 // unify VN based constant prop and non-null prop in a single pre-order walk.
4855 void Compiler::optVnNonNullPropCurStmt(BasicBlock* block, GenTree* stmt, GenTree* tree)
4857 ASSERT_TP empty = BitVecOps::UninitVal();
4858 GenTree* newTree = nullptr;
4859 if (tree->OperGet() == GT_CALL)
4861 newTree = optNonNullAssertionProp_Call(empty, tree->AsCall(), stmt);
4863 else if (tree->OperIsIndir())
4865 newTree = optAssertionProp_Ind(empty, tree, stmt);
4869 assert(newTree == tree);
4870 optAssertionProp_Update(newTree, tree, stmt);
4874 //------------------------------------------------------------------------------
4875 // optVNAssertionPropCurStmtVisitor
4876 // Unified Value Numbering based assertion propagation visitor.
4879 // This function is called as part of a pre-order tree walk.
4885 // An unified value numbering based assertion prop visitor that
4886 // performs non-null and constant assertion propagation based on
4890 Compiler::fgWalkResult Compiler::optVNAssertionPropCurStmtVisitor(GenTree** ppTree, fgWalkData* data)
4892 VNAssertionPropVisitorInfo* pData = (VNAssertionPropVisitorInfo*)data->pCallbackData;
4893 Compiler* pThis = pData->pThis;
4895 pThis->optVnNonNullPropCurStmt(pData->block, pData->stmt, *ppTree);
4897 return pThis->optVNConstantPropCurStmt(pData->block, pData->stmt, *ppTree);
4900 /*****************************************************************************
4902 * Perform VN based i.e., data flow based assertion prop first because
4903 * even if we don't gen new control flow assertions, we still propagate
4906 * Returns the skipped next stmt if the current statement or next few
4907 * statements got removed, else just returns the incoming stmt.
4909 GenTree* Compiler::optVNAssertionPropCurStmt(BasicBlock* block, GenTree* stmt)
4911 // TODO-Review: EH successor/predecessor iteration seems broken.
4912 // See: SELF_HOST_TESTS_ARM\jit\Directed\ExcepFilters\fault\fault.exe
4913 if (block->bbCatchTyp == BBCT_FAULT)
4918 // Preserve the prev link before the propagation and morph.
4919 GenTree* prev = (stmt == block->firstStmt()) ? nullptr : stmt->gtPrev;
4921 // Perform VN based assertion prop first, in case we don't find
4922 // anything in assertion gen.
4923 optAssertionPropagatedCurrentStmt = false;
4925 VNAssertionPropVisitorInfo data(this, block, stmt);
4926 fgWalkTreePre(&stmt->gtStmt.gtStmtExpr, Compiler::optVNAssertionPropCurStmtVisitor, &data);
4928 if (optAssertionPropagatedCurrentStmt)
4930 fgMorphBlockStmt(block, stmt->AsStmt() DEBUGARG("optVNAssertionPropCurStmt"));
4933 // Check if propagation removed statements starting from current stmt.
4934 // If so, advance to the next good statement.
4935 GenTree* nextStmt = (prev == nullptr) ? block->firstStmt() : prev->gtNext;
4939 /*****************************************************************************
4941 * The entry point for assertion propagation
4944 void Compiler::optAssertionPropMain()
4946 if (fgSsaPassesCompleted == 0)
4953 printf("*************** In optAssertionPropMain()\n");
4954 printf("Blocks/Trees at start of phase\n");
4955 fgDispBasicBlocks(true);
4959 optAssertionInit(false);
4961 noway_assert(optAssertionCount == 0);
4963 // First discover all value assignments and record them in the table.
4964 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
4968 fgRemoveRestOfBlock = false;
4970 GenTree* stmt = block->bbTreeList;
4973 // We need to remove the rest of the block.
4974 if (fgRemoveRestOfBlock)
4976 fgRemoveStmt(block, stmt);
4977 stmt = stmt->gtNext;
4982 // Perform VN based assertion prop before assertion gen.
4983 GenTree* nextStmt = optVNAssertionPropCurStmt(block, stmt);
4985 // Propagation resulted in removal of the remaining stmts, perform it.
4986 if (fgRemoveRestOfBlock)
4988 stmt = stmt->gtNext;
4992 // Propagation removed the current stmt or next few stmts, so skip them.
4993 if (stmt != nextStmt)
5000 // Perform assertion gen for control flow based assertions.
5001 for (GenTree* tree = stmt->gtStmt.gtStmtList; tree; tree = tree->gtNext)
5003 optAssertionGen(tree);
5006 // Advance the iterator
5007 stmt = stmt->gtNext;
5011 if (!optAssertionCount)
5017 fgDebugCheckLinks();
5020 // Allocate the bits for the predicate sensitive dataflow analysis
5021 bbJtrueAssertionOut = optInitAssertionDataflowFlags();
5022 ASSERT_TP* jumpDestGen = optComputeAssertionGen();
5024 // Modified dataflow algorithm for available expressions.
5025 DataFlow flow(this);
5026 AssertionPropFlowCallback ap(this, bbJtrueAssertionOut, jumpDestGen);
5027 flow.ForwardAnalysis(ap);
5029 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
5031 // Compute any implied non-Null assertions for block->bbAssertionIn
5032 optImpliedByTypeOfAssertions(block->bbAssertionIn);
5039 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
5041 printf("\nBB%02u", block->bbNum);
5042 printf(" valueIn = %s", BitVecOps::ToString(apTraits, block->bbAssertionIn));
5043 printf(" valueOut = %s", BitVecOps::ToString(apTraits, block->bbAssertionOut));
5044 if (block->bbJumpKind == BBJ_COND)
5046 printf(" => BB%02u", block->bbJumpDest->bbNum);
5047 printf(" valueOut= %s", BitVecOps::ToString(apTraits, bbJtrueAssertionOut[block->bbNum]));
5054 ASSERT_TP assertions = BitVecOps::MakeEmpty(apTraits);
5056 // Perform assertion propagation (and constant folding)
5057 for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
5059 BitVecOps::Assign(apTraits, assertions, block->bbAssertionIn);
5061 // TODO-Review: EH successor/predecessor iteration seems broken.
5062 // SELF_HOST_TESTS_ARM\jit\Directed\ExcepFilters\fault\fault.exe
5063 if (block->bbCatchTyp == BBCT_FAULT)
5068 // Make the current basic block address available globally.
5070 fgRemoveRestOfBlock = false;
5072 // Walk the statement trees in this basic block
5073 GenTree* stmt = block->FirstNonPhiDef();
5076 noway_assert(stmt->gtOper == GT_STMT);
5078 // Propagation tells us to remove the rest of the block. Remove it.
5079 if (fgRemoveRestOfBlock)
5081 fgRemoveStmt(block, stmt);
5082 stmt = stmt->gtNext;
5086 // Preserve the prev link before the propagation and morph, to check if propagation
5087 // removes the current stmt.
5088 GenTree* prev = (stmt == block->firstStmt()) ? nullptr : stmt->gtPrev;
5090 optAssertionPropagatedCurrentStmt = false; // set to true if a assertion propagation took place
5091 // and thus we must morph, set order, re-link
5092 for (GenTree* tree = stmt->gtStmt.gtStmtList; tree; tree = tree->gtNext)
5094 if (tree->OperIs(GT_JTRUE))
5096 // A GT_TRUE is always the last node in a tree, so we can break here
5097 assert((tree->gtNext == nullptr) && (stmt->gtNext == nullptr));
5101 JITDUMP("Propagating %s assertions for BB%02d, stmt [%06d], tree [%06d], tree -> %d\n",
5102 BitVecOps::ToString(apTraits, assertions), block->bbNum, dspTreeID(stmt), dspTreeID(tree),
5103 tree->GetAssertionInfo().GetAssertionIndex());
5105 GenTree* newTree = optAssertionProp(assertions, tree, stmt);
5108 assert(optAssertionPropagatedCurrentStmt == true);
5112 // If this tree makes an assertion - make it available.
5113 if (tree->GeneratesAssertion())
5115 AssertionInfo info = tree->GetAssertionInfo();
5116 optImpliedAssertions(info.GetAssertionIndex(), assertions);
5117 BitVecOps::AddElemD(apTraits, assertions, info.GetAssertionIndex() - 1);
5121 if (optAssertionPropagatedCurrentStmt)
5126 printf("Re-morphing this stmt:\n");
5131 // Re-morph the statement.
5132 fgMorphBlockStmt(block, stmt->AsStmt() DEBUGARG("optAssertionPropMain"));
5135 // Check if propagation removed statements starting from current stmt.
5136 // If so, advance to the next good statement.
5137 GenTree* nextStmt = (prev == nullptr) ? block->firstStmt() : prev->gtNext;
5138 stmt = (stmt == nextStmt) ? stmt->gtNext : nextStmt;
5140 optAssertionPropagatedCurrentStmt = false; // clear it back as we are done with stmts.
5144 fgDebugCheckBBlist();
5145 fgDebugCheckLinks();
5148 // Assertion propagation may have changed the reference counts
5149 // We need to resort the variable table
5151 if (optAssertionPropagated)
5153 lvaSortAgain = true;