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
21 /*****************************************************************************/
23 const unsigned short GenTree::gtOperKindTable[] = {
24 #define GTNODE(en, sn, cm, ok) ok + GTK_COMMUTE *cm,
28 /*****************************************************************************/
30 genTreeOps GenTree::OpAsgToOper(genTreeOps op)
33 assert(OperIsAssignment(op) && op != GT_ASG);
69 unreached(); // Precondition implies we don't get here.
73 /*****************************************************************************
75 * The types of different GenTree nodes
82 //--------------------------------------------
84 // IndentStack: This struct is used, along with its related enums and strings,
85 // to control both the indendtation and the printing of arcs.
88 // The mode of printing is set in the Constructor, using its 'compiler' argument.
89 // Currently it only prints arcs when fgOrder == fgOrderLinear.
90 // The type of arc to print is specified by the IndentInfo enum, and is controlled
91 // by the caller of the Push() method.
107 // Sets of strings for different dumping options vert bot top mid dash embedded terminal error
108 static const char* emptyIndents[IndentCharCount] = { " ", " ", " ", " ", " ", "{", "", "?" };
109 static const char* asciiIndents[IndentCharCount] = { "|", "\\", "/", "+", "-", "{", "*", "?" };
110 static const char* unicodeIndents[IndentCharCount] = { "\xe2\x94\x82", "\xe2\x94\x94", "\xe2\x94\x8c", "\xe2\x94\x9c", "\xe2\x94\x80", "{", "\xe2\x96\x8c", "?" };
113 typedef ArrayStack<Compiler::IndentInfo> IndentInfoStack;
116 IndentInfoStack stack;
117 const char** indents;
119 // Constructor for IndentStack. Uses 'compiler' to determine the mode of printing.
120 IndentStack(Compiler* compiler) : stack(compiler)
122 if (compiler->asciiTrees)
124 indents = asciiIndents;
128 indents = unicodeIndents;
132 // Return the depth of the current indentation.
135 return stack.Height();
138 // Push a new indentation onto the stack, of the given type.
139 void Push(Compiler::IndentInfo info)
144 // Pop the most recent indentation type off the stack.
145 Compiler::IndentInfo Pop()
150 // Print the current indentation and arcs.
153 unsigned indentCount = Depth();
154 for (unsigned i = 0; i < indentCount; i++)
156 unsigned index = indentCount - 1 - i;
157 switch (stack.Index(index))
159 case Compiler::IndentInfo::IINone:
162 case Compiler::IndentInfo::IIEmbedded:
163 printf("%s ", indents[ICEmbedded]);
165 case Compiler::IndentInfo::IIArc:
168 printf("%s%s%s", indents[ICMiddle], indents[ICDash], indents[ICDash]);
172 printf("%s ", indents[ICVertical]);
175 case Compiler::IndentInfo::IIArcBottom:
176 printf("%s%s%s", indents[ICBottom], indents[ICDash], indents[ICDash]);
178 case Compiler::IndentInfo::IIArcTop:
179 printf("%s%s%s", indents[ICTop], indents[ICDash], indents[ICDash]);
181 case Compiler::IndentInfo::IIError:
182 printf("%s%s%s", indents[ICError], indents[ICDash], indents[ICDash]);
188 printf("%s", indents[ICTerminal]);
192 //------------------------------------------------------------------------
193 // printIndent: This is a static method which simply invokes the 'print'
194 // method on its 'indentStack' argument.
197 // indentStack - specifies the information for the indentation & arcs to be printed
200 // This method exists to localize the checking for the case where indentStack is null.
202 static void printIndent(IndentStack* indentStack)
204 if (indentStack == nullptr)
208 indentStack->print();
211 static const char* nodeNames[] = {
212 #define GTNODE(en, sn, cm, ok) sn,
216 const char* GenTree::NodeName(genTreeOps op)
218 assert((unsigned)op < sizeof(nodeNames) / sizeof(nodeNames[0]));
220 return nodeNames[op];
223 static const char* opNames[] = {
224 #define GTNODE(en, sn, cm, ok) #en,
228 const char* GenTree::OpName(genTreeOps op)
230 assert((unsigned)op < sizeof(opNames) / sizeof(opNames[0]));
237 /*****************************************************************************
239 * When 'SMALL_TREE_NODES' is enabled, we allocate tree nodes in 2 different
240 * sizes: 'GTF_DEBUG_NODE_SMALL' for most nodes and 'GTF_DEBUG_NODE_LARGE' for
241 * the few nodes (such as calls and statement list nodes) that have more fields
242 * and take up a lot more space.
247 /* GT_COUNT'th oper is overloaded as 'undefined oper', so allocate storage for GT_COUNT'th oper also */
249 unsigned char GenTree::s_gtNodeSizes[GT_COUNT + 1];
252 void GenTree::InitNodeSize()
254 /* 'GT_LCL_VAR' often gets changed to 'GT_REG_VAR' */
256 assert(GenTree::s_gtNodeSizes[GT_LCL_VAR] >= GenTree::s_gtNodeSizes[GT_REG_VAR]);
258 /* Set all sizes to 'small' first */
260 for (unsigned op = 0; op <= GT_COUNT; op++)
262 GenTree::s_gtNodeSizes[op] = TREE_NODE_SZ_SMALL;
265 // Now set all of the appropriate entries to 'large'
266 CLANG_FORMAT_COMMENT_ANCHOR;
268 #if defined(FEATURE_HFA) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
269 // On ARM32, ARM64 and System V for struct returning
270 // there is code that does GT_ASG-tree.CopyObj call.
271 // CopyObj is a large node and the GT_ASG is small, which triggers an exception.
272 GenTree::s_gtNodeSizes[GT_ASG] = TREE_NODE_SZ_LARGE;
273 GenTree::s_gtNodeSizes[GT_RETURN] = TREE_NODE_SZ_LARGE;
274 #endif // defined(FEATURE_HFA) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
276 GenTree::s_gtNodeSizes[GT_CALL] = TREE_NODE_SZ_LARGE;
277 GenTree::s_gtNodeSizes[GT_CAST] = TREE_NODE_SZ_LARGE;
278 GenTree::s_gtNodeSizes[GT_FTN_ADDR] = TREE_NODE_SZ_LARGE;
279 GenTree::s_gtNodeSizes[GT_BOX] = TREE_NODE_SZ_LARGE;
280 GenTree::s_gtNodeSizes[GT_INDEX] = TREE_NODE_SZ_LARGE;
281 GenTree::s_gtNodeSizes[GT_ARR_BOUNDS_CHECK] = TREE_NODE_SZ_LARGE;
283 GenTree::s_gtNodeSizes[GT_SIMD_CHK] = TREE_NODE_SZ_LARGE;
284 #endif // FEATURE_SIMD
285 GenTree::s_gtNodeSizes[GT_ARR_ELEM] = TREE_NODE_SZ_LARGE;
286 GenTree::s_gtNodeSizes[GT_ARR_INDEX] = TREE_NODE_SZ_LARGE;
287 GenTree::s_gtNodeSizes[GT_ARR_OFFSET] = TREE_NODE_SZ_LARGE;
288 GenTree::s_gtNodeSizes[GT_RET_EXPR] = TREE_NODE_SZ_LARGE;
289 GenTree::s_gtNodeSizes[GT_OBJ] = TREE_NODE_SZ_LARGE;
290 GenTree::s_gtNodeSizes[GT_FIELD] = TREE_NODE_SZ_LARGE;
291 GenTree::s_gtNodeSizes[GT_STMT] = TREE_NODE_SZ_LARGE;
292 GenTree::s_gtNodeSizes[GT_CMPXCHG] = TREE_NODE_SZ_LARGE;
293 GenTree::s_gtNodeSizes[GT_QMARK] = TREE_NODE_SZ_LARGE;
294 GenTree::s_gtNodeSizes[GT_LEA] = TREE_NODE_SZ_LARGE;
295 GenTree::s_gtNodeSizes[GT_COPYOBJ] = TREE_NODE_SZ_LARGE;
296 GenTree::s_gtNodeSizes[GT_INTRINSIC] = TREE_NODE_SZ_LARGE;
297 GenTree::s_gtNodeSizes[GT_ALLOCOBJ] = TREE_NODE_SZ_LARGE;
298 #if USE_HELPERS_FOR_INT_DIV
299 GenTree::s_gtNodeSizes[GT_DIV] = TREE_NODE_SZ_LARGE;
300 GenTree::s_gtNodeSizes[GT_UDIV] = TREE_NODE_SZ_LARGE;
301 GenTree::s_gtNodeSizes[GT_MOD] = TREE_NODE_SZ_LARGE;
302 GenTree::s_gtNodeSizes[GT_UMOD] = TREE_NODE_SZ_LARGE;
304 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
305 GenTree::s_gtNodeSizes[GT_PUTARG_STK] = TREE_NODE_SZ_LARGE;
306 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
307 #if defined(FEATURE_HFA) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
308 // In importer for Hfa and register returned structs we rewrite GT_ASG to GT_COPYOBJ/GT_CPYBLK
309 // Make sure the sizes agree.
310 assert(GenTree::s_gtNodeSizes[GT_COPYOBJ] <= GenTree::s_gtNodeSizes[GT_ASG]);
311 assert(GenTree::s_gtNodeSizes[GT_COPYBLK] <= GenTree::s_gtNodeSizes[GT_ASG]);
312 #endif // !(defined(FEATURE_HFA) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING))
314 assert(GenTree::s_gtNodeSizes[GT_RETURN] == GenTree::s_gtNodeSizes[GT_ASG]);
316 // This list of assertions should come to contain all GenTree subtypes that are declared
318 assert(sizeof(GenTreeLclFld) <= GenTree::s_gtNodeSizes[GT_LCL_FLD]);
319 assert(sizeof(GenTreeLclVar) <= GenTree::s_gtNodeSizes[GT_LCL_VAR]);
321 static_assert_no_msg(sizeof(GenTree) <= TREE_NODE_SZ_SMALL);
322 static_assert_no_msg(sizeof(GenTreeUnOp) <= TREE_NODE_SZ_SMALL);
323 static_assert_no_msg(sizeof(GenTreeOp) <= TREE_NODE_SZ_SMALL);
324 static_assert_no_msg(sizeof(GenTreeVal) <= TREE_NODE_SZ_SMALL);
325 static_assert_no_msg(sizeof(GenTreeIntConCommon) <= TREE_NODE_SZ_SMALL);
326 static_assert_no_msg(sizeof(GenTreePhysReg) <= TREE_NODE_SZ_SMALL);
327 #ifndef LEGACY_BACKEND
328 static_assert_no_msg(sizeof(GenTreeJumpTable) <= TREE_NODE_SZ_SMALL);
329 #endif // !LEGACY_BACKEND
330 static_assert_no_msg(sizeof(GenTreeIntCon) <= TREE_NODE_SZ_SMALL);
331 static_assert_no_msg(sizeof(GenTreeLngCon) <= TREE_NODE_SZ_SMALL);
332 static_assert_no_msg(sizeof(GenTreeDblCon) <= TREE_NODE_SZ_SMALL);
333 static_assert_no_msg(sizeof(GenTreeStrCon) <= TREE_NODE_SZ_SMALL);
334 static_assert_no_msg(sizeof(GenTreeLclVarCommon) <= TREE_NODE_SZ_SMALL);
335 static_assert_no_msg(sizeof(GenTreeLclVar) <= TREE_NODE_SZ_SMALL);
336 static_assert_no_msg(sizeof(GenTreeLclFld) <= TREE_NODE_SZ_SMALL);
337 static_assert_no_msg(sizeof(GenTreeRegVar) <= TREE_NODE_SZ_SMALL);
338 static_assert_no_msg(sizeof(GenTreeCast) <= TREE_NODE_SZ_LARGE); // *** large node
339 static_assert_no_msg(sizeof(GenTreeBox) <= TREE_NODE_SZ_LARGE); // *** large node
340 static_assert_no_msg(sizeof(GenTreeField) <= TREE_NODE_SZ_LARGE); // *** large node
341 static_assert_no_msg(sizeof(GenTreeArgList) <= TREE_NODE_SZ_SMALL);
342 static_assert_no_msg(sizeof(GenTreeColon) <= TREE_NODE_SZ_SMALL);
343 static_assert_no_msg(sizeof(GenTreeCall) <= TREE_NODE_SZ_LARGE); // *** large node
344 static_assert_no_msg(sizeof(GenTreeCmpXchg) <= TREE_NODE_SZ_LARGE); // *** large node
345 static_assert_no_msg(sizeof(GenTreeFptrVal) <= TREE_NODE_SZ_LARGE); // *** large node
346 static_assert_no_msg(sizeof(GenTreeQmark) <= TREE_NODE_SZ_LARGE); // *** large node
347 static_assert_no_msg(sizeof(GenTreeIntrinsic) <= TREE_NODE_SZ_LARGE); // *** large node
348 static_assert_no_msg(sizeof(GenTreeIndex) <= TREE_NODE_SZ_LARGE); // *** large node
349 static_assert_no_msg(sizeof(GenTreeArrLen) <= TREE_NODE_SZ_LARGE); // *** large node
350 static_assert_no_msg(sizeof(GenTreeBoundsChk) <= TREE_NODE_SZ_LARGE); // *** large node
351 static_assert_no_msg(sizeof(GenTreeArrElem) <= TREE_NODE_SZ_LARGE); // *** large node
352 static_assert_no_msg(sizeof(GenTreeArrIndex) <= TREE_NODE_SZ_LARGE); // *** large node
353 static_assert_no_msg(sizeof(GenTreeArrOffs) <= TREE_NODE_SZ_LARGE); // *** large node
354 static_assert_no_msg(sizeof(GenTreeIndir) <= TREE_NODE_SZ_SMALL);
355 static_assert_no_msg(sizeof(GenTreeStoreInd) <= TREE_NODE_SZ_SMALL);
356 static_assert_no_msg(sizeof(GenTreeBlkOp) <= TREE_NODE_SZ_SMALL);
357 static_assert_no_msg(sizeof(GenTreeCpBlk) <= TREE_NODE_SZ_SMALL);
358 static_assert_no_msg(sizeof(GenTreeInitBlk) <= TREE_NODE_SZ_SMALL);
359 static_assert_no_msg(sizeof(GenTreeCpObj) <= TREE_NODE_SZ_LARGE); // *** large node
360 static_assert_no_msg(sizeof(GenTreeRetExpr) <= TREE_NODE_SZ_LARGE); // *** large node
361 static_assert_no_msg(sizeof(GenTreeStmt) <= TREE_NODE_SZ_LARGE); // *** large node
362 static_assert_no_msg(sizeof(GenTreeObj) <= TREE_NODE_SZ_LARGE); // *** large node
363 static_assert_no_msg(sizeof(GenTreeClsVar) <= TREE_NODE_SZ_SMALL);
364 static_assert_no_msg(sizeof(GenTreeArgPlace) <= TREE_NODE_SZ_SMALL);
365 static_assert_no_msg(sizeof(GenTreeLabel) <= TREE_NODE_SZ_SMALL);
366 static_assert_no_msg(sizeof(GenTreePhiArg) <= TREE_NODE_SZ_SMALL);
367 static_assert_no_msg(sizeof(GenTreeAllocObj) <= TREE_NODE_SZ_LARGE); // *** large node
368 #ifndef FEATURE_UNIX_AMD64_STRUCT_PASSING
369 static_assert_no_msg(sizeof(GenTreePutArgStk) <= TREE_NODE_SZ_SMALL);
370 #else // FEATURE_UNIX_AMD64_STRUCT_PASSING
371 static_assert_no_msg(sizeof(GenTreePutArgStk) <= TREE_NODE_SZ_LARGE);
372 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
375 static_assert_no_msg(sizeof(GenTreeSIMD) <= TREE_NODE_SZ_SMALL);
376 #endif // FEATURE_SIMD
379 size_t GenTree::GetNodeSize() const
381 return GenTree::s_gtNodeSizes[gtOper];
385 bool GenTree::IsNodeProperlySized() const
389 if (gtDebugFlags & GTF_DEBUG_NODE_SMALL)
391 size = TREE_NODE_SZ_SMALL;
395 assert(gtDebugFlags & GTF_DEBUG_NODE_LARGE);
396 size = TREE_NODE_SZ_LARGE;
399 return GenTree::s_gtNodeSizes[gtOper] <= size;
403 #else // SMALL_TREE_NODES
406 bool GenTree::IsNodeProperlySized() const
412 #endif // SMALL_TREE_NODES
414 /*****************************************************************************/
416 // make sure these get instantiated, because it's not in a header file
417 // (emulating the c++ 'export' keyword here)
418 // VC appears to be somewhat unpredictable about whether they end up in the .obj file without this
419 template Compiler::fgWalkResult Compiler::fgWalkTreePostRec<true>(GenTreePtr* pTree, fgWalkData* fgWalkData);
420 template Compiler::fgWalkResult Compiler::fgWalkTreePostRec<false>(GenTreePtr* pTree, fgWalkData* fgWalkData);
421 template Compiler::fgWalkResult Compiler::fgWalkTreePreRec<true>(GenTreePtr* pTree, fgWalkData* fgWalkData);
422 template Compiler::fgWalkResult Compiler::fgWalkTreePreRec<false>(GenTreePtr* pTree, fgWalkData* fgWalkData);
423 template Compiler::fgWalkResult Compiler::fgWalkTreeRec<true, true>(GenTreePtr* pTree, fgWalkData* fgWalkData);
424 template Compiler::fgWalkResult Compiler::fgWalkTreeRec<false, false>(GenTreePtr* pTree, fgWalkData* fgWalkData);
425 template Compiler::fgWalkResult Compiler::fgWalkTreeRec<true, false>(GenTreePtr* pTree, fgWalkData* fgWalkData);
426 template Compiler::fgWalkResult Compiler::fgWalkTreeRec<false, true>(GenTreePtr* pTree, fgWalkData* fgWalkData);
428 //******************************************************************************
429 // fgWalkTreePreRec - Helper function for fgWalkTreePre.
430 // walk tree in pre order, executing callback on every node.
431 // Template parameter 'computeStack' specifies whether to maintain
432 // a stack of ancestor nodes which can be viewed in the callback.
434 template <bool computeStack>
436 Compiler::fgWalkResult Compiler::fgWalkTreePreRec(GenTreePtr* pTree, fgWalkData* fgWalkData)
438 fgWalkResult result = WALK_CONTINUE;
439 GenTreePtr currentParent = fgWalkData->parent;
446 GenTreePtr tree = *pTree;
448 assert(tree->gtOper != GT_STMT);
449 GenTreeArgList* args; // For call node arg lists.
453 fgWalkData->parentStack->Push(tree);
456 /* Visit this node */
458 // if we are not in the mode where we only do the callback for local var nodes,
459 // visit the node unconditionally. Otherwise we will visit it under leaf handling.
460 if (!fgWalkData->wtprLclsOnly)
462 assert(tree == *pTree);
463 result = fgWalkData->wtprVisitorFn(pTree, fgWalkData);
464 if (result != WALK_CONTINUE)
470 /* Figure out what kind of a node we have */
472 oper = tree->OperGet();
473 kind = tree->OperKind();
475 /* Is this a constant or leaf node? */
477 if (kind & (GTK_CONST | GTK_LEAF))
479 if (fgWalkData->wtprLclsOnly && (oper == GT_LCL_VAR || oper == GT_LCL_FLD))
481 result = fgWalkData->wtprVisitorFn(pTree, fgWalkData);
485 else if (fgWalkData->wtprLclsOnly && GenTree::OperIsLocalStore(oper))
487 result = fgWalkData->wtprVisitorFn(pTree, fgWalkData);
488 if (result != WALK_CONTINUE)
494 fgWalkData->parent = tree;
496 /* Is it a 'simple' unary/binary operator? */
498 if (kind & GTK_SMPOP)
500 if (tree->gtGetOp2())
502 if (tree->gtOp.gtOp1 != nullptr)
504 result = fgWalkTreePreRec<computeStack>(&tree->gtOp.gtOp1, fgWalkData);
505 if (result == WALK_ABORT)
512 assert(tree->NullOp1Legal());
515 pTree = &tree->gtOp.gtOp2;
520 pTree = &tree->gtOp.gtOp1;
530 /* See what kind of a special operator we have here */
535 pTree = &tree->gtField.gtFldObj;
540 assert(tree->gtFlags & GTF_CALL);
542 /* Is this a call to unmanaged code ? */
543 if (fgWalkData->wtprLclsOnly && (tree->gtFlags & GTF_CALL_UNMANAGED))
545 result = fgWalkData->wtprVisitorFn(pTree, fgWalkData);
546 if (result == WALK_ABORT)
552 if (tree->gtCall.gtCallObjp)
554 result = fgWalkTreePreRec<computeStack>(&tree->gtCall.gtCallObjp, fgWalkData);
555 if (result == WALK_ABORT)
561 for (args = tree->gtCall.gtCallArgs; args; args = args->Rest())
563 result = fgWalkTreePreRec<computeStack>(args->pCurrent(), fgWalkData);
564 if (result == WALK_ABORT)
570 for (args = tree->gtCall.gtCallLateArgs; args; args = args->Rest())
572 result = fgWalkTreePreRec<computeStack>(args->pCurrent(), fgWalkData);
573 if (result == WALK_ABORT)
579 if (tree->gtCall.gtControlExpr)
581 result = fgWalkTreePreRec<computeStack>(&tree->gtCall.gtControlExpr, fgWalkData);
582 if (result == WALK_ABORT)
588 if (tree->gtCall.gtCallType == CT_INDIRECT)
590 if (tree->gtCall.gtCallCookie)
592 result = fgWalkTreePreRec<computeStack>(&tree->gtCall.gtCallCookie, fgWalkData);
593 if (result == WALK_ABORT)
598 pTree = &tree->gtCall.gtCallAddr;
609 result = fgWalkTreePreRec<computeStack>(&tree->gtArrElem.gtArrObj, fgWalkData);
610 if (result == WALK_ABORT)
616 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
618 result = fgWalkTreePreRec<computeStack>(&tree->gtArrElem.gtArrInds[dim], fgWalkData);
619 if (result == WALK_ABORT)
628 result = fgWalkTreePreRec<computeStack>(&tree->gtArrOffs.gtOffset, fgWalkData);
629 if (result == WALK_ABORT)
633 result = fgWalkTreePreRec<computeStack>(&tree->gtArrOffs.gtIndex, fgWalkData);
634 if (result == WALK_ABORT)
638 result = fgWalkTreePreRec<computeStack>(&tree->gtArrOffs.gtArrObj, fgWalkData);
639 if (result == WALK_ABORT)
647 result = fgWalkTreePreRec<computeStack>(&tree->gtCmpXchg.gtOpLocation, fgWalkData);
648 if (result == WALK_ABORT)
652 result = fgWalkTreePreRec<computeStack>(&tree->gtCmpXchg.gtOpValue, fgWalkData);
653 if (result == WALK_ABORT)
657 result = fgWalkTreePreRec<computeStack>(&tree->gtCmpXchg.gtOpComparand, fgWalkData);
658 if (result == WALK_ABORT)
665 case GT_ARR_BOUNDS_CHECK:
668 #endif // FEATURE_SIMD
669 result = fgWalkTreePreRec<computeStack>(&tree->gtBoundsChk.gtArrLen, fgWalkData);
670 if (result == WALK_ABORT)
674 result = fgWalkTreePreRec<computeStack>(&tree->gtBoundsChk.gtIndex, fgWalkData);
675 if (result == WALK_ABORT)
684 fgWalkData->compiler->gtDispTree(tree);
686 assert(!"unexpected operator");
688 } while (pTree != nullptr && *pTree != nullptr);
692 fgWalkData->parentStack->Pop();
695 if (result != WALK_ABORT)
698 // Restore fgWalkData->parent
700 fgWalkData->parent = currentParent;
705 /*****************************************************************************
707 * Walk all basic blocks and call the given function pointer for all tree
708 * nodes contained therein.
711 void Compiler::fgWalkAllTreesPre(fgWalkPreFn* visitor, void* pCallBackData)
715 for (block = fgFirstBB; block; block = block->bbNext)
719 for (tree = block->bbTreeList; tree; tree = tree->gtNext)
721 assert(tree->gtOper == GT_STMT);
723 fgWalkTreePre(&tree->gtStmt.gtStmtExpr, visitor, pCallBackData);
728 //******************************************************************************
729 // fgWalkTreePostRec - Helper function for fgWalkTreePost.
730 // Walk tree in post order, executing callback on every node
731 // template parameter 'computeStack' specifies whether to maintain
732 // a stack of ancestor nodes which can be viewed in the callback.
734 template <bool computeStack>
736 Compiler::fgWalkResult Compiler::fgWalkTreePostRec(GenTreePtr* pTree, fgWalkData* fgWalkData)
739 GenTreePtr currentParent = fgWalkData->parent;
744 GenTree* tree = *pTree;
746 assert(tree->gtOper != GT_STMT);
747 GenTreeArgList* args;
749 /* Figure out what kind of a node we have */
751 oper = tree->OperGet();
752 kind = tree->OperKind();
756 fgWalkData->parentStack->Push(tree);
759 /* Is this a constant or leaf node? */
761 if (kind & (GTK_CONST | GTK_LEAF))
766 /* Is it a 'simple' unary/binary operator? */
768 fgWalkData->parent = tree;
770 /* See what kind of a special operator we have here */
775 if (tree->gtField.gtFldObj)
777 result = fgWalkTreePostRec<computeStack>(&tree->gtField.gtFldObj, fgWalkData);
778 if (result == WALK_ABORT)
788 assert(tree->gtFlags & GTF_CALL);
790 if (tree->gtCall.gtCallObjp)
792 result = fgWalkTreePostRec<computeStack>(&tree->gtCall.gtCallObjp, fgWalkData);
793 if (result == WALK_ABORT)
799 for (args = tree->gtCall.gtCallArgs; args; args = args->Rest())
801 result = fgWalkTreePostRec<computeStack>(args->pCurrent(), fgWalkData);
802 if (result == WALK_ABORT)
808 for (args = tree->gtCall.gtCallLateArgs; args; args = args->Rest())
810 result = fgWalkTreePostRec<computeStack>(args->pCurrent(), fgWalkData);
811 if (result == WALK_ABORT)
816 if (tree->gtCall.gtCallType == CT_INDIRECT)
818 if (tree->gtCall.gtCallCookie)
820 result = fgWalkTreePostRec<computeStack>(&tree->gtCall.gtCallCookie, fgWalkData);
821 if (result == WALK_ABORT)
826 result = fgWalkTreePostRec<computeStack>(&tree->gtCall.gtCallAddr, fgWalkData);
827 if (result == WALK_ABORT)
833 if (tree->gtCall.gtControlExpr != nullptr)
835 result = fgWalkTreePostRec<computeStack>(&tree->gtCall.gtControlExpr, fgWalkData);
836 if (result == WALK_ABORT)
845 result = fgWalkTreePostRec<computeStack>(&tree->gtArrElem.gtArrObj, fgWalkData);
846 if (result == WALK_ABORT)
852 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
854 result = fgWalkTreePostRec<computeStack>(&tree->gtArrElem.gtArrInds[dim], fgWalkData);
855 if (result == WALK_ABORT)
863 result = fgWalkTreePostRec<computeStack>(&tree->gtArrOffs.gtOffset, fgWalkData);
864 if (result == WALK_ABORT)
868 result = fgWalkTreePostRec<computeStack>(&tree->gtArrOffs.gtIndex, fgWalkData);
869 if (result == WALK_ABORT)
873 result = fgWalkTreePostRec<computeStack>(&tree->gtArrOffs.gtArrObj, fgWalkData);
874 if (result == WALK_ABORT)
881 result = fgWalkTreePostRec<computeStack>(&tree->gtCmpXchg.gtOpComparand, fgWalkData);
882 if (result == WALK_ABORT)
886 result = fgWalkTreePostRec<computeStack>(&tree->gtCmpXchg.gtOpValue, fgWalkData);
887 if (result == WALK_ABORT)
891 result = fgWalkTreePostRec<computeStack>(&tree->gtCmpXchg.gtOpLocation, fgWalkData);
892 if (result == WALK_ABORT)
898 case GT_ARR_BOUNDS_CHECK:
901 #endif // FEATURE_SIMD
902 result = fgWalkTreePostRec<computeStack>(&tree->gtBoundsChk.gtArrLen, fgWalkData);
903 if (result == WALK_ABORT)
907 result = fgWalkTreePostRec<computeStack>(&tree->gtBoundsChk.gtIndex, fgWalkData);
908 if (result == WALK_ABORT)
916 GenTreeUnOp* phi = tree->AsUnOp();
917 if (phi->gtOp1 != nullptr)
919 for (GenTreeArgList* args = phi->gtOp1->AsArgList(); args != nullptr; args = args->Rest())
921 result = fgWalkTreePostRec<computeStack>(&args->gtOp1, fgWalkData);
922 if (result == WALK_ABORT)
935 GenTreeBlkOp* blkOp = tree->AsBlkOp();
936 result = fgWalkTreePostRec<computeStack>(&blkOp->gtOp1->AsArgList()->gtOp1, fgWalkData);
937 if (result == WALK_ABORT)
942 result = fgWalkTreePostRec<computeStack>(&blkOp->gtOp1->AsArgList()->gtOp2, fgWalkData);
943 if (result == WALK_ABORT)
948 result = fgWalkTreePostRec<computeStack>(&blkOp->gtOp2, fgWalkData);
949 if (result == WALK_ABORT)
958 GenTreeArgList* list = tree->AsArgList();
959 if (list->IsAggregate())
961 for (; list != nullptr; list = list->Rest())
963 result = fgWalkTreePostRec<computeStack>(&list->gtOp1, fgWalkData);
964 if (result == WALK_ABORT)
972 // GT_LIST nodes that do not represent aggregate arguments intentionally fall through to the
973 // default node processing below.
978 if (kind & GTK_SMPOP)
980 GenTree** op1Slot = &tree->gtOp.gtOp1;
983 if (tree->OperIsBinary())
985 if ((tree->gtFlags & GTF_REVERSE_OPS) == 0)
987 op2Slot = &tree->gtOp.gtOp2;
992 op1Slot = &tree->gtOp.gtOp2;
1000 if (*op1Slot != nullptr)
1002 result = fgWalkTreePostRec<computeStack>(op1Slot, fgWalkData);
1003 if (result == WALK_ABORT)
1009 if (op2Slot != nullptr && *op2Slot != nullptr)
1011 result = fgWalkTreePostRec<computeStack>(op2Slot, fgWalkData);
1012 if (result == WALK_ABORT)
1021 fgWalkData->compiler->gtDispTree(tree);
1022 assert(!"unexpected operator");
1030 fgWalkData->parent = currentParent;
1032 /* Finally, visit the current node */
1033 result = fgWalkData->wtpoVisitorFn(pTree, fgWalkData);
1037 fgWalkData->parentStack->Pop();
1043 // ****************************************************************************
1044 // walk tree doing callbacks in both pre- and post- order (both optional)
1046 template <bool doPreOrder, bool doPostOrder>
1048 Compiler::fgWalkResult Compiler::fgWalkTreeRec(GenTreePtr* pTree, fgWalkData* fgWalkData)
1050 fgWalkResult result = WALK_CONTINUE;
1055 GenTree* tree = *pTree;
1057 assert(tree->gtOper != GT_STMT);
1058 GenTreeArgList* args;
1060 /* Figure out what kind of a node we have */
1062 oper = tree->OperGet();
1063 kind = tree->OperKind();
1065 fgWalkData->parentStack->Push(tree);
1069 result = fgWalkData->wtprVisitorFn(pTree, fgWalkData);
1070 if (result == WALK_ABORT)
1077 oper = tree->OperGet();
1078 kind = tree->OperKind();
1082 // If we're skipping subtrees, we're done.
1083 if (result == WALK_SKIP_SUBTREES)
1088 /* Is this a constant or leaf node? */
1090 if ((kind & (GTK_CONST | GTK_LEAF)) != 0)
1095 /* Is it a 'simple' unary/binary operator? */
1097 if (kind & GTK_SMPOP)
1099 if (tree->gtOp.gtOp1)
1101 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtOp.gtOp1, fgWalkData);
1102 if (result == WALK_ABORT)
1108 if (tree->gtGetOp2())
1110 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtOp.gtOp2, fgWalkData);
1111 if (result == WALK_ABORT)
1120 /* See what kind of a special operator we have here */
1125 if (tree->gtField.gtFldObj)
1127 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtField.gtFldObj, fgWalkData);
1128 if (result == WALK_ABORT)
1138 assert(tree->gtFlags & GTF_CALL);
1140 if (tree->gtCall.gtCallObjp)
1142 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtCall.gtCallObjp, fgWalkData);
1143 if (result == WALK_ABORT)
1149 for (args = tree->gtCall.gtCallArgs; args; args = args->Rest())
1151 result = fgWalkTreeRec<doPreOrder, doPostOrder>(args->pCurrent(), fgWalkData);
1152 if (result == WALK_ABORT)
1158 for (args = tree->gtCall.gtCallLateArgs; args; args = args->Rest())
1160 result = fgWalkTreeRec<doPreOrder, doPostOrder>(args->pCurrent(), fgWalkData);
1161 if (result == WALK_ABORT)
1166 if (tree->gtCall.gtCallType == CT_INDIRECT)
1168 if (tree->gtCall.gtCallCookie)
1170 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtCall.gtCallCookie, fgWalkData);
1171 if (result == WALK_ABORT)
1176 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtCall.gtCallAddr, fgWalkData);
1177 if (result == WALK_ABORT)
1183 if (tree->gtCall.gtControlExpr)
1185 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtCall.gtControlExpr, fgWalkData);
1186 if (result == WALK_ABORT)
1196 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtArrElem.gtArrObj, fgWalkData);
1197 if (result == WALK_ABORT)
1203 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
1205 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtArrElem.gtArrInds[dim], fgWalkData);
1206 if (result == WALK_ABORT)
1214 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtArrOffs.gtOffset, fgWalkData);
1215 if (result == WALK_ABORT)
1219 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtArrOffs.gtIndex, fgWalkData);
1220 if (result == WALK_ABORT)
1224 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtArrOffs.gtArrObj, fgWalkData);
1225 if (result == WALK_ABORT)
1232 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtCmpXchg.gtOpComparand, fgWalkData);
1233 if (result == WALK_ABORT)
1237 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtCmpXchg.gtOpValue, fgWalkData);
1238 if (result == WALK_ABORT)
1242 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtCmpXchg.gtOpLocation, fgWalkData);
1243 if (result == WALK_ABORT)
1249 case GT_ARR_BOUNDS_CHECK:
1252 #endif // FEATURE_SIMD
1253 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtBoundsChk.gtArrLen, fgWalkData);
1254 if (result == WALK_ABORT)
1258 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtBoundsChk.gtIndex, fgWalkData);
1259 if (result == WALK_ABORT)
1267 fgWalkData->compiler->gtDispTree(tree);
1269 assert(!"unexpected operator");
1274 /* Finally, visit the current node */
1277 result = fgWalkData->wtpoVisitorFn(pTree, fgWalkData);
1280 fgWalkData->parentStack->Pop();
1285 /*****************************************************************************
1287 * Call the given function pointer for all nodes in the tree. The 'visitor'
1288 * fn should return one of the following values:
1290 * WALK_ABORT stop walking and return immediately
1291 * WALK_CONTINUE continue walking
1292 * WALK_SKIP_SUBTREES don't walk any subtrees of the node just visited
1295 Compiler::fgWalkResult Compiler::fgWalkTree(GenTreePtr* pTree,
1296 fgWalkPreFn* preVisitor,
1297 fgWalkPreFn* postVisitor,
1301 fgWalkData walkData;
1303 walkData.compiler = this;
1304 walkData.wtprVisitorFn = preVisitor;
1305 walkData.wtpoVisitorFn = postVisitor;
1306 walkData.pCallbackData = callBackData;
1307 walkData.parent = nullptr;
1308 walkData.wtprLclsOnly = false;
1310 walkData.printModified = false;
1312 ArrayStack<GenTree*> parentStack(this);
1313 walkData.parentStack = &parentStack;
1315 fgWalkResult result;
1317 assert(preVisitor || postVisitor);
1319 if (preVisitor && postVisitor)
1321 result = fgWalkTreeRec<true, true>(pTree, &walkData);
1323 else if (preVisitor)
1325 result = fgWalkTreeRec<true, false>(pTree, &walkData);
1329 result = fgWalkTreeRec<false, true>(pTree, &walkData);
1333 if (verbose && walkData.printModified)
1342 // ------------------------------------------------------------------------------------------
1343 // gtClearReg: Sets the register to the "no register assignment" value, depending upon
1344 // the type of the node, and whether it fits any of the special cases for register pairs
1345 // or multi-reg call nodes.
1348 // compiler - compiler instance
1352 void GenTree::gtClearReg(Compiler* compiler)
1354 #if CPU_LONG_USES_REGPAIR
1355 if (isRegPairType(TypeGet()) ||
1356 // (IsLocal() && isRegPairType(compiler->lvaTable[gtLclVarCommon.gtLclNum].TypeGet())) ||
1357 (OperGet() == GT_MUL && (gtFlags & GTF_MUL_64RSLT)))
1359 gtRegPair = REG_PAIR_NONE;
1362 #endif // CPU_LONG_USES_REGPAIR
1367 // Also clear multi-reg state if this is a call node
1370 this->AsCall()->ClearOtherRegs();
1372 else if (IsCopyOrReload())
1374 this->AsCopyOrReload()->ClearOtherRegs();
1378 //-----------------------------------------------------------
1379 // CopyReg: Copy the _gtRegNum/_gtRegPair/gtRegTag fields.
1382 // from - GenTree node from which to copy
1386 void GenTree::CopyReg(GenTreePtr from)
1388 // To do the copy, use _gtRegPair, which must be bigger than _gtRegNum. Note that the values
1389 // might be undefined (so gtRegTag == GT_REGTAG_NONE).
1390 _gtRegPair = from->_gtRegPair;
1391 C_ASSERT(sizeof(_gtRegPair) >= sizeof(_gtRegNum));
1392 INDEBUG(gtRegTag = from->gtRegTag;)
1394 // Also copy multi-reg state if this is a call node
1397 assert(from->IsCall());
1398 this->AsCall()->CopyOtherRegs(from->AsCall());
1400 else if (IsCopyOrReload())
1402 this->AsCopyOrReload()->CopyOtherRegs(from->AsCopyOrReload());
1406 //------------------------------------------------------------------
1407 // gtHasReg: Whether node beeen assigned a register by LSRA
1413 // Returns true if the node was assigned a register.
1415 // In case of multi-reg call nodes, it is considered
1416 // having a reg if regs are allocated for all its
1419 // In case of GT_COPY or GT_RELOAD of a multi-reg call,
1420 // GT_COPY/GT_RELOAD is considered having a reg if it
1421 // has a reg assigned to any of its positions.
1424 // In order for this to work properly, gtClearReg must be called
1425 // prior to setting the register value.
1427 bool GenTree::gtHasReg() const
1431 #if CPU_LONG_USES_REGPAIR
1432 if (isRegPairType(TypeGet()))
1434 assert(_gtRegNum != REG_NA);
1435 INDEBUG(assert(gtRegTag == GT_REGTAG_REGPAIR));
1436 hasReg = (gtRegPair != REG_PAIR_NONE);
1441 assert(_gtRegNum != REG_PAIR_NONE);
1442 INDEBUG(assert(gtRegTag == GT_REGTAG_REG));
1444 if (IsMultiRegCall())
1446 // Has to cast away const-ness because GetReturnTypeDesc() is a non-const method
1447 GenTree* tree = const_cast<GenTree*>(this);
1448 GenTreeCall* call = tree->AsCall();
1449 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
1452 // A Multi-reg call node is said to have regs, if it has
1453 // reg assigned to each of its result registers.
1454 for (unsigned i = 0; i < regCount; ++i)
1456 hasReg = (call->GetRegNumByIdx(i) != REG_NA);
1463 else if (IsCopyOrReloadOfMultiRegCall())
1465 GenTree* tree = const_cast<GenTree*>(this);
1466 GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
1467 GenTreeCall* call = copyOrReload->gtGetOp1()->AsCall();
1468 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
1471 // A Multi-reg copy or reload node is said to have regs,
1472 // if it has valid regs in any of the positions.
1473 for (unsigned i = 0; i < regCount; ++i)
1475 hasReg = (copyOrReload->GetRegNumByIdx(i) != REG_NA);
1484 hasReg = (gtRegNum != REG_NA);
1491 //---------------------------------------------------------------
1492 // gtGetRegMask: Get the reg mask of the node.
1498 // Reg Mask of GenTree node.
1500 regMaskTP GenTree::gtGetRegMask() const
1502 regMaskTP resultMask;
1504 #if CPU_LONG_USES_REGPAIR
1505 if (isRegPairType(TypeGet()))
1507 resultMask = genRegPairMask(gtRegPair);
1512 if (IsMultiRegCall())
1514 // temporarily cast away const-ness as AsCall() method is not declared const
1515 resultMask = genRegMask(gtRegNum);
1516 GenTree* temp = const_cast<GenTree*>(this);
1517 resultMask |= temp->AsCall()->GetOtherRegMask();
1519 else if (IsCopyOrReloadOfMultiRegCall())
1521 // A multi-reg copy or reload, will have valid regs for only those
1522 // positions that need to be copied or reloaded. Hence we need
1523 // to consider only those registers for computing reg mask.
1525 GenTree* tree = const_cast<GenTree*>(this);
1526 GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
1527 GenTreeCall* call = copyOrReload->gtGetOp1()->AsCall();
1528 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
1530 resultMask = RBM_NONE;
1531 for (unsigned i = 0; i < regCount; ++i)
1533 regNumber reg = copyOrReload->GetRegNumByIdx(i);
1536 resultMask |= genRegMask(reg);
1542 resultMask = genRegMask(gtRegNum);
1549 //---------------------------------------------------------------
1550 // GetOtherRegMask: Get the reg mask of gtOtherRegs of call node
1556 // Reg mask of gtOtherRegs of call node.
1558 regMaskTP GenTreeCall::GetOtherRegMask() const
1560 regMaskTP resultMask = RBM_NONE;
1562 #if FEATURE_MULTIREG_RET
1563 for (unsigned i = 0; i < MAX_RET_REG_COUNT - 1; ++i)
1565 if (gtOtherRegs[i] != REG_NA)
1567 resultMask |= genRegMask(gtOtherRegs[i]);
1577 #ifndef LEGACY_BACKEND
1579 //-------------------------------------------------------------------------
1580 // HasNonStandardAddedArgs: Return true if the method has non-standard args added to the call
1581 // argument list during argument morphing (fgMorphArgs), e.g., passed in R10 or R11 on AMD64.
1582 // See also GetNonStandardAddedArgCount().
1585 // compiler - the compiler instance
1588 // true if there are any such args, false otherwise.
1590 bool GenTreeCall::HasNonStandardAddedArgs(Compiler* compiler) const
1592 return GetNonStandardAddedArgCount(compiler) != 0;
1595 //-------------------------------------------------------------------------
1596 // GetNonStandardAddedArgCount: Get the count of non-standard arguments that have been added
1597 // during call argument morphing (fgMorphArgs). Do not count non-standard args that are already
1598 // counted in the argument list prior to morphing.
1600 // This function is used to help map the caller and callee arguments during tail call setup.
1603 // compiler - the compiler instance
1606 // The count of args, as described.
1609 // It would be more general to have fgMorphArgs set a bit on the call node when such
1610 // args are added to a call, and a bit on each such arg, and then have this code loop
1611 // over the call args when the special call bit is set, counting the args with the special
1612 // arg bit. This seems pretty heavyweight, though. Instead, this logic needs to be kept
1613 // in sync with fgMorphArgs.
1615 int GenTreeCall::GetNonStandardAddedArgCount(Compiler* compiler) const
1617 if (IsUnmanaged() && !compiler->opts.ShouldUsePInvokeHelpers())
1619 // R11 = PInvoke cookie param
1622 else if (gtCallType == CT_INDIRECT)
1624 if (IsVirtualStub())
1626 // R11 = Virtual stub param
1629 else if (gtCallCookie != nullptr)
1631 // R10 = PInvoke target param
1632 // R11 = PInvoke cookie param
1639 #endif // !LEGACY_BACKEND
1641 //-------------------------------------------------------------------------
1642 // TreatAsHasRetBufArg:
1645 // compiler, the compiler instance so that we can call eeGetHelperNum
1648 // Returns true if we treat the call as if it has a retBuf argument
1649 // This method may actually have a retBuf argument
1650 // or it could be a JIT helper that we are still transforming during
1651 // the importer phase.
1654 // On ARM64 marking the method with the GTF_CALL_M_RETBUFFARG flag
1655 // will make HasRetBufArg() return true, but will also force the
1656 // use of register x8 to pass the RetBuf argument.
1658 // These two Jit Helpers that we handle here by returning true
1659 // aren't actually defined to return a struct, so they don't expect
1660 // their RetBuf to be passed in x8, instead they expect it in x0.
1662 bool GenTreeCall::TreatAsHasRetBufArg(Compiler* compiler) const
1670 // If we see a Jit helper call that returns a TYP_STRUCT we will
1671 // transform it as if it has a Return Buffer Argument
1673 if (IsHelperCall() && (gtReturnType == TYP_STRUCT))
1675 // There are two possible helper calls that use this path:
1676 // CORINFO_HELP_GETFIELDSTRUCT and CORINFO_HELP_UNBOX_NULLABLE
1678 CorInfoHelpFunc helpFunc = compiler->eeGetHelperNum(gtCallMethHnd);
1680 if (helpFunc == CORINFO_HELP_GETFIELDSTRUCT)
1684 else if (helpFunc == CORINFO_HELP_UNBOX_NULLABLE)
1690 assert(!"Unexpected JIT helper in TreatAsHasRetBufArg");
1697 //-------------------------------------------------------------------------
1698 // IsHelperCall: Determine if this GT_CALL node is a specific helper call.
1701 // compiler - the compiler instance so that we can call eeFindHelper
1704 // Returns true if this GT_CALL node is a call to the specified helper.
1706 bool GenTreeCall::IsHelperCall(Compiler* compiler, unsigned helper) const
1708 return IsHelperCall(compiler->eeFindHelper(helper));
1711 /*****************************************************************************
1713 * Returns non-zero if the two trees are identical.
1716 bool GenTree::Compare(GenTreePtr op1, GenTreePtr op2, bool swapOK)
1721 // printf("tree1:\n"); gtDispTree(op1);
1722 // printf("tree2:\n"); gtDispTree(op2);
1728 return (op2 == nullptr);
1739 assert(op1->gtOper != GT_STMT);
1740 assert(op2->gtOper != GT_STMT);
1742 oper = op1->OperGet();
1744 /* The operators must be equal */
1746 if (oper != op2->gtOper)
1751 /* The types must be equal */
1753 if (op1->gtType != op2->gtType)
1758 /* Overflow must be equal */
1759 if (op1->gtOverflowEx() != op2->gtOverflowEx())
1764 /* Sensible flags must be equal */
1765 if ((op1->gtFlags & (GTF_UNSIGNED)) != (op2->gtFlags & (GTF_UNSIGNED)))
1770 /* Figure out what kind of nodes we're comparing */
1772 kind = op1->OperKind();
1774 /* Is this a constant node? */
1776 if (kind & GTK_CONST)
1781 if (op1->gtIntCon.gtIconVal == op2->gtIntCon.gtIconVal)
1787 // TODO-CQ: Enable this in the future
1789 if (op1->gtLngCon.gtLconVal == op2->gtLngCon.gtLconVal)
1794 if (op1->gtDblCon.gtDconVal == op2->gtDblCon.gtDconVal)
1805 /* Is this a leaf node? */
1807 if (kind & GTK_LEAF)
1812 if (op1->gtLclVarCommon.gtLclNum != op2->gtLclVarCommon.gtLclNum)
1820 if (op1->gtLclFld.gtLclNum != op2->gtLclFld.gtLclNum ||
1821 op1->gtLclFld.gtLclOffs != op2->gtLclFld.gtLclOffs)
1829 if (op1->gtClsVar.gtClsVarHnd != op2->gtClsVar.gtClsVarHnd)
1840 if ((op1->gtType == TYP_STRUCT) &&
1841 (op1->gtArgPlace.gtArgPlaceClsHnd != op2->gtArgPlace.gtArgPlaceClsHnd))
1854 /* Is it a 'simple' unary/binary operator? */
1856 if (kind & GTK_UNOP)
1860 // ExOp operators extend unary operator with extra, non-GenTreePtr members. In many cases,
1861 // these should be included in the comparison.
1865 if (op1->gtArrLen.ArrLenOffset() != op2->gtArrLen.ArrLenOffset())
1871 if (op1->gtCast.gtCastType != op2->gtCast.gtCastType)
1877 if (op1->AsObj()->gtClass != op2->AsObj()->gtClass)
1883 // For the ones below no extra argument matters for comparison.
1888 assert(!"unexpected unary ExOp operator");
1891 return Compare(op1->gtOp.gtOp1, op2->gtOp.gtOp1);
1894 if (kind & GTK_BINOP)
1898 // ExOp operators extend unary operator with extra, non-GenTreePtr members. In many cases,
1899 // these should be included in the hash code.
1903 if (op1->gtIntrinsic.gtIntrinsicId != op2->gtIntrinsic.gtIntrinsicId)
1909 if (op1->gtAddrMode.gtScale != op2->gtAddrMode.gtScale)
1913 if (op1->gtAddrMode.gtOffset != op2->gtAddrMode.gtOffset)
1919 if (op1->gtIndex.gtIndElemSize != op2->gtIndex.gtIndElemSize)
1925 // For the ones below no extra argument matters for comparison.
1930 assert(!"unexpected binary ExOp operator");
1934 if (op1->gtOp.gtOp2)
1936 if (!Compare(op1->gtOp.gtOp1, op2->gtOp.gtOp1, swapOK))
1938 if (swapOK && OperIsCommutative(oper) &&
1939 ((op1->gtOp.gtOp1->gtFlags | op1->gtOp.gtOp2->gtFlags | op2->gtOp.gtOp1->gtFlags |
1940 op2->gtOp.gtOp2->gtFlags) &
1941 GTF_ALL_EFFECT) == 0)
1943 if (Compare(op1->gtOp.gtOp1, op2->gtOp.gtOp2, swapOK))
1945 op1 = op1->gtOp.gtOp2;
1946 op2 = op2->gtOp.gtOp1;
1954 op1 = op1->gtOp.gtOp2;
1955 op2 = op2->gtOp.gtOp2;
1962 op1 = op1->gtOp.gtOp1;
1963 op2 = op2->gtOp.gtOp1;
1967 return (op2 == nullptr);
1978 /* See what kind of a special operator we have here */
1983 if (op1->gtField.gtFldHnd != op2->gtField.gtFldHnd)
1988 op1 = op1->gtField.gtFldObj;
1989 op2 = op2->gtField.gtFldObj;
2003 if (op1->gtCall.gtCallType != op2->gtCall.gtCallType)
2008 if (op1->gtCall.gtCallType != CT_INDIRECT)
2010 if (op1->gtCall.gtCallMethHnd != op2->gtCall.gtCallMethHnd)
2015 #ifdef FEATURE_READYTORUN_COMPILER
2016 if (op1->gtCall.gtEntryPoint.addr != op2->gtCall.gtEntryPoint.addr)
2022 if (!Compare(op1->gtCall.gtCallAddr, op2->gtCall.gtCallAddr))
2028 if (Compare(op1->gtCall.gtCallLateArgs, op2->gtCall.gtCallLateArgs) &&
2029 Compare(op1->gtCall.gtCallArgs, op2->gtCall.gtCallArgs) &&
2030 Compare(op1->gtCall.gtControlExpr, op2->gtCall.gtControlExpr) &&
2031 Compare(op1->gtCall.gtCallObjp, op2->gtCall.gtCallObjp))
2039 if (op1->gtArrElem.gtArrRank != op2->gtArrElem.gtArrRank)
2044 // NOTE: gtArrElemSize may need to be handled
2047 for (dim = 0; dim < op1->gtArrElem.gtArrRank; dim++)
2049 if (!Compare(op1->gtArrElem.gtArrInds[dim], op2->gtArrElem.gtArrInds[dim]))
2055 op1 = op1->gtArrElem.gtArrObj;
2056 op2 = op2->gtArrElem.gtArrObj;
2060 if (op1->gtArrOffs.gtCurrDim != op2->gtArrOffs.gtCurrDim ||
2061 op1->gtArrOffs.gtArrRank != op2->gtArrOffs.gtArrRank)
2065 return (Compare(op1->gtArrOffs.gtOffset, op2->gtArrOffs.gtOffset) &&
2066 Compare(op1->gtArrOffs.gtIndex, op2->gtArrOffs.gtIndex) &&
2067 Compare(op1->gtArrOffs.gtArrObj, op2->gtArrOffs.gtArrObj));
2070 return Compare(op1->gtCmpXchg.gtOpLocation, op2->gtCmpXchg.gtOpLocation) &&
2071 Compare(op1->gtCmpXchg.gtOpValue, op2->gtCmpXchg.gtOpValue) &&
2072 Compare(op1->gtCmpXchg.gtOpComparand, op2->gtCmpXchg.gtOpComparand);
2074 case GT_ARR_BOUNDS_CHECK:
2077 #endif // FEATURE_SIMD
2078 return Compare(op1->gtBoundsChk.gtArrLen, op2->gtBoundsChk.gtArrLen) &&
2079 Compare(op1->gtBoundsChk.gtIndex, op2->gtBoundsChk.gtIndex) &&
2080 (op1->gtBoundsChk.gtThrowKind == op2->gtBoundsChk.gtThrowKind);
2083 assert(!"unexpected operator");
2089 /*****************************************************************************
2091 * Returns non-zero if the given tree contains a use of a local #lclNum.
2094 bool Compiler::gtHasRef(GenTreePtr tree, ssize_t lclNum, bool defOnly)
2103 oper = tree->OperGet();
2104 kind = tree->OperKind();
2106 assert(oper != GT_STMT);
2108 /* Is this a constant node? */
2110 if (kind & GTK_CONST)
2115 /* Is this a leaf node? */
2117 if (kind & GTK_LEAF)
2119 if (oper == GT_LCL_VAR)
2121 if (tree->gtLclVarCommon.gtLclNum == (unsigned)lclNum)
2129 else if (oper == GT_RET_EXPR)
2131 return gtHasRef(tree->gtRetExpr.gtInlineCandidate, lclNum, defOnly);
2137 /* Is it a 'simple' unary/binary operator? */
2139 if (kind & GTK_SMPOP)
2141 if (tree->gtGetOp2())
2143 if (gtHasRef(tree->gtOp.gtOp1, lclNum, defOnly))
2148 tree = tree->gtOp.gtOp2;
2153 tree = tree->gtOp.gtOp1;
2160 if (kind & GTK_ASGOP)
2162 // 'tree' is the gtOp1 of an assignment node. So we can handle
2163 // the case where defOnly is either true or false.
2165 if (tree->gtOper == GT_LCL_VAR && tree->gtLclVarCommon.gtLclNum == (unsigned)lclNum)
2169 else if (tree->gtOper == GT_FIELD && lclNum == (ssize_t)tree->gtField.gtFldHnd)
2179 /* See what kind of a special operator we have here */
2184 if (lclNum == (ssize_t)tree->gtField.gtFldHnd)
2192 tree = tree->gtField.gtFldObj;
2201 if (tree->gtCall.gtCallObjp)
2203 if (gtHasRef(tree->gtCall.gtCallObjp, lclNum, defOnly))
2209 if (tree->gtCall.gtCallArgs)
2211 if (gtHasRef(tree->gtCall.gtCallArgs, lclNum, defOnly))
2217 if (tree->gtCall.gtCallLateArgs)
2219 if (gtHasRef(tree->gtCall.gtCallLateArgs, lclNum, defOnly))
2225 if (tree->gtCall.gtCallLateArgs)
2227 if (gtHasRef(tree->gtCall.gtControlExpr, lclNum, defOnly))
2233 if (tree->gtCall.gtCallType == CT_INDIRECT)
2235 // pinvoke-calli cookie is a constant, or constant indirection
2236 assert(tree->gtCall.gtCallCookie == nullptr || tree->gtCall.gtCallCookie->gtOper == GT_CNS_INT ||
2237 tree->gtCall.gtCallCookie->gtOper == GT_IND);
2239 tree = tree->gtCall.gtCallAddr;
2254 if (gtHasRef(tree->gtArrElem.gtArrObj, lclNum, defOnly))
2260 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
2262 if (gtHasRef(tree->gtArrElem.gtArrInds[dim], lclNum, defOnly))
2271 if (gtHasRef(tree->gtArrOffs.gtOffset, lclNum, defOnly) ||
2272 gtHasRef(tree->gtArrOffs.gtIndex, lclNum, defOnly) ||
2273 gtHasRef(tree->gtArrOffs.gtArrObj, lclNum, defOnly))
2280 if (gtHasRef(tree->gtCmpXchg.gtOpLocation, lclNum, defOnly))
2284 if (gtHasRef(tree->gtCmpXchg.gtOpValue, lclNum, defOnly))
2288 if (gtHasRef(tree->gtCmpXchg.gtOpComparand, lclNum, defOnly))
2294 case GT_ARR_BOUNDS_CHECK:
2297 #endif // FEATURE_SIMD
2298 if (gtHasRef(tree->gtBoundsChk.gtArrLen, lclNum, defOnly))
2302 if (gtHasRef(tree->gtBoundsChk.gtIndex, lclNum, defOnly))
2312 assert(!"unexpected operator");
2321 bool hasAddrTakenLcl;
2325 Compiler::fgWalkResult Compiler::gtHasLocalsWithAddrOpCB(GenTreePtr* pTree, fgWalkData* data)
2327 GenTreePtr tree = *pTree;
2328 Compiler* comp = data->compiler;
2330 if (tree->gtOper == GT_LCL_VAR)
2332 unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
2333 LclVarDsc* varDsc = &comp->lvaTable[lclNum];
2335 if (varDsc->lvHasLdAddrOp || varDsc->lvAddrExposed)
2337 ((AddrTakenDsc*)data->pCallbackData)->hasAddrTakenLcl = true;
2342 return WALK_CONTINUE;
2345 /*****************************************************************************
2347 * Return true if this tree contains locals with lvHasLdAddrOp or lvAddrExposed
2351 bool Compiler::gtHasLocalsWithAddrOp(GenTreePtr tree)
2356 desc.hasAddrTakenLcl = false;
2358 fgWalkTreePre(&tree, gtHasLocalsWithAddrOpCB, &desc);
2360 return desc.hasAddrTakenLcl;
2363 /*****************************************************************************
2365 * Helper used to compute hash values for trees.
2368 inline unsigned genTreeHashAdd(unsigned old, unsigned add)
2370 return (old + old / 2) ^ add;
2373 inline unsigned genTreeHashAdd(unsigned old, void* add)
2375 return genTreeHashAdd(old, (unsigned)(size_t)add);
2378 inline unsigned genTreeHashAdd(unsigned old, unsigned add1, unsigned add2)
2380 return (old + old / 2) ^ add1 ^ add2;
2383 /*****************************************************************************
2385 * Given an arbitrary expression tree, compute a hash value for it.
2388 unsigned Compiler::gtHashValue(GenTree* tree)
2399 assert(tree->gtOper != GT_STMT);
2401 /* Figure out what kind of a node we have */
2403 oper = tree->OperGet();
2404 kind = tree->OperKind();
2406 /* Include the operator value in the hash */
2408 hash = genTreeHashAdd(hash, oper);
2410 /* Is this a constant or leaf node? */
2412 if (kind & (GTK_CONST | GTK_LEAF))
2419 add = tree->gtLclVar.gtLclNum;
2422 hash = genTreeHashAdd(hash, tree->gtLclFld.gtLclNum);
2423 add = tree->gtLclFld.gtLclOffs;
2427 add = (int)tree->gtIntCon.gtIconVal;
2430 add = (int)tree->gtLngCon.gtLconVal;
2433 add = (int)tree->gtDblCon.gtDconVal;
2436 add = (int)tree->gtStrCon.gtSconCPX;
2440 add = tree->gtVal.gtVal1;
2448 // narrowing cast, but for hashing.
2449 hash = genTreeHashAdd(hash, (unsigned)add);
2453 /* Is it a 'simple' unary/binary operator? */
2457 if (kind & GTK_UNOP)
2459 op1 = tree->gtOp.gtOp1;
2460 /* Special case: no sub-operand at all */
2462 if (GenTree::IsExOp(kind))
2464 // ExOp operators extend operators with extra, non-GenTreePtr members. In many cases,
2465 // these should be included in the hash code.
2469 hash += tree->gtArrLen.ArrLenOffset();
2472 hash ^= tree->gtCast.gtCastType;
2475 hash ^= static_cast<unsigned>(reinterpret_cast<uintptr_t>(tree->gtObj.gtClass));
2478 hash += tree->gtIndex.gtIndElemSize;
2481 hash = genTreeHashAdd(hash, static_cast<unsigned>(
2482 reinterpret_cast<uintptr_t>(tree->gtAllocObj.gtAllocObjClsHnd)));
2483 hash = genTreeHashAdd(hash, tree->gtAllocObj.gtNewHelper);
2486 // For the ones below no extra argument matters for comparison.
2491 assert(!"unexpected unary ExOp operator");
2504 if (kind & GTK_BINOP)
2506 if (GenTree::IsExOp(kind))
2508 // ExOp operators extend operators with extra, non-GenTreePtr members. In many cases,
2509 // these should be included in the hash code.
2513 hash += tree->gtIntrinsic.gtIntrinsicId;
2516 hash += (tree->gtAddrMode.gtOffset << 3) + tree->gtAddrMode.gtScale;
2519 // For the ones below no extra argument matters for comparison.
2527 hash += tree->gtSIMD.gtSIMDIntrinsicID;
2528 hash += tree->gtSIMD.gtSIMDBaseType;
2530 #endif // FEATURE_SIMD
2533 assert(!"unexpected binary ExOp operator");
2537 op1 = tree->gtOp.gtOp1;
2538 GenTreePtr op2 = tree->gtOp.gtOp2;
2540 /* Is there a second sub-operand? */
2544 /* Special case: no sub-operands at all */
2551 /* This is a unary operator */
2557 /* This is a binary operator */
2559 unsigned hsh1 = gtHashValue(op1);
2561 /* Special case: addition of two values */
2563 if (GenTree::OperIsCommutative(oper))
2565 unsigned hsh2 = gtHashValue(op2);
2567 /* Produce a hash that allows swapping the operands */
2569 hash = genTreeHashAdd(hash, hsh1, hsh2);
2573 /* Add op1's hash to the running value and continue with op2 */
2575 hash = genTreeHashAdd(hash, hsh1);
2581 /* See what kind of a special operator we have here */
2582 switch (tree->gtOper)
2585 if (tree->gtField.gtFldObj)
2587 temp = tree->gtField.gtFldObj;
2589 hash = genTreeHashAdd(hash, gtHashValue(temp));
2594 temp = tree->gtStmt.gtStmtExpr;
2596 hash = genTreeHashAdd(hash, gtHashValue(temp));
2601 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrElem.gtArrObj));
2604 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
2606 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrElem.gtArrInds[dim]));
2612 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrOffs.gtOffset));
2613 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrOffs.gtIndex));
2614 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrOffs.gtArrObj));
2619 if (tree->gtCall.gtCallObjp && tree->gtCall.gtCallObjp->gtOper != GT_NOP)
2621 temp = tree->gtCall.gtCallObjp;
2623 hash = genTreeHashAdd(hash, gtHashValue(temp));
2626 if (tree->gtCall.gtCallArgs)
2628 temp = tree->gtCall.gtCallArgs;
2630 hash = genTreeHashAdd(hash, gtHashValue(temp));
2633 if (tree->gtCall.gtCallType == CT_INDIRECT)
2635 temp = tree->gtCall.gtCallAddr;
2637 hash = genTreeHashAdd(hash, gtHashValue(temp));
2641 hash = genTreeHashAdd(hash, tree->gtCall.gtCallMethHnd);
2644 if (tree->gtCall.gtCallLateArgs)
2646 temp = tree->gtCall.gtCallLateArgs;
2648 hash = genTreeHashAdd(hash, gtHashValue(temp));
2653 hash = genTreeHashAdd(hash, gtHashValue(tree->gtCmpXchg.gtOpLocation));
2654 hash = genTreeHashAdd(hash, gtHashValue(tree->gtCmpXchg.gtOpValue));
2655 hash = genTreeHashAdd(hash, gtHashValue(tree->gtCmpXchg.gtOpComparand));
2658 case GT_ARR_BOUNDS_CHECK:
2661 #endif // FEATURE_SIMD
2662 hash = genTreeHashAdd(hash, gtHashValue(tree->gtBoundsChk.gtArrLen));
2663 hash = genTreeHashAdd(hash, gtHashValue(tree->gtBoundsChk.gtIndex));
2664 hash = genTreeHashAdd(hash, tree->gtBoundsChk.gtThrowKind);
2671 assert(!"unexpected operator");
2680 /*****************************************************************************
2682 * Given an arbitrary expression tree, attempts to find the set of all local variables
2683 * referenced by the tree, and return them as "*result".
2684 * If "findPtr" is null, this is a tracked variable set;
2685 * if it is non-null, this is an "all var set."
2686 * The "*result" value is valid only if the call returns "true." It may return "false"
2687 * for several reasons:
2688 * If "findPtr" is NULL, and the expression contains an untracked variable.
2689 * If "findPtr" is non-NULL, and the expression contains a variable that can't be represented
2690 * in an "all var set."
2691 * If the expression accesses address-exposed variables.
2694 * are any indirections or global refs in the expression, the "*refsPtr" argument
2695 * will be assigned the appropriate bit set based on the 'varRefKinds' type.
2696 * It won't be assigned anything when there are no indirections or global
2697 * references, though, so this value should be initialized before the call.
2698 * If we encounter an expression that is equal to *findPtr we set *findPtr
2701 bool Compiler::lvaLclVarRefs(GenTreePtr tree, GenTreePtr* findPtr, varRefKinds* refsPtr, void* result)
2705 varRefKinds refs = VR_NONE;
2706 ALLVARSET_TP ALLVARSET_INIT_NOCOPY(allVars, AllVarSetOps::UninitVal());
2707 VARSET_TP VARSET_INIT_NOCOPY(trkdVars, VarSetOps::UninitVal());
2710 AllVarSetOps::AssignNoCopy(this, allVars, AllVarSetOps::MakeEmpty(this));
2714 VarSetOps::AssignNoCopy(this, trkdVars, VarSetOps::MakeEmpty(this));
2720 assert(tree->gtOper != GT_STMT);
2722 /* Remember whether we've come across the expression we're looking for */
2724 if (findPtr && *findPtr == tree)
2729 /* Figure out what kind of a node we have */
2731 oper = tree->OperGet();
2732 kind = tree->OperKind();
2734 /* Is this a constant or leaf node? */
2736 if (kind & (GTK_CONST | GTK_LEAF))
2738 if (oper == GT_LCL_VAR)
2740 unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
2742 /* Should we use the variable table? */
2746 if (lclNum >= lclMAX_ALLSET_TRACKED)
2751 AllVarSetOps::AddElemD(this, allVars, lclNum);
2755 assert(lclNum < lvaCount);
2756 LclVarDsc* varDsc = lvaTable + lclNum;
2758 if (varDsc->lvTracked == false)
2763 // Don't deal with expressions with address-exposed variables.
2764 if (varDsc->lvAddrExposed)
2769 VarSetOps::AddElemD(this, trkdVars, varDsc->lvVarIndex);
2772 else if (oper == GT_LCL_FLD)
2774 /* We can't track every field of every var. Moreover, indirections
2775 may access different parts of the var as different (but
2776 overlapping) fields. So just treat them as indirect accesses */
2778 if (varTypeIsGC(tree->TypeGet()))
2787 else if (oper == GT_CLS_VAR)
2792 if (refs != VR_NONE)
2794 /* Write it back to callers parameter using an 'or' */
2795 *refsPtr = varRefKinds((*refsPtr) | refs);
2797 lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
2801 /* Is it a 'simple' unary/binary operator? */
2803 if (kind & GTK_SMPOP)
2807 assert(tree->gtOp.gtOp2 == nullptr);
2809 /* Set the proper indirection bit */
2811 if ((tree->gtFlags & GTF_IND_INVARIANT) == 0)
2813 if (varTypeIsGC(tree->TypeGet()))
2822 // If the flag GTF_IND_TGTANYWHERE is set this indirection
2823 // could also point at a global variable
2825 if (tree->gtFlags & GTF_IND_TGTANYWHERE)
2827 refs = varRefKinds(((int)refs) | ((int)VR_GLB_VAR));
2831 /* Write it back to callers parameter using an 'or' */
2832 *refsPtr = varRefKinds((*refsPtr) | refs);
2834 // For IL volatile memory accesses we mark the GT_IND node
2835 // with a GTF_DONT_CSE flag.
2837 // This flag is also set for the left hand side of an assignment.
2839 // If this flag is set then we return false
2841 if (tree->gtFlags & GTF_DONT_CSE)
2847 if (tree->gtGetOp2())
2849 /* It's a binary operator */
2850 if (!lvaLclVarRefsAccum(tree->gtOp.gtOp1, findPtr, refsPtr, &allVars, &trkdVars))
2855 tree = tree->gtOp.gtOp2;
2861 /* It's a unary (or nilary) operator */
2863 tree = tree->gtOp.gtOp1;
2869 lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
2877 if (!lvaLclVarRefsAccum(tree->gtArrElem.gtArrObj, findPtr, refsPtr, &allVars, &trkdVars))
2883 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
2885 VARSET_TP VARSET_INIT_NOCOPY(tmpVs, VarSetOps::UninitVal());
2886 if (!lvaLclVarRefsAccum(tree->gtArrElem.gtArrInds[dim], findPtr, refsPtr, &allVars, &trkdVars))
2891 lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
2895 if (!lvaLclVarRefsAccum(tree->gtArrOffs.gtOffset, findPtr, refsPtr, &allVars, &trkdVars))
2900 if (!lvaLclVarRefsAccum(tree->gtArrOffs.gtIndex, findPtr, refsPtr, &allVars, &trkdVars))
2905 if (!lvaLclVarRefsAccum(tree->gtArrOffs.gtArrObj, findPtr, refsPtr, &allVars, &trkdVars))
2910 lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
2913 case GT_ARR_BOUNDS_CHECK:
2916 #endif // FEATURE_SIMD
2918 if (!lvaLclVarRefsAccum(tree->gtBoundsChk.gtArrLen, findPtr, refsPtr, &allVars, &trkdVars))
2923 if (!lvaLclVarRefsAccum(tree->gtBoundsChk.gtIndex, findPtr, refsPtr, &allVars, &trkdVars))
2928 lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
2933 /* Allow calls to the Shared Static helper */
2934 if (IsSharedStaticHelper(tree))
2936 *refsPtr = varRefKinds((*refsPtr) | VR_INVARIANT);
2937 lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
2944 } // end switch (oper)
2949 bool Compiler::lvaLclVarRefsAccum(
2950 GenTreePtr tree, GenTreePtr* findPtr, varRefKinds* refsPtr, ALLVARSET_TP* allVars, VARSET_TP* trkdVars)
2954 ALLVARSET_TP ALLVARSET_INIT_NOCOPY(tmpVs, AllVarSetOps::UninitVal());
2955 if (!lvaLclVarRefs(tree, findPtr, refsPtr, &tmpVs))
2960 AllVarSetOps::UnionD(this, *allVars, tmpVs);
2964 VARSET_TP VARSET_INIT_NOCOPY(tmpVs, VarSetOps::UninitVal());
2965 if (!lvaLclVarRefs(tree, findPtr, refsPtr, &tmpVs))
2970 VarSetOps::UnionD(this, *trkdVars, tmpVs);
2975 void Compiler::lvaLclVarRefsAccumIntoRes(GenTreePtr* findPtr,
2977 ALLVARSET_VALARG_TP allVars,
2978 VARSET_VALARG_TP trkdVars)
2982 ALLVARSET_TP* avsPtr = (ALLVARSET_TP*)result;
2983 AllVarSetOps::AssignNoCopy(this, (*avsPtr), allVars);
2987 VARSET_TP* vsPtr = (VARSET_TP*)result;
2988 VarSetOps::AssignNoCopy(this, (*vsPtr), trkdVars);
2992 /*****************************************************************************
2994 * Return a relational operator that is the reverse of the given one.
2998 genTreeOps GenTree::ReverseRelop(genTreeOps relop)
3000 static const genTreeOps reverseOps[] = {
3009 assert(reverseOps[GT_EQ - GT_EQ] == GT_NE);
3010 assert(reverseOps[GT_NE - GT_EQ] == GT_EQ);
3012 assert(reverseOps[GT_LT - GT_EQ] == GT_GE);
3013 assert(reverseOps[GT_LE - GT_EQ] == GT_GT);
3014 assert(reverseOps[GT_GE - GT_EQ] == GT_LT);
3015 assert(reverseOps[GT_GT - GT_EQ] == GT_LE);
3017 assert(OperIsCompare(relop));
3018 assert(relop >= GT_EQ && (unsigned)(relop - GT_EQ) < sizeof(reverseOps));
3020 return reverseOps[relop - GT_EQ];
3023 /*****************************************************************************
3025 * Return a relational operator that will work for swapped operands.
3029 genTreeOps GenTree::SwapRelop(genTreeOps relop)
3031 static const genTreeOps swapOps[] = {
3040 assert(swapOps[GT_EQ - GT_EQ] == GT_EQ);
3041 assert(swapOps[GT_NE - GT_EQ] == GT_NE);
3043 assert(swapOps[GT_LT - GT_EQ] == GT_GT);
3044 assert(swapOps[GT_LE - GT_EQ] == GT_GE);
3045 assert(swapOps[GT_GE - GT_EQ] == GT_LE);
3046 assert(swapOps[GT_GT - GT_EQ] == GT_LT);
3048 assert(OperIsCompare(relop));
3049 assert(relop >= GT_EQ && (unsigned)(relop - GT_EQ) < sizeof(swapOps));
3051 return swapOps[relop - GT_EQ];
3054 /*****************************************************************************
3056 * Reverse the meaning of the given test condition.
3059 GenTreePtr Compiler::gtReverseCond(GenTree* tree)
3061 if (tree->OperIsCompare())
3063 tree->SetOper(GenTree::ReverseRelop(tree->OperGet()));
3065 // Flip the GTF_RELOP_NAN_UN bit
3066 // a ord b === (a != NaN && b != NaN)
3067 // a unord b === (a == NaN || b == NaN)
3068 // => !(a ord b) === (a unord b)
3069 if (varTypeIsFloating(tree->gtOp.gtOp1->TypeGet()))
3071 tree->gtFlags ^= GTF_RELOP_NAN_UN;
3076 tree = gtNewOperNode(GT_NOT, TYP_INT, tree);
3082 /*****************************************************************************/
3086 bool GenTree::gtIsValid64RsltMul()
3088 if ((gtOper != GT_MUL) || !(gtFlags & GTF_MUL_64RSLT))
3093 GenTreePtr op1 = gtOp.gtOp1;
3094 GenTreePtr op2 = gtOp.gtOp2;
3096 if (TypeGet() != TYP_LONG || op1->TypeGet() != TYP_LONG || op2->TypeGet() != TYP_LONG)
3106 // op1 has to be conv.i8(i4Expr)
3107 if ((op1->gtOper != GT_CAST) || (genActualType(op1->CastFromType()) != TYP_INT))
3112 // op2 has to be conv.i8(i4Expr)
3113 if ((op2->gtOper != GT_CAST) || (genActualType(op2->CastFromType()) != TYP_INT))
3118 // The signedness of both casts must be the same
3119 if (((op1->gtFlags & GTF_UNSIGNED) != 0) != ((op2->gtFlags & GTF_UNSIGNED) != 0))
3124 // Do unsigned mul iff both the casts are unsigned
3125 if (((op1->gtFlags & GTF_UNSIGNED) != 0) != ((gtFlags & GTF_UNSIGNED) != 0))
3135 //------------------------------------------------------------------------------
3136 // gtSetListOrder : Figure out the evaluation order for a list of values.
3140 // list - List to figure out the evaluation order for
3141 // isListCallArgs - True iff the list is a list of call arguments
3142 // callArgsInRegs - True iff the list is a list of call arguments and they are passed in registers
3145 // True if the operation can be a root of a bitwise rotation tree; false otherwise.
3147 unsigned Compiler::gtSetListOrder(GenTree *list, bool isListCallArgs, bool callArgsInRegs)
3149 assert((list != nullptr) && list->IsList());
3150 assert(!callArgsInRegs || isListCallArgs);
3152 ArrayStack<GenTree *> listNodes(this);
3156 listNodes.Push(list);
3157 list = list->gtOp.gtOp2;
3158 } while ((list != nullptr) && (list->IsList()));
3160 unsigned nxtlvl = (list == nullptr) ? 0 : gtSetEvalOrder(list);
3161 while (listNodes.Height() > 0)
3163 #if FEATURE_STACK_FP_X87
3164 /* Save the current FP stack level since an argument list
3165 * will implicitly pop the FP stack when pushing the argument */
3166 unsigned FPlvlSave = codeGen->genGetFPstkLevel();
3167 #endif // FEATURE_STACK_FP_X87
3169 list = listNodes.Pop();
3170 assert(list && list->IsList());
3171 GenTreePtr next = list->gtOp.gtOp2;
3176 // TODO: Do we have to compute costs differently for argument lists and
3178 // https://github.com/dotnet/coreclr/issues/7095
3179 unsigned costSz = (isListCallArgs || (next == nullptr)) ? 0 : 1;
3180 unsigned costEx = (isListCallArgs || (next == nullptr)) ? 0 : 1;
3182 if (next != nullptr)
3184 ftreg |= next->gtRsvdRegs;
3192 costEx += next->gtCostEx;
3193 costSz += next->gtCostSz;
3196 GenTreePtr op1 = list->gtOp.gtOp1;
3197 unsigned lvl = gtSetEvalOrder(op1);
3199 #if FEATURE_STACK_FP_X87
3200 // restore the FP level
3201 codeGen->genResetFPstkLevel(FPlvlSave);
3202 #endif // FEATURE_STACK_FP_X87
3204 list->gtRsvdRegs = (regMaskSmall)(ftreg | op1->gtRsvdRegs);
3206 // Swap the level counts
3207 if (list->gtFlags & GTF_REVERSE_OPS)
3216 // TODO: Do we have to compute levels differently for argument lists and
3218 // https://github.com/dotnet/coreclr/issues/7095
3232 else if (lvl == nxtlvl)
3242 if (op1->gtCostEx != 0)
3244 costEx += op1->gtCostEx;
3245 costEx += (callArgsInRegs || !isListCallArgs) ? 0 : IND_COST_EX;
3248 if (op1->gtCostSz != 0)
3250 costSz += op1->gtCostSz;
3251 #ifdef _TARGET_XARCH_
3252 if (callArgsInRegs) // push is smaller than mov to reg
3259 list->SetCosts(costEx, costSz);
3267 /*****************************************************************************
3269 * This routine is a helper routine for gtSetEvalOrder() and is used to
3270 * mark the interior address computation nodes with the GTF_ADDRMODE_NO_CSE flag
3271 * which prevents them from being considered for CSE's.
3273 * Furthermore this routine is a factoring of the logic used to walk down
3274 * the child nodes of a GT_IND tree, similar to optParseArrayRef().
3276 * Previously we had this logic repeated three times inside of gtSetEvalOrder().
3277 * Here we combine those three repeats into this routine and use the
3278 * bool constOnly to modify the behavior of this routine for the first call.
3280 * The object here is to mark all of the interior GT_ADD's and GT_NOP's
3281 * with the GTF_ADDRMODE_NO_CSE flag and to set op1 and op2 to the terminal nodes
3282 * which are later matched against 'adr' and 'idx'.
3284 * *pbHasRangeCheckBelow is set to false if we traverse a range check GT_NOP
3285 * node in our walk. It remains unchanged otherwise.
3287 * TODO-Cleanup: It is essentially impossible to determine
3288 * what it is supposed to do, or to write a reasonable specification comment
3289 * for it that describes what it is supposed to do. There are obviously some
3290 * very specific tree patterns that it expects to see, but those are not documented.
3291 * The fact that it writes back to its op1WB and op2WB arguments, and traverses
3292 * down both op1 and op2 trees, but op2 is only related to op1 in the (!constOnly)
3293 * case (which really seems like a bug) is very confusing.
3296 void Compiler::gtWalkOp(GenTree** op1WB, GenTree** op2WB, GenTree* adr, bool constOnly)
3298 GenTreePtr op1 = *op1WB;
3299 GenTreePtr op2 = *op2WB;
3300 GenTreePtr op1EffectiveVal;
3302 if (op1->gtOper == GT_COMMA)
3304 op1EffectiveVal = op1->gtEffectiveVal();
3305 if ((op1EffectiveVal->gtOper == GT_ADD) && (!op1EffectiveVal->gtOverflow()) &&
3306 (!constOnly || (op1EffectiveVal->gtOp.gtOp2->IsCnsIntOrI())))
3308 op1 = op1EffectiveVal;
3312 // Now we look for op1's with non-overflow GT_ADDs [of constants]
3313 while ((op1->gtOper == GT_ADD) && (!op1->gtOverflow()) && (!constOnly || (op1->gtOp.gtOp2->IsCnsIntOrI())))
3315 // mark it with GTF_ADDRMODE_NO_CSE
3316 op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3319 { // TODO-Cleanup: It seems bizarre that this is !constOnly
3320 op2 = op1->gtOp.gtOp2;
3322 op1 = op1->gtOp.gtOp1;
3324 // If op1 is a GT_NOP then swap op1 and op2.
3325 // (Why? Also, presumably op2 is not a GT_NOP in this case?)
3326 if (op1->gtOper == GT_NOP)
3335 if (op1->gtOper == GT_COMMA)
3337 op1EffectiveVal = op1->gtEffectiveVal();
3338 if ((op1EffectiveVal->gtOper == GT_ADD) && (!op1EffectiveVal->gtOverflow()) &&
3339 (!constOnly || (op1EffectiveVal->gtOp.gtOp2->IsCnsIntOrI())))
3341 op1 = op1EffectiveVal;
3345 if (!constOnly && ((op2 == adr) || (!op2->IsCnsIntOrI())))
3356 /*****************************************************************************
3357 * This is a workaround. It is to help implement an assert in gtSetEvalOrder() that the values
3358 * gtWalkOp() leaves in op1 and op2 correspond with the values of adr, idx, mul, and cns
3359 * that are returned by genCreateAddrMode(). It's essentially impossible to determine
3360 * what gtWalkOp() *should* return for all possible trees. This simply loosens one assert
3361 * to handle the following case:
3364 const(h) int 4 field
3366 lclVar byref V00 this <-- op2
3367 comma byref <-- adr (base)
3369 lclVar byref V00 this
3371 const int 2 <-- mul == 4
3373 lclVar int V01 arg1 <-- idx
3375 * Here, we are planning to generate the address mode [edx+4*eax], where eax = idx and edx = the GT_COMMA expression.
3376 * To check adr equivalence with op2, we need to walk down the GT_ADD tree just like gtWalkOp() does.
3378 GenTreePtr Compiler::gtWalkOpEffectiveVal(GenTreePtr op)
3382 if (op->gtOper == GT_COMMA)
3384 GenTreePtr opEffectiveVal = op->gtEffectiveVal();
3385 if ((opEffectiveVal->gtOper == GT_ADD) && (!opEffectiveVal->gtOverflow()) &&
3386 (opEffectiveVal->gtOp.gtOp2->IsCnsIntOrI()))
3388 op = opEffectiveVal;
3392 if ((op->gtOper != GT_ADD) || op->gtOverflow() || !op->gtOp.gtOp2->IsCnsIntOrI())
3397 op = op->gtOp.gtOp1;
3404 /*****************************************************************************
3406 * Given a tree, set the gtCostEx and gtCostSz fields which
3407 * are used to measure the relative costs of the codegen of the tree
3411 void Compiler::gtPrepareCost(GenTree* tree)
3413 #if FEATURE_STACK_FP_X87
3414 codeGen->genResetFPstkLevel();
3415 #endif // FEATURE_STACK_FP_X87
3416 gtSetEvalOrder(tree);
3419 bool Compiler::gtIsLikelyRegVar(GenTree* tree)
3421 if (tree->gtOper != GT_LCL_VAR)
3426 assert(tree->gtLclVar.gtLclNum < lvaTableCnt);
3427 LclVarDsc* varDsc = lvaTable + tree->gtLclVar.gtLclNum;
3429 if (varDsc->lvDoNotEnregister)
3434 if (varDsc->lvRefCntWtd < (BB_UNITY_WEIGHT * 3))
3440 if (varTypeIsFloating(tree->TypeGet()))
3442 if (varTypeIsLong(tree->TypeGet()))
3449 //------------------------------------------------------------------------
3450 // gtCanSwapOrder: Returns true iff the secondNode can be swapped with firstNode.
3453 // firstNode - An operand of a tree that can have GTF_REVERSE_OPS set.
3454 // secondNode - The other operand of the tree.
3457 // Returns a boolean indicating whether it is safe to reverse the execution
3458 // order of the two trees, considering any exception, global effects, or
3459 // ordering constraints.
3461 bool Compiler::gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode)
3463 // Relative of order of global / side effects can't be swapped.
3465 bool canSwap = true;
3467 if (optValnumCSE_phase)
3469 canSwap = optCSE_canSwap(firstNode, secondNode);
3472 // We cannot swap in the presence of special side effects such as GT_CATCH_ARG.
3474 if (canSwap && (firstNode->gtFlags & GTF_ORDER_SIDEEFF))
3479 // When strict side effect order is disabled we allow GTF_REVERSE_OPS to be set
3480 // when one or both sides contains a GTF_CALL or GTF_EXCEPT.
3481 // Currently only the C and C++ languages allow non strict side effect order.
3483 unsigned strictEffects = GTF_GLOB_EFFECT;
3485 if (canSwap && (firstNode->gtFlags & strictEffects))
3487 // op1 has side efects that can't be reordered.
3488 // Check for some special cases where we still may be able to swap.
3490 if (secondNode->gtFlags & strictEffects)
3492 // op2 has also has non reorderable side effects - can't swap.
3497 // No side effects in op2 - we can swap iff op1 has no way of modifying op2,
3498 // i.e. through byref assignments or calls or op2 is a constant.
3500 if (firstNode->gtFlags & strictEffects & GTF_PERSISTENT_SIDE_EFFECTS)
3502 // We have to be conservative - can swap iff op2 is constant.
3503 if (!secondNode->OperIsConst())
3513 /*****************************************************************************
3515 * Given a tree, figure out the order in which its sub-operands should be
3516 * evaluated. If the second operand of a binary operator is more expensive
3517 * than the first operand, then try to swap the operand trees. Updates the
3518 * GTF_REVERSE_OPS bit if necessary in this case.
3520 * Returns the Sethi 'complexity' estimate for this tree (the higher
3521 * the number, the higher is the tree's resources requirement).
3523 * This function sets:
3524 * 1. gtCostEx to the execution complexity estimate
3525 * 2. gtCostSz to the code size estimate
3526 * 3. gtRsvdRegs to the set of fixed registers trashed by the tree
3527 * 4. gtFPlvl to the "floating point depth" value for node, i.e. the max. number
3528 * of operands the tree will push on the x87 (coprocessor) stack. Also sets
3529 * genFPstkLevel, tmpDoubleSpillMax, and possibly gtFPstLvlRedo.
3530 * 5. Sometimes sets GTF_ADDRMODE_NO_CSE on nodes in the tree.
3531 * 6. DEBUG-only: clears GTF_DEBUG_NODE_MORPHED.
3535 #pragma warning(push)
3536 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
3538 unsigned Compiler::gtSetEvalOrder(GenTree* tree)
3541 assert(tree->gtOper != GT_STMT);
3544 /* Clear the GTF_DEBUG_NODE_MORPHED flag as well */
3545 tree->gtDebugFlags &= ~GTF_DEBUG_NODE_MORPHED;
3548 /* Is this a FP value? */
3550 bool isflt = varTypeIsFloating(tree->TypeGet());
3553 /* Figure out what kind of a node we have */
3555 genTreeOps oper = tree->OperGet();
3556 unsigned kind = tree->OperKind();
3558 /* Assume no fixed registers will be trashed */
3560 regMaskTP ftreg = RBM_NONE; // Set of registers that will be used by the subtree
3572 /* Is this a constant or a leaf node? */
3574 if (kind & (GTK_LEAF | GTK_CONST))
3578 bool iconNeedsReloc;
3594 // If the constant is a handle then it will need to have a relocation
3596 // Any constant that requires a reloc must use the movw/movt sequence
3598 iconNeedsReloc = opts.compReloc && tree->IsIconHandle() && !tree->IsIconHandle(GTF_ICON_FIELD_HDL);
3600 if (iconNeedsReloc || !codeGen->validImmForInstr(INS_mov, tree->gtIntCon.gtIconVal))
3606 else if (((unsigned)tree->gtIntCon.gtIconVal) <= 0x00ff)
3620 #elif defined _TARGET_XARCH_
3634 // If the constant is a handle then it will need to have a relocation
3636 // Any constant that requires a reloc must use the movw/movt sequence
3638 iconNeedsReloc = opts.compReloc && tree->IsIconHandle() && !tree->IsIconHandle(GTF_ICON_FIELD_HDL);
3640 if (!iconNeedsReloc && (((signed char)tree->gtIntCon.gtIconVal) == tree->gtIntCon.gtIconVal))
3645 #if defined(_TARGET_AMD64_)
3646 else if (iconNeedsReloc || ((tree->gtIntCon.gtIconVal & 0xFFFFFFFF00000000LL) != 0))
3651 #endif // _TARGET_AMD64_
3659 #elif defined(_TARGET_ARM64_)
3663 // TODO-ARM64-NYI: Need cost estimates.
3672 #error "Unknown _TARGET_"
3677 Note that some code below depends on constants always getting
3678 moved to be the second operand of a binary operator. This is
3679 easily accomplished by giving constants a level of 0, which
3680 we do on the next line. If you ever decide to change this, be
3681 aware that unless you make other arrangements for integer
3682 constants to be moved, stuff will break.
3690 /* We use fldz and fld1 to load 0.0 and 1.0, but all other */
3691 /* floating point constants are loaded using an indirection */
3692 if ((*((__int64*)&(tree->gtDblCon.gtDconVal)) == 0) ||
3693 (*((__int64*)&(tree->gtDblCon.gtDconVal)) == I64(0x3ff0000000000000)))
3700 costEx = IND_COST_EX;
3707 if (gtIsLikelyRegVar(tree))
3711 /* Sign-extend and zero-extend are more expensive to load */
3712 if (lvaTable[tree->gtLclVar.gtLclNum].lvNormalizeOnLoad())
3720 costEx = IND_COST_EX;
3722 /* Sign-extend and zero-extend are more expensive to load */
3723 if (varTypeIsSmall(tree->TypeGet()))
3729 #if defined(_TARGET_AMD64_)
3730 // increase costSz for floating point locals
3734 if (!gtIsLikelyRegVar(tree))
3740 #if CPU_LONG_USES_REGPAIR
3741 if (varTypeIsLong(tree->TypeGet()))
3743 costEx *= 2; // Longs are twice as expensive
3751 // We generate movw/movt/ldr
3753 costEx = 3 + IND_COST_EX; // 6
3754 costSz = 4 + 4 + 2; // 10
3759 costEx = IND_COST_EX;
3761 if (varTypeIsSmall(tree->TypeGet()))
3781 #if FEATURE_STACK_FP_X87
3782 if (isflt && (oper != GT_PHI_ARG))
3784 codeGen->genIncrementFPstkLevel();
3786 #endif // FEATURE_STACK_FP_X87
3790 /* Is it a 'simple' unary/binary operator? */
3792 if (kind & GTK_SMPOP)
3794 int lvlb; // preference for op2
3795 unsigned lvl2; // scratch variable
3797 GenTreePtr op1 = tree->gtOp.gtOp1;
3798 GenTreePtr op2 = tree->gtGetOp2();
3803 if (tree->OperIsAddrMode())
3812 /* Check for a nilary operator */
3816 assert(op2 == nullptr);
3823 /* Is this a unary operator? */
3827 /* Process the operand of the operator */
3829 /* Most Unary ops have costEx of 1 */
3833 level = gtSetEvalOrder(op1);
3834 ftreg |= op1->gtRsvdRegs;
3836 /* Special handling for some operators */
3851 #if defined(_TARGET_ARM_)
3854 if (isflt || varTypeIsFloating(op1->TypeGet()))
3859 #elif defined(_TARGET_ARM64_)
3862 if (isflt || varTypeIsFloating(op1->TypeGet()))
3867 #elif defined(_TARGET_XARCH_)
3871 if (isflt || varTypeIsFloating(op1->TypeGet()))
3873 /* cast involving floats always go through memory */
3874 costEx = IND_COST_EX * 2;
3877 #if FEATURE_STACK_FP_X87
3878 if (isflt != varTypeIsFloating(op1->TypeGet()))
3880 isflt ? codeGen->genIncrementFPstkLevel() // Cast from int to float
3881 : codeGen->genDecrementFPstkLevel(); // Cast from float to int
3883 #endif // FEATURE_STACK_FP_X87
3886 #error "Unknown _TARGET_"
3889 #if CPU_LONG_USES_REGPAIR
3890 if (varTypeIsLong(tree->TypeGet()))
3892 if (varTypeIsUnsigned(tree->TypeGet()))
3894 /* Cast to unsigned long */
3900 /* Cast to signed long is slightly more costly */
3905 #endif // CPU_LONG_USES_REGPAIR
3907 /* Overflow casts are a lot more expensive */
3908 if (tree->gtOverflow())
3923 // GT_INTRINSIC intrinsics Sin, Cos, Sqrt, Abs ... have higher costs.
3924 // TODO: tune these costs target specific as some of these are
3925 // target intrinsics and would cost less to generate code.
3926 switch (tree->gtIntrinsic.gtIntrinsicId)
3929 assert(!"missing case for gtIntrinsicId");
3934 case CORINFO_INTRINSIC_Sin:
3935 case CORINFO_INTRINSIC_Cos:
3936 case CORINFO_INTRINSIC_Sqrt:
3937 case CORINFO_INTRINSIC_Cosh:
3938 case CORINFO_INTRINSIC_Sinh:
3939 case CORINFO_INTRINSIC_Tan:
3940 case CORINFO_INTRINSIC_Tanh:
3941 case CORINFO_INTRINSIC_Asin:
3942 case CORINFO_INTRINSIC_Acos:
3943 case CORINFO_INTRINSIC_Atan:
3944 case CORINFO_INTRINSIC_Atan2:
3945 case CORINFO_INTRINSIC_Log10:
3946 case CORINFO_INTRINSIC_Pow:
3947 case CORINFO_INTRINSIC_Exp:
3948 case CORINFO_INTRINSIC_Ceiling:
3949 case CORINFO_INTRINSIC_Floor:
3950 case CORINFO_INTRINSIC_Object_GetType:
3951 // Giving intrinsics a large fixed exectuion cost is because we'd like to CSE
3952 // them, even if they are implemented by calls. This is different from modeling
3953 // user calls since we never CSE user calls.
3958 case CORINFO_INTRINSIC_Abs:
3963 case CORINFO_INTRINSIC_Round:
3966 #if FEATURE_STACK_FP_X87
3967 if (tree->TypeGet() == TYP_INT)
3969 // This is a special case to handle the following
3970 // optimization: conv.i4(round.d(d)) -> round.i(d)
3971 codeGen->genDecrementFPstkLevel();
3973 #endif // FEATURE_STACK_FP_X87
3981 // We need to ensure that -x is evaluated before x or else
3982 // we get burned while adjusting genFPstkLevel in x*-x where
3983 // the rhs x is the last use of the enregsitered x.
3985 // Even in the integer case we want to prefer to
3986 // evaluate the side without the GT_NEG node, all other things
3987 // being equal. Also a GT_NOT requires a scratch register
3994 #if FEATURE_STACK_FP_X87
3995 /* If the operand was floating point, pop the value from the stack */
3997 if (varTypeIsFloating(op1->TypeGet()))
3999 codeGen->genDecrementFPstkLevel();
4001 #endif // FEATURE_STACK_FP_X87
4005 // If we have a GT_ADDR of an GT_IND we can just copy the costs from indOp1
4006 if (op1->OperGet() == GT_IND)
4008 GenTreePtr indOp1 = op1->gtOp.gtOp1;
4009 costEx = indOp1->gtCostEx;
4010 costSz = indOp1->gtCostSz;
4017 /* Array Len should be the same as an indirections, which have a costEx of IND_COST_EX */
4018 costEx = IND_COST_EX - 1;
4024 // We estimate the cost of a GT_OBJ or GT_MKREFANY to be two loads (GT_INDs)
4025 costEx = 2 * IND_COST_EX;
4030 // We estimate the cost of a GT_BOX to be two stores (GT_INDs)
4031 costEx = 2 * IND_COST_EX;
4037 /* An indirection should always have a non-zero level.
4038 * Only constant leaf nodes have level 0.
4046 /* Indirections have a costEx of IND_COST_EX */
4047 costEx = IND_COST_EX;
4050 /* If we have to sign-extend or zero-extend, bump the cost */
4051 if (varTypeIsSmall(tree->TypeGet()))
4059 #if FEATURE_STACK_FP_X87
4060 /* Indirect loads of FP values push a new value on the FP stack */
4061 codeGen->genIncrementFPstkLevel();
4062 #endif // FEATURE_STACK_FP_X87
4063 if (tree->TypeGet() == TYP_DOUBLE)
4069 #endif // _TARGET_ARM_
4072 /* Can we form an addressing mode with this indirection? */
4074 if (op1->gtOper == GT_ADD)
4077 #if SCALED_ADDR_MODES
4084 /* See if we can form a complex addressing mode? */
4086 GenTreePtr addr = op1;
4087 if (codeGen->genCreateAddrMode(addr, // address
4090 RBM_NONE, // reg mask
4091 &rev, // reverse ops
4094 #if SCALED_ADDR_MODES
4097 &cns, // displacement
4098 true)) // don't generate code
4100 // We can form a complex addressing mode, so mark each of the interior
4101 // nodes with GTF_ADDRMODE_NO_CSE and calculate a more accurate cost.
4103 addr->gtFlags |= GTF_ADDRMODE_NO_CSE;
4104 #ifdef _TARGET_XARCH_
4105 // addrmodeCount is the count of items that we used to form
4106 // an addressing mode. The maximum value is 4 when we have
4107 // all of these: { base, idx, cns, mul }
4109 unsigned addrmodeCount = 0;
4112 costEx += base->gtCostEx;
4113 costSz += base->gtCostSz;
4119 costEx += idx->gtCostEx;
4120 costSz += idx->gtCostSz;
4126 if (((signed char)cns) == ((int)cns))
4140 // When we form a complex addressing mode we can reduced the costs
4141 // associated with the interior GT_ADD and GT_LSH nodes:
4143 // GT_ADD -- reduce this interior GT_ADD by (-3,-3)
4145 // GT_ADD 'cns' -- reduce this interior GT_ADD by (-2,-2)
4147 // 'base' GT_LSL -- reduce this interior GT_LSL by (-1,-1)
4151 if (addrmodeCount > 1)
4153 // The number of interior GT_ADD and GT_LSL will always be one less than addrmodeCount
4157 GenTreePtr tmp = addr;
4158 while (addrmodeCount > 0)
4160 // decrement the gtCosts for the interior GT_ADD or GT_LSH node by the remaining
4162 tmp->SetCosts(tmp->gtCostEx - addrmodeCount, tmp->gtCostSz - addrmodeCount);
4165 if (addrmodeCount > 0)
4167 GenTreePtr tmpOp1 = tmp->gtOp.gtOp1;
4168 GenTreePtr tmpOp2 = tmp->gtGetOp2();
4169 assert(tmpOp2 != nullptr);
4171 if ((tmpOp1 != base) && (tmpOp1->OperGet() == GT_ADD))
4175 else if (tmpOp2->OperGet() == GT_LSH)
4179 else if (tmpOp1->OperGet() == GT_LSH)
4183 else if (tmpOp2->OperGet() == GT_ADD)
4189 // We can very rarely encounter a tree that has a GT_COMMA node
4190 // that is difficult to walk, so we just early out without decrementing.
4196 #elif defined _TARGET_ARM_
4199 costEx += base->gtCostEx;
4200 costSz += base->gtCostSz;
4201 if ((base->gtOper == GT_LCL_VAR) && ((idx == NULL) || (cns == 0)))
4209 costEx += idx->gtCostEx;
4210 costSz += idx->gtCostSz;
4219 if (cns >= 128) // small offsets fits into a 16-bit instruction
4221 if (cns < 4096) // medium offsets require a 32-bit instruction
4228 costEx += 2; // Very large offsets require movw/movt instructions
4233 #elif defined _TARGET_ARM64_
4236 costEx += base->gtCostEx;
4237 costSz += base->gtCostSz;
4242 costEx += idx->gtCostEx;
4243 costSz += idx->gtCostSz;
4248 if (cns >= (4096 * genTypeSize(tree->TypeGet())))
4255 #error "Unknown _TARGET_"
4258 assert(addr->gtOper == GT_ADD);
4259 assert(!addr->gtOverflow());
4260 assert(op2 == nullptr);
4263 // If we have an addressing mode, we have one of:
4265 // [ idx * mul ] // mul >= 2, else we would use base instead of idx
4266 // [ idx * mul + cns] // mul >= 2, else we would use base instead of idx
4267 // [base + idx * mul ] // mul can be 0, 2, 4, or 8
4268 // [base + idx * mul + cns] // mul can be 0, 2, 4, or 8
4269 // Note that mul == 0 is semantically equivalent to mul == 1.
4270 // Note that cns can be zero.
4271 CLANG_FORMAT_COMMENT_ANCHOR;
4273 #if SCALED_ADDR_MODES
4274 assert((base != nullptr) || (idx != nullptr && mul >= 2));
4276 assert(base != NULL);
4279 INDEBUG(GenTreePtr op1Save = addr);
4281 /* Walk addr looking for non-overflow GT_ADDs */
4282 gtWalkOp(&addr, &op2, base, false);
4284 // addr and op2 are now children of the root GT_ADD of the addressing mode
4285 assert(addr != op1Save);
4286 assert(op2 != nullptr);
4288 /* Walk addr looking for non-overflow GT_ADDs of constants */
4289 gtWalkOp(&addr, &op2, nullptr, true);
4291 // TODO-Cleanup: It seems very strange that we might walk down op2 now, even though the
4293 // call to gtWalkOp() may have altered op2.
4295 /* Walk op2 looking for non-overflow GT_ADDs of constants */
4296 gtWalkOp(&op2, &addr, nullptr, true);
4298 // OK we are done walking the tree
4299 // Now assert that addr and op2 correspond with base and idx
4300 // in one of the several acceptable ways.
4302 // Note that sometimes addr/op2 is equal to idx/base
4303 // and other times addr/op2 is a GT_COMMA node with
4304 // an effective value that is idx/base
4308 if ((addr != base) && (addr->gtOper == GT_LSH))
4310 addr->gtFlags |= GTF_ADDRMODE_NO_CSE;
4311 if (addr->gtOp.gtOp1->gtOper == GT_MUL)
4313 addr->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
4315 assert((base == nullptr) || (op2 == base) ||
4316 (op2->gtEffectiveVal() == base->gtEffectiveVal()) ||
4317 (gtWalkOpEffectiveVal(op2) == gtWalkOpEffectiveVal(base)));
4322 assert(op2->gtOper == GT_LSH || op2->gtOper == GT_MUL);
4323 op2->gtFlags |= GTF_ADDRMODE_NO_CSE;
4324 // We may have eliminated multiple shifts and multiplies in the addressing mode,
4325 // so navigate down through them to get to "idx".
4326 GenTreePtr op2op1 = op2->gtOp.gtOp1;
4327 while ((op2op1->gtOper == GT_LSH || op2op1->gtOper == GT_MUL) && op2op1 != idx)
4329 op2op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
4330 op2op1 = op2op1->gtOp.gtOp1;
4332 assert(addr->gtEffectiveVal() == base);
4333 assert(op2op1 == idx);
4340 if ((addr == idx) || (addr->gtEffectiveVal() == idx))
4344 if ((addr->gtOper == GT_MUL) || (addr->gtOper == GT_LSH))
4346 if ((addr->gtOp.gtOp1->gtOper == GT_NOP) ||
4347 (addr->gtOp.gtOp1->gtOper == GT_MUL &&
4348 addr->gtOp.gtOp1->gtOp.gtOp1->gtOper == GT_NOP))
4350 addr->gtFlags |= GTF_ADDRMODE_NO_CSE;
4351 if (addr->gtOp.gtOp1->gtOper == GT_MUL)
4353 addr->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
4358 assert((op2 == base) || (op2->gtEffectiveVal() == base));
4360 else if ((addr == base) || (addr->gtEffectiveVal() == base))
4365 if ((op2->gtOper == GT_MUL) || (op2->gtOper == GT_LSH))
4367 if ((op2->gtOp.gtOp1->gtOper == GT_NOP) ||
4368 (op2->gtOp.gtOp1->gtOper == GT_MUL &&
4369 op2->gtOp.gtOp1->gtOp.gtOp1->gtOper == GT_NOP))
4372 op2->gtFlags |= GTF_ADDRMODE_NO_CSE;
4373 if (op2->gtOp.gtOp1->gtOper == GT_MUL)
4375 op2->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
4379 assert((op2 == idx) || (op2->gtEffectiveVal() == idx));
4384 // addr isn't base or idx. Is this possible? Or should there be an assert?
4389 } // end if (genCreateAddrMode(...))
4391 } // end if (op1->gtOper == GT_ADD)
4392 else if (gtIsLikelyRegVar(op1))
4394 /* Indirection of an enregister LCL_VAR, don't increase costEx/costSz */
4397 #ifdef _TARGET_XARCH_
4398 else if (op1->IsCnsIntOrI())
4400 // Indirection of a CNS_INT, subtract 1 from costEx
4401 // makes costEx 3 for x86 and 4 for amd64
4403 costEx += (op1->gtCostEx - 1);
4404 costSz += op1->gtCostSz;
4413 costEx += op1->gtCostEx;
4414 costSz += op1->gtCostSz;
4418 /* Binary operator - check for certain special cases */
4422 /* Default Binary ops have a cost of 1,1 */
4432 #ifndef _TARGET_64BIT_
4433 if (varTypeIsLong(op1->TypeGet()))
4435 /* Operations on longs are more expensive */
4445 /* Modulo by a power of 2 is easy */
4447 if (op2->IsCnsIntOrI())
4449 size_t ival = op2->gtIntConCommon.IconValue();
4451 if (ival > 0 && ival == genFindLowestBit(ival))
4464 /* fp division is very expensive to execute */
4465 costEx = 36; // TYP_DOUBLE
4470 /* integer division is also very expensive */
4474 // Encourage the first operand to be evaluated (into EAX/EDX) first */
4477 #ifdef _TARGET_XARCH_
4478 // the idiv and div instruction requires EAX/EDX
4479 ftreg |= RBM_EAX | RBM_EDX;
4488 /* FP multiplication instructions are more expensive */
4494 /* Integer multiplication instructions are more expensive */
4498 if (tree->gtOverflow())
4500 /* Overflow check are more expensive */
4506 if ((tree->gtType == TYP_LONG) || tree->gtOverflow())
4508 /* We use imulEAX for TYP_LONG and overflow multiplications */
4509 // Encourage the first operand to be evaluated (into EAX/EDX) first */
4512 // the imulEAX instruction ob x86 requires EDX:EAX
4513 ftreg |= (RBM_EAX | RBM_EDX);
4515 /* The 64-bit imul instruction costs more */
4518 #endif // _TARGET_X86_
4529 /* FP instructions are a bit more expensive */
4535 /* Overflow check are more expensive */
4536 if (tree->gtOverflow())
4545 /* Comma tosses the result of the left operand */
4546 gtSetEvalOrderAndRestoreFPstkLevel(op1);
4547 level = gtSetEvalOrder(op2);
4549 ftreg |= op1->gtRsvdRegs | op2->gtRsvdRegs;
4551 /* GT_COMMA cost is the sum of op1 and op2 costs */
4552 costEx = (op1->gtCostEx + op2->gtCostEx);
4553 costSz = (op1->gtCostSz + op2->gtCostSz);
4559 level = gtSetEvalOrderAndRestoreFPstkLevel(op1);
4560 lvl2 = gtSetEvalOrder(op2);
4566 else if (level == lvl2)
4571 ftreg |= op1->gtRsvdRegs | op2->gtRsvdRegs;
4572 costEx = op1->gtCostEx + op2->gtCostEx;
4573 costSz = op1->gtCostSz + op2->gtCostSz;
4580 const bool isListCallArgs = false;
4581 const bool callArgsInRegs = false;
4582 return gtSetListOrder(tree, isListCallArgs, callArgsInRegs);
4589 /* Assignments need a bit of special handling */
4591 if (kind & GTK_ASGOP)
4593 /* Process the target */
4595 level = gtSetEvalOrder(op1);
4597 #if FEATURE_STACK_FP_X87
4599 /* If assigning an FP value, the target won't get pushed */
4601 if (isflt && !tree->IsPhiDefn())
4604 codeGen->genDecrementFPstkLevel();
4607 #endif // FEATURE_STACK_FP_X87
4609 if (gtIsLikelyRegVar(op1))
4612 lvl2 = gtSetEvalOrder(op2);
4615 ftreg |= op2->gtRsvdRegs;
4618 /* Assignment to an enregistered LCL_VAR */
4619 costEx = op2->gtCostEx;
4620 costSz = max(3, op2->gtCostSz); // 3 is an estimate for a reg-reg assignment
4621 goto DONE_OP1_AFTER_COST;
4623 else if (oper != GT_ASG)
4625 // Assign-Op instructions read and write op1
4627 costEx += op1->gtCostEx;
4629 costSz += op1->gtCostSz;
4636 /* Process the sub-operands */
4638 level = gtSetEvalOrder(op1);
4641 level -= lvlb; // lvlb is negative, so this increases level
4647 lvl2 = gtSetEvalOrder(op2) + lvlb;
4648 ftreg |= op1->gtRsvdRegs;
4651 ftreg |= op2->gtRsvdRegs;
4654 costEx += (op1->gtCostEx + op2->gtCostEx);
4655 costSz += (op1->gtCostSz + op2->gtCostSz);
4657 DONE_OP1_AFTER_COST:
4658 #if FEATURE_STACK_FP_X87
4660 Binary FP operators pop 2 operands and produce 1 result;
4661 FP comparisons pop 2 operands and produces 0 results.
4662 assignments consume 1 value and don't produce anything.
4665 if (isflt && !tree->IsPhiDefn())
4667 assert(oper != GT_COMMA);
4668 codeGen->genDecrementFPstkLevel();
4670 #endif // FEATURE_STACK_FP_X87
4672 bool bReverseInAssignment = false;
4673 if (kind & GTK_ASGOP)
4675 GenTreePtr op1Val = op1;
4677 if (tree->gtOper == GT_ASG)
4679 // Skip over the GT_IND/GT_ADDR tree (if one exists)
4681 if ((op1->gtOper == GT_IND) && (op1->gtOp.gtOp1->gtOper == GT_ADDR))
4683 op1Val = op1->gtOp.gtOp1->gtOp.gtOp1;
4687 switch (op1Val->gtOper)
4691 // If we have any side effects on the GT_IND child node
4692 // we have to evaluate op1 first
4693 if (op1Val->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT)
4698 // In case op2 assigns to a local var that is used in op1Val, we have to evaluate op1Val first.
4699 if (op2->gtFlags & GTF_ASG)
4704 // If op2 is simple then evaluate op1 first
4706 if (op2->OperKind() & GTK_LEAF)
4711 // fall through and set GTF_REVERSE_OPS
4716 // We evaluate op2 before op1
4717 bReverseInAssignment = true;
4718 tree->gtFlags |= GTF_REVERSE_OPS;
4725 else if (kind & GTK_RELOP)
4727 /* Float compares remove both operands from the FP stack */
4728 /* Also FP comparison uses EAX for flags */
4730 if (varTypeIsFloating(op1->TypeGet()))
4732 #if FEATURE_STACK_FP_X87
4733 codeGen->genDecrementFPstkLevel(2);
4734 #endif // FEATURE_STACK_FP_X87
4735 #ifdef _TARGET_XARCH_
4741 #if CPU_LONG_USES_REGPAIR
4742 if (varTypeIsLong(op1->TypeGet()))
4744 costEx *= 2; // Longs are twice as expensive
4748 if ((tree->gtFlags & GTF_RELOP_JMP_USED) == 0)
4750 /* Using a setcc instruction is more expensive */
4755 /* Check for other interesting cases */
4768 /* Variable sized shifts are more expensive and use REG_SHIFT */
4770 if (!op2->IsCnsIntOrI())
4773 if (REG_SHIFT != REG_NA)
4778 #ifndef _TARGET_64BIT_
4779 // Variable sized LONG shifts require the use of a helper call
4781 if (tree->gtType == TYP_LONG)
4785 costEx += 3 * IND_COST_EX;
4787 ftreg |= RBM_CALLEE_TRASH;
4789 #endif // !_TARGET_64BIT_
4795 switch (tree->gtIntrinsic.gtIntrinsicId)
4797 case CORINFO_INTRINSIC_Atan2:
4798 case CORINFO_INTRINSIC_Pow:
4799 // These math intrinsics are actually implemented by user calls.
4800 // Increase the Sethi 'complexity' by two to reflect the argument
4801 // register requirement.
4805 assert(!"Unknown binary GT_INTRINSIC operator");
4815 /* We need to evalutate constants later as many places in codegen
4816 can't handle op1 being a constant. This is normally naturally
4817 enforced as constants have the least level of 0. However,
4818 sometimes we end up with a tree like "cns1 < nop(cns2)". In
4819 such cases, both sides have a level of 0. So encourage constants
4820 to be evaluated last in such cases */
4822 if ((level == 0) && (level == lvl2) && (op1->OperKind() & GTK_CONST) &&
4823 (tree->OperIsCommutative() || tree->OperIsCompare()))
4828 /* We try to swap operands if the second one is more expensive */
4830 GenTreePtr opA, opB;
4832 if (tree->gtFlags & GTF_REVERSE_OPS)
4843 if (fgOrder == FGOrderLinear)
4845 // Don't swap anything if we're in linear order; we're really just interested in the costs.
4848 else if (bReverseInAssignment)
4850 // Assignments are special, we want the reverseops flags
4851 // so if possible it was set above.
4856 if (tree->gtFlags & GTF_REVERSE_OPS)
4858 tryToSwap = (level > lvl2);
4862 tryToSwap = (level < lvl2);
4865 // Try to force extra swapping when in the stress mode:
4866 if (compStressCompile(STRESS_REVERSE_FLAG, 60) && ((tree->gtFlags & GTF_REVERSE_OPS) == 0) &&
4867 ((op2->OperKind() & GTK_CONST) == 0))
4875 bool canSwap = gtCanSwapOrder(opA, opB);
4879 /* Can we swap the order by commuting the operands? */
4889 if (GenTree::SwapRelop(oper) != oper)
4891 // SetOper will obliterate the VN for the underlying expression.
4892 // If we're in VN CSE phase, we don't want to lose that information,
4893 // so save the value numbers and put them back after the SetOper.
4894 ValueNumPair vnp = tree->gtVNPair;
4895 tree->SetOper(GenTree::SwapRelop(oper));
4896 if (optValnumCSE_phase)
4898 tree->gtVNPair = vnp;
4911 /* Swap the operands */
4913 tree->gtOp.gtOp1 = op2;
4914 tree->gtOp.gtOp2 = op1;
4916 #if FEATURE_STACK_FP_X87
4917 /* We may have to recompute FP levels */
4918 if (op1->gtFPlvl || op2->gtFPlvl)
4919 gtFPstLvlRedo = true;
4920 #endif // FEATURE_STACK_FP_X87
4932 #ifdef LEGACY_BACKEND
4933 // For LSRA we require that LclVars be "evaluated" just prior to their use,
4934 // so that if they must be reloaded, it is done at the right place.
4935 // This means that we allow reverse evaluation for all BINOPs.
4936 // (Note that this doesn't affect the order of the operands in the instruction).
4939 #endif // LEGACY_BACKEND
4945 /* Mark the operand's evaluation order to be swapped */
4946 if (tree->gtFlags & GTF_REVERSE_OPS)
4948 tree->gtFlags &= ~GTF_REVERSE_OPS;
4952 tree->gtFlags |= GTF_REVERSE_OPS;
4955 #if FEATURE_STACK_FP_X87
4956 /* We may have to recompute FP levels */
4957 if (op1->gtFPlvl || op2->gtFPlvl)
4958 gtFPstLvlRedo = true;
4959 #endif // FEATURE_STACK_FP_X87
4966 /* Swap the level counts */
4967 if (tree->gtFlags & GTF_REVERSE_OPS)
4976 /* Compute the sethi number for this binary operator */
4982 else if (level == lvl2)
4990 /* See what kind of a special operator we have here */
4994 unsigned lvl2; // Scratch variable
4998 assert(tree->gtFlags & GTF_CALL);
5004 /* Evaluate the 'this' argument, if present */
5006 if (tree->gtCall.gtCallObjp)
5008 GenTreePtr thisVal = tree->gtCall.gtCallObjp;
5010 lvl2 = gtSetEvalOrder(thisVal);
5015 costEx += thisVal->gtCostEx;
5016 costSz += thisVal->gtCostSz + 1;
5017 ftreg |= thisVal->gtRsvdRegs;
5020 /* Evaluate the arguments, right to left */
5022 if (tree->gtCall.gtCallArgs)
5024 #if FEATURE_STACK_FP_X87
5025 FPlvlSave = codeGen->genGetFPstkLevel();
5026 #endif // FEATURE_STACK_FP_X87
5027 const bool isListCallArgs = true;
5028 const bool callArgsInRegs = false;
5029 lvl2 = gtSetListOrder(tree->gtCall.gtCallArgs, isListCallArgs, callArgsInRegs);
5034 costEx += tree->gtCall.gtCallArgs->gtCostEx;
5035 costSz += tree->gtCall.gtCallArgs->gtCostSz;
5036 ftreg |= tree->gtCall.gtCallArgs->gtRsvdRegs;
5037 #if FEATURE_STACK_FP_X87
5038 codeGen->genResetFPstkLevel(FPlvlSave);
5039 #endif // FEATURE_STACK_FP_X87
5042 /* Evaluate the temp register arguments list
5043 * This is a "hidden" list and its only purpose is to
5044 * extend the life of temps until we make the call */
5046 if (tree->gtCall.gtCallLateArgs)
5048 #if FEATURE_STACK_FP_X87
5049 FPlvlSave = codeGen->genGetFPstkLevel();
5050 #endif // FEATURE_STACK_FP_X87
5051 const bool isListCallArgs = true;
5052 const bool callArgsInRegs = true;
5053 lvl2 = gtSetListOrder(tree->gtCall.gtCallLateArgs, isListCallArgs, callArgsInRegs);
5058 costEx += tree->gtCall.gtCallLateArgs->gtCostEx;
5059 costSz += tree->gtCall.gtCallLateArgs->gtCostSz;
5060 ftreg |= tree->gtCall.gtCallLateArgs->gtRsvdRegs;
5061 #if FEATURE_STACK_FP_X87
5062 codeGen->genResetFPstkLevel(FPlvlSave);
5063 #endif // FEATURE_STACK_FP_X87
5066 if (tree->gtCall.gtCallType == CT_INDIRECT)
5068 // pinvoke-calli cookie is a constant, or constant indirection
5069 assert(tree->gtCall.gtCallCookie == nullptr || tree->gtCall.gtCallCookie->gtOper == GT_CNS_INT ||
5070 tree->gtCall.gtCallCookie->gtOper == GT_IND);
5072 GenTreePtr indirect = tree->gtCall.gtCallAddr;
5074 lvl2 = gtSetEvalOrder(indirect);
5079 costEx += indirect->gtCostEx + IND_COST_EX;
5080 costSz += indirect->gtCostSz;
5081 ftreg |= indirect->gtRsvdRegs;
5086 if ((tree->gtFlags & GTF_CALL_VIRT_KIND_MASK) == GTF_CALL_VIRT_STUB)
5088 // We generate movw/movt/ldr
5089 costEx += (1 + IND_COST_EX);
5091 if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT)
5093 // Must use R12 for the ldr target -- REG_JUMP_THUNK_PARAM
5097 else if ((opts.eeFlags & CORJIT_FLG_PREJIT) == 0)
5104 #ifdef _TARGET_XARCH_
5112 callKind = (tree->gtFlags & GTF_CALL_VIRT_KIND_MASK);
5114 /* Virtual calls are a bit more expensive */
5115 if (callKind != GTF_CALL_NONVIRT)
5117 costEx += 2 * IND_COST_EX;
5121 /* Virtual stub calls also must reserve the VIRTUAL_STUB_PARAM reg */
5122 if (callKind == GTF_CALL_VIRT_STUB)
5124 ftreg |= RBM_VIRTUAL_STUB_PARAM;
5127 #ifdef FEATURE_READYTORUN_COMPILER
5128 #ifdef _TARGET_ARM64_
5129 if (tree->gtCall.IsR2RRelativeIndir())
5131 ftreg |= RBM_R2R_INDIRECT_PARAM;
5136 #if GTF_CALL_REG_SAVE
5137 // Normally function calls don't preserve caller save registers
5138 // and thus are much more expensive.
5139 // However a few function calls do preserve these registers
5140 // such as the GC WriteBarrier helper calls.
5142 if (!(tree->gtFlags & GTF_CALL_REG_SAVE))
5146 costEx += 3 * IND_COST_EX;
5147 ftreg |= RBM_CALLEE_TRASH;
5150 #if FEATURE_STACK_FP_X87
5152 codeGen->genIncrementFPstkLevel();
5153 #endif // FEATURE_STACK_FP_X87
5159 level = gtSetEvalOrder(tree->gtArrElem.gtArrObj);
5160 costEx = tree->gtArrElem.gtArrObj->gtCostEx;
5161 costSz = tree->gtArrElem.gtArrObj->gtCostSz;
5164 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
5166 lvl2 = gtSetEvalOrder(tree->gtArrElem.gtArrInds[dim]);
5171 costEx += tree->gtArrElem.gtArrInds[dim]->gtCostEx;
5172 costSz += tree->gtArrElem.gtArrInds[dim]->gtCostSz;
5175 #if FEATURE_STACK_FP_X87
5177 codeGen->genIncrementFPstkLevel();
5178 #endif // FEATURE_STACK_FP_X87
5179 level += tree->gtArrElem.gtArrRank;
5180 costEx += 2 + (tree->gtArrElem.gtArrRank * (IND_COST_EX + 1));
5181 costSz += 2 + (tree->gtArrElem.gtArrRank * 2);
5185 level = gtSetEvalOrder(tree->gtArrOffs.gtOffset);
5186 costEx = tree->gtArrOffs.gtOffset->gtCostEx;
5187 costSz = tree->gtArrOffs.gtOffset->gtCostSz;
5188 lvl2 = gtSetEvalOrder(tree->gtArrOffs.gtIndex);
5189 level = max(level, lvl2);
5190 costEx += tree->gtArrOffs.gtIndex->gtCostEx;
5191 costSz += tree->gtArrOffs.gtIndex->gtCostSz;
5192 lvl2 = gtSetEvalOrder(tree->gtArrOffs.gtArrObj);
5193 level = max(level, lvl2);
5194 costEx += tree->gtArrOffs.gtArrObj->gtCostEx;
5195 costSz += tree->gtArrOffs.gtArrObj->gtCostSz;
5200 level = gtSetEvalOrder(tree->gtCmpXchg.gtOpLocation);
5201 costSz = tree->gtCmpXchg.gtOpLocation->gtCostSz;
5203 lvl2 = gtSetEvalOrder(tree->gtCmpXchg.gtOpValue);
5208 costSz += tree->gtCmpXchg.gtOpValue->gtCostSz;
5210 lvl2 = gtSetEvalOrder(tree->gtCmpXchg.gtOpComparand);
5215 costSz += tree->gtCmpXchg.gtOpComparand->gtCostSz;
5217 costEx = MAX_COST; // Seriously, what could be more expensive than lock cmpxchg?
5218 costSz += 5; // size of lock cmpxchg [reg+C], reg
5219 #ifdef _TARGET_XARCH_
5220 ftreg |= RBM_EAX; // cmpxchg must be evaluated into eax.
5224 case GT_ARR_BOUNDS_CHECK:
5227 #endif // FEATURE_SIMD
5228 costEx = 4; // cmp reg,reg and jae throw (not taken)
5229 costSz = 7; // jump to cold section
5231 level = gtSetEvalOrder(tree->gtBoundsChk.gtArrLen);
5232 costEx += tree->gtBoundsChk.gtArrLen->gtCostEx;
5233 costSz += tree->gtBoundsChk.gtArrLen->gtCostSz;
5235 lvl2 = gtSetEvalOrder(tree->gtBoundsChk.gtIndex);
5240 costEx += tree->gtBoundsChk.gtIndex->gtCostEx;
5241 costSz += tree->gtBoundsChk.gtIndex->gtCostSz;
5249 printf("unexpected operator in this tree:\n");
5253 NO_WAY("unexpected operator");
5258 #if FEATURE_STACK_FP_X87
5259 // printf("[FPlvl=%2u] ", genGetFPstkLevel()); gtDispTree(tree, 0, true);
5260 noway_assert((unsigned char)codeGen->genFPstkLevel == codeGen->genFPstkLevel);
5261 tree->gtFPlvl = (unsigned char)codeGen->genFPstkLevel;
5263 if (codeGen->genFPstkLevel > tmpDoubleSpillMax)
5264 tmpDoubleSpillMax = codeGen->genFPstkLevel;
5265 #endif // FEATURE_STACK_FP_X87
5267 tree->gtRsvdRegs = (regMaskSmall)ftreg;
5269 // Some path through this function must have set the costs.
5270 assert(costEx != -1);
5271 assert(costSz != -1);
5273 tree->SetCosts(costEx, costSz);
5278 #pragma warning(pop)
5281 #if FEATURE_STACK_FP_X87
5283 /*****************************************************************************/
5284 void Compiler::gtComputeFPlvls(GenTreePtr tree)
5289 unsigned savFPstkLevel;
5292 noway_assert(tree->gtOper != GT_STMT);
5294 /* Figure out what kind of a node we have */
5296 oper = tree->OperGet();
5297 kind = tree->OperKind();
5298 isflt = varTypeIsFloating(tree->TypeGet()) ? 1 : 0;
5300 /* Is this a constant or leaf node? */
5302 if (kind & (GTK_CONST | GTK_LEAF))
5304 codeGen->genFPstkLevel += isflt;
5308 /* Is it a 'simple' unary/binary operator? */
5310 if (kind & GTK_SMPOP)
5312 GenTreePtr op1 = tree->gtOp.gtOp1;
5313 GenTreePtr op2 = tree->gtGetOp2();
5315 /* Check for some special cases */
5321 gtComputeFPlvls(op1);
5323 /* Indirect loads of FP values push a new value on the FP stack */
5325 codeGen->genFPstkLevel += isflt;
5330 gtComputeFPlvls(op1);
5332 /* Casts between non-FP and FP push on / pop from the FP stack */
5334 if (varTypeIsFloating(op1->TypeGet()))
5337 codeGen->genFPstkLevel--;
5342 codeGen->genFPstkLevel++;
5347 case GT_LIST: /* GT_LIST presumably part of an argument list */
5348 case GT_COMMA: /* Comma tosses the result of the left operand */
5350 savFPstkLevel = codeGen->genFPstkLevel;
5351 gtComputeFPlvls(op1);
5352 codeGen->genFPstkLevel = savFPstkLevel;
5355 gtComputeFPlvls(op2);
5368 gtComputeFPlvls(op2);
5374 gtComputeFPlvls(op1);
5375 if (oper == GT_ADDR)
5377 /* If the operand was floating point pop the value from the stack */
5378 if (varTypeIsFloating(op1->TypeGet()))
5380 noway_assert(codeGen->genFPstkLevel);
5381 codeGen->genFPstkLevel--;
5385 // This is a special case to handle the following
5386 // optimization: conv.i4(round.d(d)) -> round.i(d)
5388 if (oper == GT_INTRINSIC && tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Round &&
5389 tree->TypeGet() == TYP_INT)
5391 codeGen->genFPstkLevel--;
5397 /* FP assignments need a bit special handling */
5399 if (isflt && (kind & GTK_ASGOP))
5401 /* The target of the assignment won't get pushed */
5403 if (tree->gtFlags & GTF_REVERSE_OPS)
5405 gtComputeFPlvls(op2);
5406 gtComputeFPlvls(op1);
5408 codeGen->genFPstkLevel--;
5412 gtComputeFPlvls(op1);
5414 codeGen->genFPstkLevel--;
5415 gtComputeFPlvls(op2);
5418 codeGen->genFPstkLevel--;
5422 /* Here we have a binary operator; visit operands in proper order */
5424 if (tree->gtFlags & GTF_REVERSE_OPS)
5426 gtComputeFPlvls(op2);
5427 gtComputeFPlvls(op1);
5431 gtComputeFPlvls(op1);
5432 gtComputeFPlvls(op2);
5436 Binary FP operators pop 2 operands and produce 1 result;
5437 assignments consume 1 value and don't produce any.
5441 codeGen->genFPstkLevel--;
5443 /* Float compares remove both operands from the FP stack */
5445 if (kind & GTK_RELOP)
5447 if (varTypeIsFloating(op1->TypeGet()))
5448 codeGen->genFPstkLevel -= 2;
5454 /* See what kind of a special operator we have here */
5459 gtComputeFPlvls(tree->gtField.gtFldObj);
5460 codeGen->genFPstkLevel += isflt;
5465 if (tree->gtCall.gtCallObjp)
5466 gtComputeFPlvls(tree->gtCall.gtCallObjp);
5468 if (tree->gtCall.gtCallArgs)
5470 savFPstkLevel = codeGen->genFPstkLevel;
5471 gtComputeFPlvls(tree->gtCall.gtCallArgs);
5472 codeGen->genFPstkLevel = savFPstkLevel;
5475 if (tree->gtCall.gtCallLateArgs)
5477 savFPstkLevel = codeGen->genFPstkLevel;
5478 gtComputeFPlvls(tree->gtCall.gtCallLateArgs);
5479 codeGen->genFPstkLevel = savFPstkLevel;
5482 codeGen->genFPstkLevel += isflt;
5487 gtComputeFPlvls(tree->gtArrElem.gtArrObj);
5490 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
5491 gtComputeFPlvls(tree->gtArrElem.gtArrInds[dim]);
5493 /* Loads of FP values push a new value on the FP stack */
5494 codeGen->genFPstkLevel += isflt;
5498 // Evaluate the trees left to right
5499 gtComputeFPlvls(tree->gtCmpXchg.gtOpLocation);
5500 gtComputeFPlvls(tree->gtCmpXchg.gtOpValue);
5501 gtComputeFPlvls(tree->gtCmpXchg.gtOpComparand);
5502 noway_assert(!isflt);
5505 case GT_ARR_BOUNDS_CHECK:
5506 gtComputeFPlvls(tree->gtBoundsChk.gtArrLen);
5507 gtComputeFPlvls(tree->gtBoundsChk.gtIndex);
5508 noway_assert(!isflt);
5513 noway_assert(!"Unhandled special operator in gtComputeFPlvls()");
5520 noway_assert((unsigned char)codeGen->genFPstkLevel == codeGen->genFPstkLevel);
5522 tree->gtFPlvl = (unsigned char)codeGen->genFPstkLevel;
5525 #endif // FEATURE_STACK_FP_X87
5527 /*****************************************************************************
5529 * If the given tree is an integer constant that can be used
5530 * in a scaled index address mode as a multiplier (e.g. "[4*index]"), then return
5531 * the scale factor: 2, 4, or 8. Otherwise, return 0. Note that we never return 1,
5532 * to match the behavior of GetScaleIndexShf().
5535 unsigned GenTree::GetScaleIndexMul()
5537 if (IsCnsIntOrI() && jitIsScaleIndexMul(gtIntConCommon.IconValue()) && gtIntConCommon.IconValue() != 1)
5539 return (unsigned)gtIntConCommon.IconValue();
5545 /*****************************************************************************
5547 * If the given tree is the right-hand side of a left shift (that is,
5548 * 'y' in the tree 'x' << 'y'), and it is an integer constant that can be used
5549 * in a scaled index address mode as a multiplier (e.g. "[4*index]"), then return
5550 * the scale factor: 2, 4, or 8. Otherwise, return 0.
5553 unsigned GenTree::GetScaleIndexShf()
5555 if (IsCnsIntOrI() && jitIsScaleIndexShift(gtIntConCommon.IconValue()))
5557 return (unsigned)(1 << gtIntConCommon.IconValue());
5563 /*****************************************************************************
5565 * If the given tree is a scaled index (i.e. "op * 4" or "op << 2"), returns
5566 * the multiplier: 2, 4, or 8; otherwise returns 0. Note that "1" is never
5570 unsigned GenTree::GetScaledIndex()
5572 // with (!opts.OptEnabled(CLFLG_CONSTANTFOLD) we can have
5573 // CNS_INT * CNS_INT
5575 if (gtOp.gtOp1->IsCnsIntOrI())
5583 return gtOp.gtOp2->GetScaleIndexMul();
5586 return gtOp.gtOp2->GetScaleIndexShf();
5589 assert(!"GenTree::GetScaledIndex() called with illegal gtOper");
5596 /*****************************************************************************
5598 * Returns true if "addr" is a GT_ADD node, at least one of whose arguments is an integer (<= 32 bit)
5599 * constant. If it returns true, it sets "*offset" to (one of the) constant value(s), and
5600 * "*addr" to the other argument.
5603 bool GenTree::IsAddWithI32Const(GenTreePtr* addr, int* offset)
5605 if (OperGet() == GT_ADD)
5607 if (gtOp.gtOp1->IsIntCnsFitsInI32())
5609 *offset = (int)gtOp.gtOp1->gtIntCon.gtIconVal;
5613 else if (gtOp.gtOp2->IsIntCnsFitsInI32())
5615 *offset = (int)gtOp.gtOp2->gtIntCon.gtIconVal;
5624 //------------------------------------------------------------------------
5625 // gtGetChildPointer: If 'parent' is the parent of this node, return the pointer
5626 // to the child node so that it can be modified; otherwise, return nullptr.
5629 // parent - The possible parent of this node
5632 // If "child" is a child of "parent", returns a pointer to the child node in the parent
5633 // (i.e. a pointer to a GenTree pointer).
5634 // Otherwise, returns nullptr.
5637 // 'parent' must be non-null
5640 // When FEATURE_MULTIREG_ARGS is defined we can get here with GT_LDOBJ tree.
5641 // This happens when we have a struct that is passed in multiple registers.
5643 // Also note that when FEATURE_UNIX_AMD64_STRUCT_PASSING is defined the GT_LDOBJ
5644 // later gets converted to a GT_LIST with two GT_LCL_FLDs in Lower/LowerXArch.
5647 GenTreePtr* GenTree::gtGetChildPointer(GenTreePtr parent)
5650 switch (parent->OperGet())
5653 if (!parent->OperIsSimple())
5657 if (this == parent->gtOp.gtOp1)
5659 return &(parent->gtOp.gtOp1);
5661 if (this == parent->gtOp.gtOp2)
5663 return &(parent->gtOp.gtOp2);
5667 #if !FEATURE_MULTIREG_ARGS
5668 // Note that when FEATURE_MULTIREG_ARGS==1
5669 // a GT_OBJ node is handled above by the default case
5671 // Any GT_OBJ with a field must be lowered before this point.
5672 noway_assert(!"GT_OBJ encountered in GenTree::gtGetChildPointer");
5674 #endif // !FEATURE_MULTIREG_ARGS
5677 if (this == parent->gtCmpXchg.gtOpLocation)
5679 return &(parent->gtCmpXchg.gtOpLocation);
5681 if (this == parent->gtCmpXchg.gtOpValue)
5683 return &(parent->gtCmpXchg.gtOpValue);
5685 if (this == parent->gtCmpXchg.gtOpComparand)
5687 return &(parent->gtCmpXchg.gtOpComparand);
5691 case GT_ARR_BOUNDS_CHECK:
5694 #endif // FEATURE_SIMD
5695 if (this == parent->gtBoundsChk.gtArrLen)
5697 return &(parent->gtBoundsChk.gtArrLen);
5699 if (this == parent->gtBoundsChk.gtIndex)
5701 return &(parent->gtBoundsChk.gtIndex);
5703 if (this == parent->gtBoundsChk.gtIndRngFailBB)
5705 return &(parent->gtBoundsChk.gtIndRngFailBB);
5710 if (this == parent->gtArrElem.gtArrObj)
5712 return &(parent->gtArrElem.gtArrObj);
5714 for (int i = 0; i < GT_ARR_MAX_RANK; i++)
5716 if (this == parent->gtArrElem.gtArrInds[i])
5718 return &(parent->gtArrElem.gtArrInds[i]);
5724 if (this == parent->gtArrOffs.gtOffset)
5726 return &(parent->gtArrOffs.gtOffset);
5728 if (this == parent->gtArrOffs.gtIndex)
5730 return &(parent->gtArrOffs.gtIndex);
5732 if (this == parent->gtArrOffs.gtArrObj)
5734 return &(parent->gtArrOffs.gtArrObj);
5739 if (this == parent->AsField()->gtFldObj)
5741 return &(parent->AsField()->gtFldObj);
5746 if (this == parent->gtRetExpr.gtInlineCandidate)
5748 return &(parent->gtRetExpr.gtInlineCandidate);
5754 GenTreeCall* call = parent->AsCall();
5756 if (this == call->gtCallObjp)
5758 return &(call->gtCallObjp);
5760 if (this == call->gtCallArgs)
5762 return reinterpret_cast<GenTreePtr*>(&(call->gtCallArgs));
5764 if (this == call->gtCallLateArgs)
5766 return reinterpret_cast<GenTreePtr*>(&(call->gtCallLateArgs));
5768 if (this == call->gtControlExpr)
5770 return &(call->gtControlExpr);
5772 if (call->gtCallType == CT_INDIRECT)
5774 if (this == call->gtCallCookie)
5776 return &(call->gtCallCookie);
5778 if (this == call->gtCallAddr)
5780 return &(call->gtCallAddr);
5787 noway_assert(!"Illegal node for gtGetChildPointer()");
5794 bool GenTree::TryGetUse(GenTree* def, GenTree*** use)
5796 for (GenTree** useEdge : UseEdges())
5798 if (*useEdge == def)
5808 //------------------------------------------------------------------------
5809 // gtGetParent: Get the parent of this node, and optionally capture the
5810 // pointer to the child so that it can be modified.
5814 // parentChildPointer - A pointer to a GenTreePtr* (yes, that's three
5815 // levels, i.e. GenTree ***), which if non-null,
5816 // will be set to point to the field in the parent
5817 // that points to this node.
5819 // Return value - The parent of this node.
5823 // This requires that the execution order must be defined (i.e. gtSetEvalOrder() has been called).
5824 // To enable the child to be replaced, it accepts an argument, parentChildPointer that, if non-null,
5825 // will be set to point to the child pointer in the parent that points to this node.
5827 GenTreePtr GenTree::gtGetParent(GenTreePtr** parentChildPtrPtr)
5829 // Find the parent node; it must be after this node in the execution order.
5830 GenTreePtr* parentChildPtr = nullptr;
5832 for (parent = gtNext; parent != nullptr; parent = parent->gtNext)
5834 parentChildPtr = gtGetChildPointer(parent);
5835 if (parentChildPtr != nullptr)
5840 if (parentChildPtrPtr != nullptr)
5842 *parentChildPtrPtr = parentChildPtr;
5847 /*****************************************************************************
5849 * Returns true if the given operator may cause an exception.
5852 bool GenTree::OperMayThrow()
5863 /* Division with a non-zero, non-minus-one constant does not throw an exception */
5867 if (varTypeIsFloating(op->TypeGet()))
5869 return false; // Floating point division does not throw.
5872 // For integers only division by 0 or by -1 can throw
5873 if (op->IsIntegralConst() && !op->IsIntegralConst(0) && !op->IsIntegralConst(-1))
5882 /* Indirections of handles are known to be safe */
5883 if (op->gtOper == GT_CNS_INT)
5885 if (op->IsIconHandle())
5887 /* No exception is thrown on this indirection */
5891 if (this->gtFlags & GTF_IND_NONFAULTING)
5895 // Non-Null AssertionProp will remove the GTF_EXCEPT flag and mark the GT_IND with GTF_ORDER_SIDEEFF flag
5896 if ((this->gtFlags & GTF_ALL_EFFECT) == GTF_ORDER_SIDEEFF)
5904 // If this is an intrinsic that represents the object.GetType(), it can throw an NullReferenceException.
5905 // Report it as may throw.
5906 // Note: Some of the rest of the existing intrinsics could potentially throw an exception (for example
5907 // the array and string element access ones). They are handled differently than the GetType intrinsic
5908 // and are not marked with GTF_EXCEPT. If these are revisited at some point to be marked as
5910 // the code below might need to be specialized to handle them properly.
5911 if ((this->gtFlags & GTF_EXCEPT) != 0)
5919 return !Compiler::fgIsIndirOfAddrOfLocal(this);
5921 case GT_ARR_BOUNDS_CHECK:
5931 #endif // FEATURE_SIMD
5937 /* Overflow arithmetic operations also throw exceptions */
5947 #if DEBUGGABLE_GENTREE
5949 GenTree::VtablePtr GenTree::s_vtablesForOpers[] = {nullptr};
5950 GenTree::VtablePtr GenTree::s_vtableForOp = nullptr;
5952 GenTree::VtablePtr GenTree::GetVtableForOper(genTreeOps oper)
5954 noway_assert(oper < GT_COUNT);
5956 if (s_vtablesForOpers[oper] != nullptr)
5958 return s_vtablesForOpers[oper];
5961 VtablePtr res = nullptr;
5964 #define GTSTRUCT_0(nm, tag) /*handle explicitly*/
5965 #define GTSTRUCT_1(nm, tag) \
5969 res = *reinterpret_cast<VtablePtr*>(>); \
5972 #define GTSTRUCT_2(nm, tag, tag2) /*handle explicitly*/
5973 #define GTSTRUCT_3(nm, tag, tag2, tag3) /*handle explicitly*/
5974 #define GTSTRUCT_4(nm, tag, tag2, tag3, tag4) /*handle explicitly*/
5975 #define GTSTRUCT_N(nm, ...) /*handle explicitly*/
5976 #include "gtstructs.h"
5978 #if !FEATURE_EH_FUNCLETS
5979 // If FEATURE_EH_FUNCLETS is set, then GT_JMP becomes the only member of Val, and will be handled above.
5983 GenTreeVal gt(GT_JMP, TYP_INT, 0);
5984 res = *reinterpret_cast<VtablePtr*>(>);
5990 // Should be unary or binary op.
5991 if (s_vtableForOp == nullptr)
5993 unsigned opKind = OperKind(oper);
5994 assert(!IsExOp(opKind));
5995 assert(OperIsSimple(oper) || OperIsLeaf(oper));
5996 // Need to provide non-null operands.
5997 Compiler* comp = (Compiler*)_alloca(sizeof(Compiler));
5998 GenTreeIntCon dummyOp(TYP_INT, 0);
5999 GenTreeOp gt(oper, TYP_INT, &dummyOp, ((opKind & GTK_UNOP) ? nullptr : &dummyOp));
6000 s_vtableForOp = *reinterpret_cast<VtablePtr*>(>);
6002 res = s_vtableForOp;
6006 s_vtablesForOpers[oper] = res;
6010 void GenTree::SetVtableForOper(genTreeOps oper)
6012 *reinterpret_cast<VtablePtr*>(this) = GetVtableForOper(oper);
6014 #endif // DEBUGGABLE_GENTREE
6016 GenTreePtr Compiler::gtNewOperNode(genTreeOps oper, var_types type, GenTreePtr op1, GenTreePtr op2)
6018 assert(op1 != nullptr);
6019 assert(op2 != nullptr);
6021 // We should not be allocating nodes that extend GenTreeOp with this;
6022 // should call the appropriate constructor for the extended type.
6023 assert(!GenTree::IsExOp(GenTree::OperKind(oper)));
6025 GenTreePtr node = new (this, oper) GenTreeOp(oper, type, op1, op2);
6030 GenTreePtr Compiler::gtNewQmarkNode(var_types type, GenTreePtr cond, GenTreePtr colon)
6032 compQmarkUsed = true;
6033 GenTree* result = new (this, GT_QMARK) GenTreeQmark(type, cond, colon, this);
6035 if (compQmarkRationalized)
6037 fgCheckQmarkAllowedForm(result);
6043 GenTreeQmark::GenTreeQmark(var_types type, GenTreePtr cond, GenTreePtr colonOp, Compiler* comp)
6044 : GenTreeOp(GT_QMARK, type, cond, colonOp)
6045 , gtThenLiveSet(VarSetOps::UninitVal())
6046 , gtElseLiveSet(VarSetOps::UninitVal())
6048 // These must follow a specific form.
6049 assert(cond != nullptr && cond->TypeGet() == TYP_INT);
6050 assert(colonOp != nullptr && colonOp->OperGet() == GT_COLON);
6052 comp->impInlineRoot()->compQMarks->Push(this);
6055 GenTreeIntCon* Compiler::gtNewIconNode(ssize_t value, var_types type)
6057 return new (this, GT_CNS_INT) GenTreeIntCon(type, value);
6060 // return a new node representing the value in a physical register
6061 GenTree* Compiler::gtNewPhysRegNode(regNumber reg, var_types type)
6063 assert(genIsValidIntReg(reg) || (reg == REG_SPBASE));
6064 GenTree* result = new (this, GT_PHYSREG) GenTreePhysReg(reg, type);
6068 // Return a new node representing a store of a value to a physical register
6069 // modifies: child's gtRegNum
6070 GenTree* Compiler::gtNewPhysRegNode(regNumber reg, GenTree* src)
6072 assert(genIsValidIntReg(reg));
6073 GenTree* result = new (this, GT_PHYSREGDST) GenTreeOp(GT_PHYSREGDST, TYP_I_IMPL, src, nullptr);
6074 result->gtRegNum = reg;
6075 src->gtRegNum = reg;
6079 #ifndef LEGACY_BACKEND
6080 GenTreePtr Compiler::gtNewJmpTableNode()
6082 GenTreePtr node = new (this, GT_JMPTABLE) GenTreeJumpTable(TYP_INT);
6083 node->gtJumpTable.gtJumpTableAddr = 0;
6086 #endif // !LEGACY_BACKEND
6088 /*****************************************************************************
6090 * Converts an annotated token into an icon flags (so that we will later be
6091 * able to tell the type of the handle that will be embedded in the icon
6095 unsigned Compiler::gtTokenToIconFlags(unsigned token)
6099 switch (TypeFromToken(token))
6104 flags = GTF_ICON_CLASS_HDL;
6108 flags = GTF_ICON_METHOD_HDL;
6112 flags = GTF_ICON_FIELD_HDL;
6116 flags = GTF_ICON_TOKEN_HDL;
6123 /*****************************************************************************
6125 * Allocates a integer constant entry that represents a HANDLE to something.
6126 * It may not be allowed to embed HANDLEs directly into the JITed code (for eg,
6127 * as arguments to JIT helpers). Get a corresponding value that can be embedded.
6128 * If the handle needs to be accessed via an indirection, pValue points to it.
6131 GenTreePtr Compiler::gtNewIconEmbHndNode(
6132 void* value, void* pValue, unsigned flags, unsigned handle1, void* handle2, void* compileTimeHandle)
6136 assert((!value) != (!pValue));
6140 node = gtNewIconHandleNode((size_t)value, flags, /*fieldSeq*/ FieldSeqStore::NotAField(), handle1, handle2);
6141 node->gtIntCon.gtCompileTimeHandle = (size_t)compileTimeHandle;
6145 node = gtNewIconHandleNode((size_t)pValue, flags, /*fieldSeq*/ FieldSeqStore::NotAField(), handle1, handle2);
6146 node->gtIntCon.gtCompileTimeHandle = (size_t)compileTimeHandle;
6147 node = gtNewOperNode(GT_IND, TYP_I_IMPL, node);
6153 /*****************************************************************************/
6154 GenTreePtr Compiler::gtNewStringLiteralNode(InfoAccessType iat, void* pValue)
6156 GenTreePtr tree = nullptr;
6160 case IAT_VALUE: // The info value is directly available
6161 tree = gtNewIconEmbHndNode(pValue, nullptr, GTF_ICON_STR_HDL);
6162 tree->gtType = TYP_REF;
6163 tree = gtNewOperNode(GT_NOP, TYP_REF, tree); // prevents constant folding
6166 case IAT_PVALUE: // The value needs to be accessed via an indirection
6167 tree = gtNewIconHandleNode((size_t)pValue, GTF_ICON_STR_HDL);
6168 // An indirection of a string handle can't cause an exception so don't set GTF_EXCEPT
6169 tree = gtNewOperNode(GT_IND, TYP_REF, tree);
6170 tree->gtFlags |= GTF_GLOB_REF;
6173 case IAT_PPVALUE: // The value needs to be accessed via a double indirection
6174 tree = gtNewIconHandleNode((size_t)pValue, GTF_ICON_PSTR_HDL);
6175 tree = gtNewOperNode(GT_IND, TYP_I_IMPL, tree);
6176 tree->gtFlags |= GTF_IND_INVARIANT;
6177 // An indirection of a string handle can't cause an exception so don't set GTF_EXCEPT
6178 tree = gtNewOperNode(GT_IND, TYP_REF, tree);
6179 tree->gtFlags |= GTF_GLOB_REF;
6183 assert(!"Unexpected InfoAccessType");
6189 /*****************************************************************************/
6191 GenTreePtr Compiler::gtNewLconNode(__int64 value)
6193 #ifdef _TARGET_64BIT_
6194 GenTreePtr node = new (this, GT_CNS_INT) GenTreeIntCon(TYP_LONG, value);
6196 GenTreePtr node = new (this, GT_CNS_LNG) GenTreeLngCon(value);
6202 GenTreePtr Compiler::gtNewDconNode(double value)
6204 GenTreePtr node = new (this, GT_CNS_DBL) GenTreeDblCon(value);
6209 GenTreePtr Compiler::gtNewSconNode(int CPX, CORINFO_MODULE_HANDLE scpHandle)
6212 #if SMALL_TREE_NODES
6214 /* 'GT_CNS_STR' nodes later get transformed into 'GT_CALL' */
6216 assert(GenTree::s_gtNodeSizes[GT_CALL] > GenTree::s_gtNodeSizes[GT_CNS_STR]);
6218 GenTreePtr node = new (this, GT_CALL) GenTreeStrCon(CPX, scpHandle DEBUGARG(/*largeNode*/ true));
6220 GenTreePtr node = new (this, GT_CNS_STR) GenTreeStrCon(CPX, scpHandle DEBUGARG(/*largeNode*/ true));
6226 GenTreePtr Compiler::gtNewZeroConNode(var_types type)
6232 zero = gtNewIconNode(0);
6239 zero = gtNewIconNode(0);
6240 zero->gtType = type;
6244 zero = gtNewLconNode(0);
6248 zero = gtNewDconNode(0.0);
6249 zero->gtType = type;
6253 zero = gtNewDconNode(0.0);
6257 assert(!"Bad type");
6264 GenTreePtr Compiler::gtNewOneConNode(var_types type)
6270 return gtNewIconNode(1);
6274 return gtNewLconNode(1);
6278 GenTreePtr one = gtNewDconNode(1.0);
6284 return gtNewDconNode(1.0);
6287 assert(!"Bad type");
6292 GenTreeCall* Compiler::gtNewIndCallNode(GenTreePtr addr, var_types type, GenTreeArgList* args, IL_OFFSETX ilOffset)
6294 return gtNewCallNode(CT_INDIRECT, (CORINFO_METHOD_HANDLE)addr, type, args, ilOffset);
6297 GenTreeCall* Compiler::gtNewCallNode(
6298 gtCallTypes callType, CORINFO_METHOD_HANDLE callHnd, var_types type, GenTreeArgList* args, IL_OFFSETX ilOffset)
6300 GenTreeCall* node = new (this, GT_CALL) GenTreeCall(genActualType(type));
6302 node->gtFlags |= (GTF_CALL | GTF_GLOB_REF);
6305 node->gtFlags |= (args->gtFlags & GTF_ALL_EFFECT);
6307 node->gtCallType = callType;
6308 node->gtCallMethHnd = callHnd;
6309 node->gtCallArgs = args;
6310 node->gtCallObjp = nullptr;
6311 node->fgArgInfo = nullptr;
6312 node->callSig = nullptr;
6313 node->gtRetClsHnd = nullptr;
6314 node->gtControlExpr = nullptr;
6315 node->gtCallMoreFlags = 0;
6317 if (callType == CT_INDIRECT)
6319 node->gtCallCookie = nullptr;
6323 node->gtInlineCandidateInfo = nullptr;
6325 node->gtCallLateArgs = nullptr;
6326 node->gtReturnType = type;
6328 #ifdef LEGACY_BACKEND
6329 node->gtCallRegUsedMask = RBM_NONE;
6330 #endif // LEGACY_BACKEND
6332 #ifdef FEATURE_READYTORUN_COMPILER
6333 node->gtCall.gtEntryPoint.addr = nullptr;
6336 #if defined(DEBUG) || defined(INLINE_DATA)
6337 // These get updated after call node is built.
6338 node->gtCall.gtInlineObservation = InlineObservation::CALLEE_UNUSED_INITIAL;
6339 node->gtCall.gtRawILOffset = BAD_IL_OFFSET;
6342 #ifdef DEBUGGING_SUPPORT
6343 // Spec: Managed Retval sequence points needs to be generated while generating debug info for debuggable code.
6345 // Implementation note: if not generating MRV info genCallSite2ILOffsetMap will be NULL and
6346 // codegen will pass BAD_IL_OFFSET as IL offset of a call node to emitter, which will cause emitter
6347 // not to emit IP mapping entry.
6348 if (opts.compDbgCode && opts.compDbgInfo)
6350 // Managed Retval - IL offset of the call. This offset is used to emit a
6351 // CALL_INSTRUCTION type sequence point while emitting corresponding native call.
6354 // a) (Opt) We need not store this offset if the method doesn't return a
6355 // value. Rather it can be made BAD_IL_OFFSET to prevent a sequence
6356 // point being emitted.
6358 // b) (Opt) Add new sequence points only if requested by debugger through
6359 // a new boundary type - ICorDebugInfo::BoundaryTypes
6360 if (genCallSite2ILOffsetMap == nullptr)
6362 genCallSite2ILOffsetMap = new (getAllocator()) CallSiteILOffsetTable(getAllocator());
6365 // Make sure that there are no duplicate entries for a given call node
6367 assert(!genCallSite2ILOffsetMap->Lookup(node, &value));
6368 genCallSite2ILOffsetMap->Set(node, ilOffset);
6372 // Initialize gtOtherRegs
6373 node->ClearOtherRegs();
6375 // Initialize spill flags of gtOtherRegs
6376 node->ClearOtherRegFlags();
6381 GenTreePtr Compiler::gtNewLclvNode(unsigned lnum, var_types type, IL_OFFSETX ILoffs)
6383 // We need to ensure that all struct values are normalized.
6384 // It might be nice to assert this in general, but we have assignments of int to long.
6385 if (varTypeIsStruct(type))
6387 assert(type == lvaTable[lnum].lvType);
6389 GenTreePtr node = new (this, GT_LCL_VAR) GenTreeLclVar(type, lnum, ILoffs);
6391 /* Cannot have this assert because the inliner uses this function
6392 * to add temporaries */
6394 // assert(lnum < lvaCount);
6399 GenTreePtr Compiler::gtNewLclLNode(unsigned lnum, var_types type, IL_OFFSETX ILoffs)
6401 // We need to ensure that all struct values are normalized.
6402 // It might be nice to assert this in general, but we have assignments of int to long.
6403 if (varTypeIsStruct(type))
6405 assert(type == lvaTable[lnum].lvType);
6407 #if SMALL_TREE_NODES
6408 /* This local variable node may later get transformed into a large node */
6410 // assert(GenTree::s_gtNodeSizes[GT_CALL] > GenTree::s_gtNodeSizes[GT_LCL_VAR]);
6412 GenTreePtr node = new (this, GT_CALL) GenTreeLclVar(type, lnum, ILoffs DEBUGARG(/*largeNode*/ true));
6414 GenTreePtr node = new (this, GT_LCL_VAR) GenTreeLclVar(type, lnum, ILoffs DEBUGARG(/*largeNode*/ true));
6420 GenTreeLclFld* Compiler::gtNewLclFldNode(unsigned lnum, var_types type, unsigned offset)
6422 GenTreeLclFld* node = new (this, GT_LCL_FLD) GenTreeLclFld(type, lnum, offset);
6424 /* Cannot have this assert because the inliner uses this function
6425 * to add temporaries */
6427 // assert(lnum < lvaCount);
6429 node->gtFieldSeq = FieldSeqStore::NotAField();
6433 GenTreePtr Compiler::gtNewInlineCandidateReturnExpr(GenTreePtr inlineCandidate, var_types type)
6435 assert(GenTree::s_gtNodeSizes[GT_RET_EXPR] == TREE_NODE_SZ_LARGE);
6437 GenTreePtr node = new (this, GT_RET_EXPR) GenTreeRetExpr(type);
6439 node->gtRetExpr.gtInlineCandidate = inlineCandidate;
6441 if (varTypeIsStruct(inlineCandidate))
6443 node->gtRetExpr.gtRetClsHnd = gtGetStructHandle(inlineCandidate);
6446 // GT_RET_EXPR node eventually might be bashed back to GT_CALL (when inlining is aborted for example).
6447 // Therefore it should carry the GTF_CALL flag so that all the rules about spilling can apply to it as well.
6448 // For example, impImportLeave or CEE_POP need to spill GT_RET_EXPR before empty the evaluation stack.
6449 node->gtFlags |= GTF_CALL;
6454 GenTreeArgList* Compiler::gtNewListNode(GenTreePtr op1, GenTreeArgList* op2)
6456 assert((op1 != nullptr) && (op1->OperGet() != GT_LIST));
6458 return new (this, GT_LIST) GenTreeArgList(op1, op2);
6461 /*****************************************************************************
6463 * Create a list out of one value.
6466 GenTreeArgList* Compiler::gtNewArgList(GenTreePtr arg)
6468 return new (this, GT_LIST) GenTreeArgList(arg);
6471 /*****************************************************************************
6473 * Create a list out of the two values.
6476 GenTreeArgList* Compiler::gtNewArgList(GenTreePtr arg1, GenTreePtr arg2)
6478 return new (this, GT_LIST) GenTreeArgList(arg1, gtNewArgList(arg2));
6481 //------------------------------------------------------------------------
6482 // Compiler::gtNewAggregate:
6483 // Creates a new aggregate argument node. These nodes are used to
6484 // represent arguments that are composed of multiple values (e.g.
6485 // the lclVars that represent the fields of a promoted struct).
6487 // Note that aggregate arguments are currently represented by GT_LIST
6488 // nodes that are marked with the GTF_LIST_AGGREGATE flag. This
6489 // representation may be changed in the future to instead use its own
6490 // node type (e.g. GT_AGGREGATE).
6493 // firstElement - The first element in the aggregate's list of values.
6496 // The newly-created aggregate node.
6497 GenTreeArgList* Compiler::gtNewAggregate(GenTree* firstElement)
6499 GenTreeArgList* agg = gtNewArgList(firstElement);
6500 agg->gtFlags |= GTF_LIST_AGGREGATE;
6504 /*****************************************************************************
6506 * Create a list out of the three values.
6509 GenTreeArgList* Compiler::gtNewArgList(GenTreePtr arg1, GenTreePtr arg2, GenTreePtr arg3)
6511 return new (this, GT_LIST) GenTreeArgList(arg1, gtNewArgList(arg2, arg3));
6514 /*****************************************************************************
6516 * Given a GT_CALL node, access the fgArgInfo and find the entry
6517 * that has the matching argNum and return the fgArgTableEntryPtr
6520 fgArgTabEntryPtr Compiler::gtArgEntryByArgNum(GenTreePtr call, unsigned argNum)
6522 noway_assert(call->IsCall());
6523 fgArgInfoPtr argInfo = call->gtCall.fgArgInfo;
6524 noway_assert(argInfo != nullptr);
6526 unsigned argCount = argInfo->ArgCount();
6527 fgArgTabEntryPtr* argTable = argInfo->ArgTable();
6528 fgArgTabEntryPtr curArgTabEntry = nullptr;
6530 for (unsigned i = 0; i < argCount; i++)
6532 curArgTabEntry = argTable[i];
6533 if (curArgTabEntry->argNum == argNum)
6535 return curArgTabEntry;
6538 noway_assert(!"gtArgEntryByArgNum: argNum not found");
6542 /*****************************************************************************
6544 * Given a GT_CALL node, access the fgArgInfo and find the entry
6545 * that has the matching node and return the fgArgTableEntryPtr
6548 fgArgTabEntryPtr Compiler::gtArgEntryByNode(GenTreePtr call, GenTreePtr node)
6550 noway_assert(call->IsCall());
6551 fgArgInfoPtr argInfo = call->gtCall.fgArgInfo;
6552 noway_assert(argInfo != nullptr);
6554 unsigned argCount = argInfo->ArgCount();
6555 fgArgTabEntryPtr* argTable = argInfo->ArgTable();
6556 fgArgTabEntryPtr curArgTabEntry = nullptr;
6558 for (unsigned i = 0; i < argCount; i++)
6560 curArgTabEntry = argTable[i];
6562 if (curArgTabEntry->node == node)
6564 return curArgTabEntry;
6567 else if (node->OperGet() == GT_RELOAD && node->gtOp.gtOp1 == curArgTabEntry->node)
6569 return curArgTabEntry;
6572 else if (curArgTabEntry->parent != nullptr)
6574 assert(curArgTabEntry->parent->IsList());
6575 if (curArgTabEntry->parent->Current() == node)
6577 return curArgTabEntry;
6580 else // (curArgTabEntry->parent == NULL)
6582 if (call->gtCall.gtCallObjp == node)
6584 return curArgTabEntry;
6588 noway_assert(!"gtArgEntryByNode: node not found");
6592 /*****************************************************************************
6594 * Find and return the entry with the given "lateArgInx". Requires that one is found
6597 fgArgTabEntryPtr Compiler::gtArgEntryByLateArgIndex(GenTreePtr call, unsigned lateArgInx)
6599 noway_assert(call->IsCall());
6600 fgArgInfoPtr argInfo = call->gtCall.fgArgInfo;
6601 noway_assert(argInfo != nullptr);
6603 unsigned argCount = argInfo->ArgCount();
6604 fgArgTabEntryPtr* argTable = argInfo->ArgTable();
6605 fgArgTabEntryPtr curArgTabEntry = nullptr;
6607 for (unsigned i = 0; i < argCount; i++)
6609 curArgTabEntry = argTable[i];
6610 if (curArgTabEntry->lateArgInx == lateArgInx)
6612 return curArgTabEntry;
6615 noway_assert(!"gtArgEntryByNode: node not found");
6619 /*****************************************************************************
6621 * Given an fgArgTabEntryPtr, return true if it is the 'this' pointer argument.
6623 bool Compiler::gtArgIsThisPtr(fgArgTabEntryPtr argEntry)
6625 return (argEntry->parent == nullptr);
6628 /*****************************************************************************
6630 * Create a node that will assign 'src' to 'dst'.
6633 GenTreePtr Compiler::gtNewAssignNode(GenTreePtr dst, GenTreePtr src)
6635 /* Mark the target as being assigned */
6637 if ((dst->gtOper == GT_LCL_VAR) || (dst->OperGet() == GT_LCL_FLD))
6639 dst->gtFlags |= GTF_VAR_DEF;
6640 if (dst->IsPartialLclFld(this))
6642 // We treat these partial writes as combined uses and defs.
6643 dst->gtFlags |= GTF_VAR_USEASG;
6646 dst->gtFlags |= GTF_DONT_CSE;
6648 /* Create the assignment node */
6650 GenTreePtr asg = gtNewOperNode(GT_ASG, dst->TypeGet(), dst, src);
6652 /* Mark the expression as containing an assignment */
6654 asg->gtFlags |= GTF_ASG;
6659 // Creates a new Obj node.
6660 GenTreeObj* Compiler::gtNewObjNode(CORINFO_CLASS_HANDLE structHnd, GenTree* addr)
6662 var_types nodeType = impNormStructType(structHnd);
6663 assert(varTypeIsStruct(nodeType));
6664 GenTreeObj* objNode = new (this, GT_OBJ) GenTreeObj(nodeType, addr, structHnd);
6665 // An Obj is not a global reference, if it is known to be a local struct.
6666 GenTreeLclVarCommon* lclNode = addr->IsLocalAddrExpr();
6667 if ((lclNode != nullptr) && !lvaIsImplicitByRefLocal(lclNode->gtLclNum))
6669 objNode->gtFlags &= ~GTF_GLOB_REF;
6674 // Creates a new CpObj node.
6675 // Parameters (exactly the same as MSIL CpObj):
6677 // dst - The target to copy the struct to
6678 // src - The source to copy the struct from
6679 // structHnd - A class token that represents the type of object being copied. May be null
6680 // if FEATURE_SIMD is enabled and the source has a SIMD type.
6681 // isVolatile - Is this marked as volatile memory?
6682 GenTreeBlkOp* Compiler::gtNewCpObjNode(GenTreePtr dst, GenTreePtr src, CORINFO_CLASS_HANDLE structHnd, bool isVolatile)
6686 unsigned gcPtrCount = 0;
6687 BYTE* gcPtrs = nullptr;
6688 var_types type = TYP_STRUCT;
6690 GenTreePtr hndOrSize = nullptr;
6692 GenTreeBlkOp* result = nullptr;
6694 bool useCopyObj = false;
6696 // Intermediate SIMD operations may use SIMD types that are not used by the input IL.
6697 // In this case, the provided type handle will be null and the size of the copy will
6698 // be derived from the node's varType.
6699 if (structHnd == nullptr)
6702 assert(src->OperGet() == GT_ADDR);
6704 GenTree* srcValue = src->gtGetOp1();
6706 type = srcValue->TypeGet();
6707 assert(varTypeIsSIMD(type));
6709 size = genTypeSize(type);
6711 assert(!"structHnd should not be null if FEATURE_SIMD is not enabled!");
6716 // Get the size of the type
6717 size = info.compCompHnd->getClassSize(structHnd);
6719 if (size >= TARGET_POINTER_SIZE)
6721 slots = (unsigned)(roundUp(size, TARGET_POINTER_SIZE) / TARGET_POINTER_SIZE);
6722 gcPtrs = new (this, CMK_ASTNode) BYTE[slots];
6724 type = impNormStructType(structHnd, gcPtrs, &gcPtrCount);
6725 if (varTypeIsEnregisterableStruct(type))
6727 if (dst->OperGet() == GT_ADDR)
6729 GenTree* actualDst = dst->gtGetOp1();
6730 assert((actualDst->TypeGet() == type) || !varTypeIsEnregisterableStruct(actualDst));
6731 actualDst->gtType = type;
6733 if (src->OperGet() == GT_ADDR)
6735 GenTree* actualSrc = src->gtGetOp1();
6736 assert((actualSrc->TypeGet() == type) || !varTypeIsEnregisterableStruct(actualSrc));
6737 actualSrc->gtType = type;
6741 useCopyObj = gcPtrCount > 0;
6745 // If the class being copied contains any GC pointer we store a class handle
6746 // in the icon, otherwise we store the size in bytes to copy
6751 // This will treated as a cpobj as we need to note GC info.
6752 // Store the class handle and mark the node
6754 hndOrSize = gtNewIconHandleNode((size_t)structHnd, GTF_ICON_CLASS_HDL);
6755 result = new (this, GT_COPYOBJ) GenTreeCpObj(gcPtrCount, slots, gcPtrs);
6759 assert(gcPtrCount == 0);
6761 // Doesn't need GC info. Treat operation as a cpblk
6763 hndOrSize = gtNewIconNode(size);
6764 result = new (this, GT_COPYBLK) GenTreeCpBlk();
6765 result->gtBlkOpGcUnsafe = false;
6768 gtBlockOpInit(result, op, dst, src, hndOrSize, isVolatile);
6772 //------------------------------------------------------------------------
6773 // FixupInitBlkValue: Fixup the init value for an initBlk operation
6776 // asgType - The type of assignment that the initBlk is being transformed into
6779 // Modifies the constant value on this node to be the appropriate "fill"
6780 // value for the initblk.
6783 // The initBlk MSIL instruction takes a byte value, which must be
6784 // extended to the size of the assignment when an initBlk is transformed
6785 // to an assignment of a primitive type.
6786 // This performs the appropriate extension.
6788 void GenTreeIntCon::FixupInitBlkValue(var_types asgType)
6790 assert(varTypeIsIntegralOrI(asgType));
6791 unsigned size = genTypeSize(asgType);
6794 size_t cns = gtIconVal;
6800 #ifdef _TARGET_64BIT_
6805 #endif // _TARGET_64BIT_
6807 // Make the type used in the GT_IND node match for evaluation types.
6810 // if we are using an GT_INITBLK on a GC type the value being assigned has to be zero (null).
6811 assert(!varTypeIsGC(asgType) || (cns == 0));
6818 // Initializes a BlkOp GenTree
6820 // - Result is a GenTreeBlkOp that is newly constructed by gtNewCpObjNode or gtNewBlkOpNode
6823 // - result is a GenTreeBlkOp node that is the node to be initialized.
6824 // - oper must be either GT_INITBLK or GT_COPYBLK
6825 // - dst is the target (destination) we want to either initialize or copy to
6826 // - src is the init value for IniBlk or the source struct for CpBlk/CpObj
6827 // - size is either the size of the buffer to copy/initialize or a class token
6828 // in the case of CpObj.
6829 // - volatil flag specifies if this node is a volatile memory operation.
6831 // This procedure centralizes all the logic to both enforce proper structure and
6832 // to properly construct any InitBlk/CpBlk node.
6833 void Compiler::gtBlockOpInit(
6834 GenTreePtr result, genTreeOps oper, GenTreePtr dst, GenTreePtr srcOrFillVal, GenTreePtr hndOrSize, bool volatil)
6836 assert(GenTree::OperIsBlkOp(oper));
6838 assert(result->gtType == TYP_VOID);
6839 result->gtOper = oper;
6842 // If this is a CpObj node, the caller must have already set
6843 // the node additional members (gtGcPtrs, gtGcPtrCount, gtSlots).
6844 if (hndOrSize->OperGet() == GT_CNS_INT && hndOrSize->IsIconHandle(GTF_ICON_CLASS_HDL))
6846 GenTreeCpObj* cpObjNode = result->AsCpObj();
6848 assert(cpObjNode->gtGcPtrs != nullptr);
6849 assert(!IsUninitialized(cpObjNode->gtGcPtrs));
6850 assert(!IsUninitialized(cpObjNode->gtGcPtrCount) && cpObjNode->gtGcPtrCount > 0);
6851 assert(!IsUninitialized(cpObjNode->gtSlots) && cpObjNode->gtSlots > 0);
6853 for (unsigned i = 0; i < cpObjNode->gtGcPtrCount; ++i)
6855 CorInfoGCType t = (CorInfoGCType)cpObjNode->gtGcPtrs[i];
6870 /* In the case of CpBlk, we want to avoid generating
6871 * nodes where the source and destination are the same
6872 * because of two reasons, first, is useless, second
6873 * it introduces issues in liveness and also copying
6874 * memory from an overlapping memory location is
6875 * undefined both as per the ECMA standard and also
6876 * the memcpy semantics specify that.
6878 * NOTE: In this case we'll only detect the case for addr of a local
6879 * and a local itself, any other complex expressions won't be
6882 * TODO-Cleanup: though having this logic is goodness (i.e. avoids self-assignment
6883 * of struct vars very early), it was added because fgInterBlockLocalVarLiveness()
6884 * isn't handling self-assignment of struct variables correctly. This issue may not
6885 * surface if struct promotion is ON (which is the case on x86/arm). But still the
6886 * fundamental issue exists that needs to be addressed.
6888 GenTreePtr currSrc = srcOrFillVal;
6889 GenTreePtr currDst = dst;
6890 if (currSrc->OperGet() == GT_ADDR && currDst->OperGet() == GT_ADDR)
6892 currSrc = currSrc->gtOp.gtOp1;
6893 currDst = currDst->gtOp.gtOp1;
6896 if (currSrc->OperGet() == GT_LCL_VAR && currDst->OperGet() == GT_LCL_VAR &&
6897 currSrc->gtLclVarCommon.gtLclNum == currDst->gtLclVarCommon.gtLclNum)
6900 result->gtBashToNOP();
6904 /* Note that this use of a GT_LIST is different than all others */
6905 /* in that the the GT_LIST is used as a tuple [dest,src] rather */
6906 /* than a being a NULL terminated list of GT_LIST nodes */
6907 result->gtOp.gtOp1 = gtNewOperNode(GT_LIST, TYP_VOID, /* GT_[oper] */
6908 dst, srcOrFillVal); /* / \ */
6909 result->gtOp.gtOp2 = hndOrSize; /* GT_LIST \ */
6910 /* / \ [hndOrSize] */
6911 /* [dst] [srcOrFillVal] */
6913 // Propagate all effect flags from children
6914 result->gtFlags |= result->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT;
6915 result->gtFlags |= result->gtOp.gtOp2->gtFlags & GTF_ALL_EFFECT;
6917 result->gtFlags |= (GTF_GLOB_REF | GTF_ASG);
6919 // REVERSE_OPS is necessary because the use must occur before the def
6920 result->gtOp.gtOp1->gtFlags |= GTF_REVERSE_OPS;
6922 if (result->gtOper == GT_INITBLK)
6924 result->gtFlags |= (dst->gtFlags & GTF_EXCEPT) | (hndOrSize->gtFlags & GTF_EXCEPT);
6929 (dst->gtFlags & GTF_EXCEPT) | (srcOrFillVal->gtFlags & GTF_EXCEPT) | (hndOrSize->gtFlags & GTF_EXCEPT);
6931 // If the class being copied contains any GC pointer we store a class handle
6932 // and we must set the flag GTF_BLK_HASGCPTR, so that the register predictor
6933 // knows that this GT_COPYBLK will use calls to the ByRef Assign helper
6935 if ((hndOrSize->OperGet() == GT_CNS_INT) && hndOrSize->IsIconHandle(GTF_ICON_CLASS_HDL))
6937 hndOrSize->gtFlags |= GTF_DONT_CSE; // We can't CSE the class handle
6938 result->gtFlags |= GTF_BLK_HASGCPTR;
6944 result->gtFlags |= GTF_BLK_VOLATILE;
6948 if (oper == GT_COPYBLK && srcOrFillVal->OperGet() == GT_ADDR && dst->OperGet() == GT_ADDR)
6950 // If the source is a GT_SIMD node of SIMD type, then the dst lclvar struct
6951 // should be labeled as simd intrinsic related struct.
6952 // This is done so that the morpher can transform any field accesses into
6953 // intrinsics, thus avoiding conflicting access methods (fields vs. whole-register).
6955 GenTreePtr srcChild = srcOrFillVal->gtGetOp1();
6956 GenTreePtr dstChild = dst->gtGetOp1();
6958 if (dstChild->OperIsLocal() && varTypeIsStruct(dstChild) && srcChild->OperGet() == GT_SIMD &&
6959 varTypeIsSIMD(srcChild))
6961 unsigned lclNum = dst->gtGetOp1()->AsLclVarCommon()->GetLclNum();
6962 LclVarDsc* lclVarDsc = &lvaTable[lclNum];
6963 lclVarDsc->lvUsedInSIMDIntrinsic = true;
6966 #endif // FEATURE_SIMD
6969 //------------------------------------------------------------------------
6970 // gtNewBlkOpNode: Creates an InitBlk or CpBlk node.
6973 // oper - GT_COPYBLK, GT_INITBLK or GT_COPYOBJ
6974 // dst - Destination or target to copy to / initialize the buffer.
6975 // srcOrFillVall - Either the source to copy from or the byte value to fill the buffer.
6976 // sizeOrClsTok - The size of the buffer or a class token (in the case of CpObj).
6977 // isVolatile - Whether this is a volatile memory operation or not.
6980 // Returns the newly constructed and initialized block operation.
6982 GenTreeBlkOp* Compiler::gtNewBlkOpNode(
6983 genTreeOps oper, GenTreePtr dst, GenTreePtr srcOrFillVal, GenTreePtr sizeOrClsTok, bool isVolatile)
6985 GenTreeBlkOp* result = new (this, oper) GenTreeBlkOp(oper);
6986 gtBlockOpInit(result, oper, dst, srcOrFillVal, sizeOrClsTok, isVolatile);
6990 /*****************************************************************************
6992 * Clones the given tree value and returns a copy of the given tree.
6993 * If 'complexOK' is false, the cloning is only done provided the tree
6994 * is not too complex (whatever that may mean);
6995 * If 'complexOK' is true, we try slightly harder to clone the tree.
6996 * In either case, NULL is returned if the tree cannot be cloned
6998 * Note that there is the function gtCloneExpr() which does a more
6999 * complete job if you can't handle this function failing.
7002 GenTreePtr Compiler::gtClone(GenTree* tree, bool complexOK)
7006 switch (tree->gtOper)
7010 #if defined(LATE_DISASM)
7011 if (tree->IsIconHandle())
7013 copy = gtNewIconHandleNode(tree->gtIntCon.gtIconVal, tree->gtFlags, tree->gtIntCon.gtFieldSeq,
7014 tree->gtIntCon.gtIconHdl.gtIconHdl1, tree->gtIntCon.gtIconHdl.gtIconHdl2);
7015 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
7016 copy->gtType = tree->gtType;
7021 copy = new (this, GT_CNS_INT)
7022 GenTreeIntCon(tree->gtType, tree->gtIntCon.gtIconVal, tree->gtIntCon.gtFieldSeq);
7023 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
7028 // Remember that the LclVar node has been cloned. The flag will be set
7029 // on 'copy' as well.
7030 tree->gtFlags |= GTF_VAR_CLONED;
7031 copy = gtNewLclvNode(tree->gtLclVarCommon.gtLclNum, tree->gtType, tree->gtLclVar.gtLclILoffs);
7035 case GT_LCL_FLD_ADDR:
7036 // Remember that the LclVar node has been cloned. The flag will be set
7037 // on 'copy' as well.
7038 tree->gtFlags |= GTF_VAR_CLONED;
7039 copy = new (this, tree->gtOper)
7040 GenTreeLclFld(tree->gtOper, tree->TypeGet(), tree->gtLclFld.gtLclNum, tree->gtLclFld.gtLclOffs);
7041 copy->gtLclFld.gtFieldSeq = tree->gtLclFld.gtFieldSeq;
7045 copy = new (this, GT_CLS_VAR)
7046 GenTreeClsVar(tree->gtType, tree->gtClsVar.gtClsVarHnd, tree->gtClsVar.gtFieldSeq);
7050 assert(!"clone regvar");
7058 if (tree->gtOper == GT_FIELD)
7062 // copied from line 9850
7065 if (tree->gtField.gtFldObj)
7067 objp = gtClone(tree->gtField.gtFldObj, false);
7074 copy = gtNewFieldRef(tree->TypeGet(), tree->gtField.gtFldHnd, objp, tree->gtField.gtFldOffset);
7075 copy->gtField.gtFldMayOverlap = tree->gtField.gtFldMayOverlap;
7077 else if (tree->gtOper == GT_ADD)
7079 GenTreePtr op1 = tree->gtOp.gtOp1;
7080 GenTreePtr op2 = tree->gtOp.gtOp2;
7082 if (op1->OperIsLeaf() && op2->OperIsLeaf())
7095 copy = gtNewOperNode(GT_ADD, tree->TypeGet(), op1, op2);
7102 else if (tree->gtOper == GT_ADDR)
7104 GenTreePtr op1 = gtClone(tree->gtOp.gtOp1);
7109 copy = gtNewOperNode(GT_ADDR, tree->TypeGet(), op1);
7119 copy->gtFlags |= tree->gtFlags & ~GTF_NODE_MASK;
7121 copy->gtDebugFlags |= tree->gtDebugFlags & ~GTF_DEBUG_NODE_MASK;
7122 #endif // defined(DEBUG)
7127 /*****************************************************************************
7129 * Clones the given tree value and returns a copy of the given tree. Any
7130 * references to local variable varNum will be replaced with the integer
7134 GenTreePtr Compiler::gtCloneExpr(GenTree* tree,
7136 unsigned varNum, // = (unsigned)-1
7139 if (tree == nullptr)
7144 /* Figure out what kind of a node we have */
7146 genTreeOps oper = tree->OperGet();
7147 unsigned kind = tree->OperKind();
7150 /* Is this a constant or leaf node? */
7152 if (kind & (GTK_CONST | GTK_LEAF))
7158 #if defined(LATE_DISASM)
7159 if (tree->IsIconHandle())
7161 copy = gtNewIconHandleNode(tree->gtIntCon.gtIconVal, tree->gtFlags, tree->gtIntCon.gtFieldSeq,
7162 tree->gtIntCon.gtIconFld.gtIconCPX, tree->gtIntCon.gtIconFld.gtIconCls);
7163 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
7164 copy->gtType = tree->gtType;
7169 copy = gtNewIconNode(tree->gtIntCon.gtIconVal, tree->gtType);
7170 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
7171 copy->gtIntCon.gtFieldSeq = tree->gtIntCon.gtFieldSeq;
7176 copy = gtNewLconNode(tree->gtLngCon.gtLconVal);
7180 copy = gtNewDconNode(tree->gtDblCon.gtDconVal);
7181 copy->gtType = tree->gtType; // keep the same type
7185 copy = gtNewSconNode(tree->gtStrCon.gtSconCPX, tree->gtStrCon.gtScpHnd);
7190 if (tree->gtLclVarCommon.gtLclNum == varNum)
7192 copy = gtNewIconNode(varVal, tree->gtType);
7196 // Remember that the LclVar node has been cloned. The flag will
7197 // be set on 'copy' as well.
7198 tree->gtFlags |= GTF_VAR_CLONED;
7199 copy = gtNewLclvNode(tree->gtLclVar.gtLclNum, tree->gtType, tree->gtLclVar.gtLclILoffs);
7200 copy->AsLclVarCommon()->SetSsaNum(tree->AsLclVarCommon()->GetSsaNum());
7202 copy->gtFlags = tree->gtFlags;
7206 if (tree->gtLclFld.gtLclNum == varNum)
7208 IMPL_LIMITATION("replacing GT_LCL_FLD with a constant");
7212 // Remember that the LclVar node has been cloned. The flag will
7213 // be set on 'copy' as well.
7214 tree->gtFlags |= GTF_VAR_CLONED;
7215 copy = new (this, GT_LCL_FLD)
7216 GenTreeLclFld(tree->TypeGet(), tree->gtLclFld.gtLclNum, tree->gtLclFld.gtLclOffs);
7217 copy->gtLclFld.gtFieldSeq = tree->gtLclFld.gtFieldSeq;
7218 copy->gtFlags = tree->gtFlags;
7223 copy = new (this, GT_CLS_VAR)
7224 GenTreeClsVar(tree->TypeGet(), tree->gtClsVar.gtClsVarHnd, tree->gtClsVar.gtFieldSeq);
7228 copy = gtNewInlineCandidateReturnExpr(tree->gtRetExpr.gtInlineCandidate, tree->gtType);
7231 case GT_MEMORYBARRIER:
7232 copy = new (this, GT_MEMORYBARRIER) GenTree(GT_MEMORYBARRIER, TYP_VOID);
7236 copy = gtNewArgPlaceHolderNode(tree->gtType, tree->gtArgPlace.gtArgPlaceClsHnd);
7240 NO_WAY("Cloning of GT_REG_VAR node not supported");
7244 copy = new (this, oper) GenTreeFptrVal(tree->gtType, tree->gtFptrVal.gtFptrMethod);
7246 #ifdef FEATURE_READYTORUN_COMPILER
7247 copy->gtFptrVal.gtEntryPoint = tree->gtFptrVal.gtEntryPoint;
7248 copy->gtFptrVal.gtLdftnResolvedToken = tree->gtFptrVal.gtLdftnResolvedToken;
7254 copy = new (this, oper) GenTree(oper, tree->gtType);
7257 #if !FEATURE_EH_FUNCLETS
7259 #endif // !FEATURE_EH_FUNCLETS
7261 copy = new (this, oper) GenTreeVal(oper, tree->gtType, tree->gtVal.gtVal1);
7265 copy = new (this, oper) GenTreeLabel(tree->gtLabel.gtLabBB);
7269 NO_WAY("Cloning of node not supported");
7274 /* Is it a 'simple' unary/binary operator? */
7276 if (kind & GTK_SMPOP)
7278 /* If necessary, make sure we allocate a "fat" tree node */
7279 CLANG_FORMAT_COMMENT_ANCHOR;
7281 #if SMALL_TREE_NODES
7284 /* These nodes sometimes get bashed to "fat" ones */
7293 // In the implementation of gtNewLargeOperNode you have
7294 // to give an oper that will create a small node,
7295 // otherwise it asserts.
7297 if (GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL)
7299 copy = gtNewLargeOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1,
7300 tree->OperIsBinary() ? tree->gtOp.gtOp2 : nullptr);
7302 else // Always a large tree
7304 if (tree->OperIsBinary())
7306 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2);
7310 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1);
7316 copy = new (this, LargeOpOpcode()) GenTreeCast(tree->TypeGet(), tree->gtCast.CastOp(),
7317 tree->gtCast.gtCastType DEBUGARG(/*largeNode*/ TRUE));
7320 // The nodes below this are not bashed, so they can be allocated at their individual sizes.
7323 // This is ridiculous, but would go away if we made a stronger distinction between argument lists, whose
7324 // second argument *must* be an arglist*, and the uses of LIST in copyblk and initblk.
7325 if (tree->gtOp.gtOp2 != nullptr && tree->gtOp.gtOp2->OperGet() == GT_LIST)
7327 copy = new (this, GT_LIST) GenTreeArgList(tree->gtOp.gtOp1, tree->gtOp.gtOp2->AsArgList());
7331 copy = new (this, GT_LIST) GenTreeOp(GT_LIST, TYP_VOID, tree->gtOp.gtOp1, tree->gtOp.gtOp2);
7337 GenTreeIndex* asInd = tree->AsIndex();
7338 copy = new (this, GT_INDEX)
7339 GenTreeIndex(asInd->TypeGet(), asInd->Arr(), asInd->Index(), asInd->gtIndElemSize);
7340 copy->AsIndex()->gtStructElemClass = asInd->gtStructElemClass;
7346 GenTreeAllocObj* asAllocObj = tree->AsAllocObj();
7347 copy = new (this, GT_ALLOCOBJ) GenTreeAllocObj(tree->TypeGet(), asAllocObj->gtNewHelper,
7348 asAllocObj->gtAllocObjClsHnd, asAllocObj->gtOp1);
7353 copy = new (this, GT_ARR_LENGTH)
7354 GenTreeArrLen(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtArrLen.ArrLenOffset());
7358 copy = new (this, GT_ARR_INDEX)
7359 GenTreeArrIndex(tree->TypeGet(), gtCloneExpr(tree->gtArrIndex.ArrObj(), addFlags, varNum, varVal),
7360 gtCloneExpr(tree->gtArrIndex.IndexExpr(), addFlags, varNum, varVal),
7361 tree->gtArrIndex.gtCurrDim, tree->gtArrIndex.gtArrRank,
7362 tree->gtArrIndex.gtArrElemType);
7366 copy = new (this, GT_QMARK) GenTreeQmark(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2, this);
7367 VarSetOps::AssignAllowUninitRhs(this, copy->gtQmark.gtThenLiveSet, tree->gtQmark.gtThenLiveSet);
7368 VarSetOps::AssignAllowUninitRhs(this, copy->gtQmark.gtElseLiveSet, tree->gtQmark.gtElseLiveSet);
7372 copy = new (this, GT_OBJ) GenTreeObj(tree->TypeGet(), tree->gtOp.gtOp1, tree->AsObj()->gtClass);
7376 copy = new (this, GT_BOX)
7377 GenTreeBox(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtBox.gtAsgStmtWhenInlinedBoxValue);
7381 copy = new (this, GT_INTRINSIC)
7382 GenTreeIntrinsic(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2,
7383 tree->gtIntrinsic.gtIntrinsicId, tree->gtIntrinsic.gtMethodHandle);
7384 #ifdef FEATURE_READYTORUN_COMPILER
7385 copy->gtIntrinsic.gtEntryPoint = tree->gtIntrinsic.gtEntryPoint;
7391 GenTreeCpObj* cpObjOp = tree->AsCpObj();
7392 assert(cpObjOp->gtGcPtrCount > 0);
7393 copy = gtCloneCpObjNode(cpObjOp);
7399 GenTreeInitBlk* initBlkOp = tree->AsInitBlk();
7400 copy = gtNewBlkOpNode(oper, initBlkOp->Dest(), initBlkOp->InitVal(), initBlkOp->Size(),
7401 initBlkOp->IsVolatile());
7407 GenTreeCpBlk* cpBlkOp = tree->AsCpBlk();
7408 copy = gtNewBlkOpNode(oper, cpBlkOp->Dest(), cpBlkOp->Source(), cpBlkOp->Size(), cpBlkOp->IsVolatile());
7409 copy->AsCpBlk()->gtBlkOpGcUnsafe = cpBlkOp->gtBlkOpGcUnsafe;
7415 GenTreeAddrMode* addrModeOp = tree->AsAddrMode();
7417 new (this, GT_LEA) GenTreeAddrMode(addrModeOp->TypeGet(), addrModeOp->Base(), addrModeOp->Index(),
7418 addrModeOp->gtScale, addrModeOp->gtOffset);
7425 copy = new (this, oper) GenTreeCopyOrReload(oper, tree->TypeGet(), tree->gtGetOp1());
7432 GenTreeSIMD* simdOp = tree->AsSIMD();
7433 copy = gtNewSIMDNode(simdOp->TypeGet(), simdOp->gtGetOp1(), simdOp->gtGetOp2(),
7434 simdOp->gtSIMDIntrinsicID, simdOp->gtSIMDBaseType, simdOp->gtSIMDSize);
7440 assert(!GenTree::IsExOp(tree->OperKind()) && tree->OperIsSimple());
7441 // We're in the SimpleOp case, so it's always unary or binary.
7442 if (GenTree::OperIsUnary(tree->OperGet()))
7444 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, /*doSimplifications*/ false);
7448 assert(GenTree::OperIsBinary(tree->OperGet()));
7449 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2);
7454 // We're in the SimpleOp case, so it's always unary or binary.
7455 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2);
7458 // Some flags are conceptually part of the gtOper, and should be copied immediately.
7459 if (tree->gtOverflowEx())
7461 copy->gtFlags |= GTF_OVERFLOW;
7463 if (copy->OperGet() == GT_CAST)
7465 copy->gtFlags |= (tree->gtFlags & GTF_UNSIGNED);
7468 if (tree->gtOp.gtOp1)
7470 copy->gtOp.gtOp1 = gtCloneExpr(tree->gtOp.gtOp1, addFlags, varNum, varVal);
7473 if (tree->gtGetOp2())
7475 copy->gtOp.gtOp2 = gtCloneExpr(tree->gtOp.gtOp2, addFlags, varNum, varVal);
7479 addFlags |= tree->gtFlags;
7481 // Copy any node annotations, if necessary.
7482 switch (tree->gtOper)
7486 IndirectAssignmentAnnotation* pIndirAnnot = nullptr;
7487 if (m_indirAssignMap != nullptr && GetIndirAssignMap()->Lookup(tree, &pIndirAnnot))
7489 IndirectAssignmentAnnotation* pNewIndirAnnot = new (this, CMK_Unknown)
7490 IndirectAssignmentAnnotation(pIndirAnnot->m_lclNum, pIndirAnnot->m_fieldSeq,
7491 pIndirAnnot->m_isEntire);
7492 GetIndirAssignMap()->Set(copy, pNewIndirAnnot);
7499 if (tree->gtFlags & GTF_IND_ARR_INDEX)
7502 bool b = GetArrayInfoMap()->Lookup(tree, &arrInfo);
7504 GetArrayInfoMap()->Set(copy, arrInfo);
7513 /* GTF_NODE_MASK should not be propagated from 'tree' to 'copy' */
7514 addFlags &= ~GTF_NODE_MASK;
7517 // Effects flags propagate upwards.
7518 if (copy->gtOp.gtOp1 != nullptr)
7520 copy->gtFlags |= (copy->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
7522 if (copy->gtGetOp2() != nullptr)
7524 copy->gtFlags |= (copy->gtGetOp2()->gtFlags & GTF_ALL_EFFECT);
7527 // The early morph for TailCall creates a GT_NOP with GTF_REG_VAL flag set
7528 // Thus we have to copy the gtRegNum/gtRegPair value if we clone it here.
7530 if (addFlags & GTF_REG_VAL)
7532 copy->CopyReg(tree);
7535 // We can call gtCloneExpr() before we have called fgMorph when we expand a GT_INDEX node in fgMorphArrayIndex()
7536 // The method gtFoldExpr() expects to be run after fgMorph so it will set the GTF_DEBUG_NODE_MORPHED
7537 // flag on nodes that it adds/modifies. Then when we call fgMorph we will assert.
7538 // We really only will need to fold when this method is used to replace references to
7539 // local variable with an integer.
7541 if (varNum != (unsigned)-1)
7543 /* Try to do some folding */
7544 copy = gtFoldExpr(copy);
7550 /* See what kind of a special operator we have here */
7555 copy = gtCloneExpr(tree->gtStmt.gtStmtExpr, addFlags, varNum, varVal);
7556 copy = gtNewStmt(copy, tree->gtStmt.gtStmtILoffsx);
7561 copy = new (this, GT_CALL) GenTreeCall(tree->TypeGet());
7563 copy->gtCall.gtCallObjp =
7564 tree->gtCall.gtCallObjp ? gtCloneExpr(tree->gtCall.gtCallObjp, addFlags, varNum, varVal) : nullptr;
7565 copy->gtCall.gtCallArgs = tree->gtCall.gtCallArgs
7566 ? gtCloneExpr(tree->gtCall.gtCallArgs, addFlags, varNum, varVal)->AsArgList()
7568 copy->gtCall.gtCallMoreFlags = tree->gtCall.gtCallMoreFlags;
7569 copy->gtCall.gtCallLateArgs =
7570 tree->gtCall.gtCallLateArgs
7571 ? gtCloneExpr(tree->gtCall.gtCallLateArgs, addFlags, varNum, varVal)->AsArgList()
7574 #if !FEATURE_FIXED_OUT_ARGS
7575 copy->gtCall.regArgList = tree->gtCall.regArgList;
7576 copy->gtCall.regArgListCount = tree->gtCall.regArgListCount;
7579 // The call sig comes from the EE and doesn't change throughout the compilation process, meaning
7580 // we only really need one physical copy of it. Therefore a shallow pointer copy will suffice.
7581 // (Note that this still holds even if the tree we are cloning was created by an inlinee compiler,
7582 // because the inlinee still uses the inliner's memory allocator anyway.)
7583 copy->gtCall.callSig = tree->gtCall.callSig;
7585 copy->gtCall.gtCallType = tree->gtCall.gtCallType;
7586 copy->gtCall.gtReturnType = tree->gtCall.gtReturnType;
7587 copy->gtCall.gtControlExpr = tree->gtCall.gtControlExpr;
7589 /* Copy the union */
7590 if (tree->gtCall.gtCallType == CT_INDIRECT)
7592 copy->gtCall.gtCallCookie = tree->gtCall.gtCallCookie
7593 ? gtCloneExpr(tree->gtCall.gtCallCookie, addFlags, varNum, varVal)
7595 copy->gtCall.gtCallAddr =
7596 tree->gtCall.gtCallAddr ? gtCloneExpr(tree->gtCall.gtCallAddr, addFlags, varNum, varVal) : nullptr;
7598 else if (tree->gtFlags & GTF_CALL_VIRT_STUB)
7600 copy->gtCall.gtCallMethHnd = tree->gtCall.gtCallMethHnd;
7601 copy->gtCall.gtStubCallStubAddr = tree->gtCall.gtStubCallStubAddr;
7605 copy->gtCall.gtCallMethHnd = tree->gtCall.gtCallMethHnd;
7606 copy->gtCall.gtInlineCandidateInfo = tree->gtCall.gtInlineCandidateInfo;
7609 if (tree->gtCall.fgArgInfo)
7611 // Create and initialize the fgArgInfo for our copy of the call tree
7612 copy->gtCall.fgArgInfo = new (this, CMK_Unknown) fgArgInfo(copy, tree);
7616 copy->gtCall.fgArgInfo = nullptr;
7618 copy->gtCall.gtRetClsHnd = tree->gtCall.gtRetClsHnd;
7620 #if FEATURE_MULTIREG_RET
7621 copy->gtCall.gtReturnTypeDesc = tree->gtCall.gtReturnTypeDesc;
7624 #ifdef LEGACY_BACKEND
7625 copy->gtCall.gtCallRegUsedMask = tree->gtCall.gtCallRegUsedMask;
7626 #endif // LEGACY_BACKEND
7628 #ifdef FEATURE_READYTORUN_COMPILER
7629 copy->gtCall.setEntryPoint(tree->gtCall.gtEntryPoint);
7633 copy->gtCall.gtInlineObservation = tree->gtCall.gtInlineObservation;
7636 copy->AsCall()->CopyOtherRegFlags(tree->AsCall());
7641 copy = gtNewFieldRef(tree->TypeGet(), tree->gtField.gtFldHnd, nullptr, tree->gtField.gtFldOffset);
7643 copy->gtField.gtFldObj =
7644 tree->gtField.gtFldObj ? gtCloneExpr(tree->gtField.gtFldObj, addFlags, varNum, varVal) : nullptr;
7645 copy->gtField.gtFldMayOverlap = tree->gtField.gtFldMayOverlap;
7646 #ifdef FEATURE_READYTORUN_COMPILER
7647 copy->gtField.gtFieldLookup = tree->gtField.gtFieldLookup;
7654 GenTreePtr inds[GT_ARR_MAX_RANK];
7655 for (unsigned dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
7657 inds[dim] = gtCloneExpr(tree->gtArrElem.gtArrInds[dim], addFlags, varNum, varVal);
7659 copy = new (this, GT_ARR_ELEM)
7660 GenTreeArrElem(tree->TypeGet(), gtCloneExpr(tree->gtArrElem.gtArrObj, addFlags, varNum, varVal),
7661 tree->gtArrElem.gtArrRank, tree->gtArrElem.gtArrElemSize, tree->gtArrElem.gtArrElemType,
7668 copy = new (this, GT_ARR_OFFSET)
7669 GenTreeArrOffs(tree->TypeGet(), gtCloneExpr(tree->gtArrOffs.gtOffset, addFlags, varNum, varVal),
7670 gtCloneExpr(tree->gtArrOffs.gtIndex, addFlags, varNum, varVal),
7671 gtCloneExpr(tree->gtArrOffs.gtArrObj, addFlags, varNum, varVal),
7672 tree->gtArrOffs.gtCurrDim, tree->gtArrOffs.gtArrRank, tree->gtArrOffs.gtArrElemType);
7677 copy = new (this, GT_CMPXCHG)
7678 GenTreeCmpXchg(tree->TypeGet(), gtCloneExpr(tree->gtCmpXchg.gtOpLocation, addFlags, varNum, varVal),
7679 gtCloneExpr(tree->gtCmpXchg.gtOpValue, addFlags, varNum, varVal),
7680 gtCloneExpr(tree->gtCmpXchg.gtOpComparand, addFlags, varNum, varVal));
7683 case GT_ARR_BOUNDS_CHECK:
7686 #endif // FEATURE_SIMD
7687 copy = new (this, oper) GenTreeBoundsChk(oper, tree->TypeGet(),
7688 gtCloneExpr(tree->gtBoundsChk.gtArrLen, addFlags, varNum, varVal),
7689 gtCloneExpr(tree->gtBoundsChk.gtIndex, addFlags, varNum, varVal),
7690 tree->gtBoundsChk.gtThrowKind);
7697 NO_WAY("unexpected operator");
7702 // If it has a zero-offset field seq, copy annotation.
7703 if (tree->TypeGet() == TYP_BYREF)
7705 FieldSeqNode* fldSeq = nullptr;
7706 if (GetZeroOffsetFieldMap()->Lookup(tree, &fldSeq))
7708 GetZeroOffsetFieldMap()->Set(copy, fldSeq);
7712 copy->gtVNPair = tree->gtVNPair; // A cloned tree gets the orginal's Value number pair
7714 /* We assume the FP stack level will be identical */
7716 copy->gtCopyFPlvl(tree);
7718 /* Compute the flags for the copied node. Note that we can do this only
7719 if we didnt gtFoldExpr(copy) */
7721 if (copy->gtOper == oper)
7723 addFlags |= tree->gtFlags;
7726 /* GTF_NODE_MASK should not be propagated from 'tree' to 'copy' */
7727 addFlags &= ~GTF_NODE_MASK;
7729 // Some other flags depend on the context of the expression, and should not be preserved.
7730 // For example, GTF_RELOP_QMARK:
7731 if (copy->OperKind() & GTK_RELOP)
7733 addFlags &= ~GTF_RELOP_QMARK;
7735 // On the other hand, if we're creating such a context, restore this flag.
7736 if (copy->OperGet() == GT_QMARK)
7738 copy->gtOp.gtOp1->gtFlags |= GTF_RELOP_QMARK;
7741 copy->gtFlags |= addFlags;
7744 /* GTF_COLON_COND should be propagated from 'tree' to 'copy' */
7745 copy->gtFlags |= (tree->gtFlags & GTF_COLON_COND);
7748 // Non-node debug flags should be propagated from 'tree' to 'copy'
7749 copy->gtDebugFlags |= (tree->gtDebugFlags & ~GTF_DEBUG_NODE_MASK);
7752 /* Make sure to copy back fields that may have been initialized */
7754 copy->CopyRawCosts(tree);
7755 copy->gtRsvdRegs = tree->gtRsvdRegs;
7756 copy->CopyReg(tree);
7760 //------------------------------------------------------------------------
7761 // gtReplaceTree: Replace a tree with a new tree.
7764 // stmt - The top-level root stmt of the tree being replaced.
7765 // Must not be null.
7766 // tree - The tree being replaced. Must not be null.
7767 // replacementTree - The replacement tree. Must not be null.
7770 // The tree node that replaces the old tree.
7773 // The sequencing of the stmt has been done.
7776 // The caller must ensure that the original statement has been sequenced,
7777 // but this method will sequence 'replacementTree', and insert it into the
7778 // proper place in the statement sequence.
7780 GenTreePtr Compiler::gtReplaceTree(GenTreePtr stmt, GenTreePtr tree, GenTreePtr replacementTree)
7782 assert(fgStmtListThreaded);
7783 assert(tree != nullptr);
7784 assert(stmt != nullptr);
7785 assert(replacementTree != nullptr);
7787 GenTreePtr* treePtr = nullptr;
7788 GenTreePtr treeParent = tree->gtGetParent(&treePtr);
7790 assert(treeParent != nullptr || tree == stmt->gtStmt.gtStmtExpr);
7792 if (treePtr == nullptr)
7794 // Replace the stmt expr and rebuild the linear order for "stmt".
7795 assert(treeParent == nullptr);
7796 assert(fgOrder != FGOrderLinear);
7797 stmt->gtStmt.gtStmtExpr = tree;
7802 assert(treeParent != nullptr);
7804 GenTreePtr treeFirstNode = fgGetFirstNode(tree);
7805 GenTreePtr treeLastNode = tree;
7806 GenTreePtr treePrevNode = treeFirstNode->gtPrev;
7807 GenTreePtr treeNextNode = treeLastNode->gtNext;
7809 *treePtr = replacementTree;
7811 // Build the linear order for "replacementTree".
7812 fgSetTreeSeq(replacementTree, treePrevNode);
7814 // Restore linear-order Prev and Next for "replacementTree".
7815 if (treePrevNode != nullptr)
7817 treeFirstNode = fgGetFirstNode(replacementTree);
7818 treeFirstNode->gtPrev = treePrevNode;
7819 treePrevNode->gtNext = treeFirstNode;
7823 // Update the linear oder start of "stmt" if treeFirstNode
7824 // appears to have replaced the original first node.
7825 assert(treeFirstNode == stmt->gtStmt.gtStmtList);
7826 stmt->gtStmt.gtStmtList = fgGetFirstNode(replacementTree);
7829 if (treeNextNode != nullptr)
7831 treeLastNode = replacementTree;
7832 treeLastNode->gtNext = treeNextNode;
7833 treeNextNode->gtPrev = treeLastNode;
7836 bool needFixupCallArg = false;
7837 GenTreePtr node = treeParent;
7839 // If we have replaced an arg, then update pointers in argtable.
7842 // Look for the first enclosing callsite
7843 switch (node->OperGet())
7847 // "tree" is likely an argument of a call.
7848 needFixupCallArg = true;
7852 if (needFixupCallArg)
7854 // We have replaced an arg, so update pointers in argtable.
7855 fgFixupArgTabEntryPtr(node, tree, replacementTree);
7856 needFixupCallArg = false;
7861 // "tree" is unlikely an argument of a call.
7862 needFixupCallArg = false;
7866 if (needFixupCallArg)
7868 // Keep tracking to update the first enclosing call.
7869 node = node->gtGetParent(nullptr);
7876 } while (node != nullptr);
7878 // Propagate side-effect flags of "replacementTree" to its parents if needed.
7879 gtUpdateSideEffects(treeParent, tree->gtFlags, replacementTree->gtFlags);
7882 return replacementTree;
7885 //------------------------------------------------------------------------
7886 // gtUpdateSideEffects: Update the side effects for ancestors.
7889 // treeParent - The immediate parent node.
7890 // oldGtFlags - The stale gtFlags.
7891 // newGtFlags - The new gtFlags.
7895 // Linear order of the stmt has been established.
7898 // The routine is used for updating the stale side effect flags for ancestor
7899 // nodes starting from treeParent up to the top-level stmt expr.
7901 void Compiler::gtUpdateSideEffects(GenTreePtr treeParent, unsigned oldGtFlags, unsigned newGtFlags)
7903 assert(fgStmtListThreaded);
7905 oldGtFlags = oldGtFlags & GTF_ALL_EFFECT;
7906 newGtFlags = newGtFlags & GTF_ALL_EFFECT;
7908 if (oldGtFlags != newGtFlags)
7912 treeParent->gtFlags &= ~oldGtFlags;
7913 treeParent->gtFlags |= newGtFlags;
7914 treeParent = treeParent->gtGetParent(nullptr);
7919 /*****************************************************************************
7921 * Comapres two trees and returns true when both trees are the same.
7922 * Instead of fully comparing the two trees this method can just return false.
7923 * Thus callers should not assume that the trees are different when false is returned.
7924 * Only when true is returned can the caller perform code optimizations.
7925 * The current implementation only compares a limited set of LEAF/CONST node
7926 * and returns false for all othere trees.
7928 bool Compiler::gtCompareTree(GenTree* op1, GenTree* op2)
7930 /* Make sure that both trees are of the same GT node kind */
7931 if (op1->OperGet() != op2->OperGet())
7936 /* Make sure that both trees are returning the same type */
7937 if (op1->gtType != op2->gtType)
7942 /* Figure out what kind of a node we have */
7944 genTreeOps oper = op1->OperGet();
7945 unsigned kind = op1->OperKind();
7947 /* Is this a constant or leaf node? */
7949 if (kind & (GTK_CONST | GTK_LEAF))
7954 if ((op1->gtIntCon.gtIconVal == op2->gtIntCon.gtIconVal) && GenTree::SameIconHandleFlag(op1, op2))
7961 if (op1->gtLngCon.gtLconVal == op2->gtLngCon.gtLconVal)
7968 if (op1->gtStrCon.gtSconCPX == op2->gtStrCon.gtSconCPX)
7975 if (op1->gtLclVarCommon.gtLclNum == op2->gtLclVarCommon.gtLclNum)
7982 if (op1->gtClsVar.gtClsVarHnd == op2->gtClsVar.gtClsVarHnd)
7989 // we return false for these unhandled 'oper' kinds
7996 GenTreePtr Compiler::gtGetThisArg(GenTreePtr call)
7998 assert(call->gtOper == GT_CALL);
8000 if (call->gtCall.gtCallObjp != nullptr)
8002 if (call->gtCall.gtCallObjp->gtOper != GT_NOP && call->gtCall.gtCallObjp->gtOper != GT_ASG)
8004 if (!(call->gtCall.gtCallObjp->gtFlags & GTF_LATE_ARG))
8006 return call->gtCall.gtCallObjp;
8010 if (call->gtCall.gtCallLateArgs)
8012 regNumber thisReg = REG_ARG_0;
8013 unsigned argNum = 0;
8014 fgArgTabEntryPtr thisArgTabEntry = gtArgEntryByArgNum(call, argNum);
8015 GenTreePtr result = thisArgTabEntry->node;
8017 #if !FEATURE_FIXED_OUT_ARGS
8018 GenTreePtr lateArgs = call->gtCall.gtCallLateArgs;
8019 regList list = call->gtCall.regArgList;
8021 while (lateArgs != NULL)
8023 assert(lateArgs->gtOper == GT_LIST);
8024 assert(index < call->gtCall.regArgListCount);
8025 regNumber curArgReg = list[index];
8026 if (curArgReg == thisReg)
8028 if (optAssertionPropagatedCurrentStmt)
8029 result = lateArgs->gtOp.gtOp1;
8031 assert(result == lateArgs->gtOp.gtOp1);
8034 lateArgs = lateArgs->gtOp.gtOp2;
8044 bool GenTree::gtSetFlags() const
8047 // When FEATURE_SET_FLAGS (_TARGET_ARM_) is active the method returns true
8048 // when the gtFlags has the flag GTF_SET_FLAGS set
8049 // otherwise the architecture will be have instructions that typically set
8050 // the flags and this method will return true.
8052 // Exceptions: GT_IND (load/store) is not allowed to set the flags
8053 // and on XARCH the GT_MUL/GT_DIV and all overflow instructions
8054 // do not set the condition flags
8056 // Precondition we have a GTK_SMPOP
8058 assert(OperIsSimple());
8060 if (!varTypeIsIntegralOrI(TypeGet()))
8065 #if FEATURE_SET_FLAGS
8067 if ((gtFlags & GTF_SET_FLAGS) && gtOper != GT_IND)
8069 // GTF_SET_FLAGS is not valid on GT_IND and is overlaid with GTF_NONFAULTING_IND
8077 #else // !FEATURE_SET_FLAGS
8079 #ifdef _TARGET_XARCH_
8080 // Return true if/when the codegen for this node will set the flags
8083 if ((gtOper == GT_IND) || (gtOper == GT_MUL) || (gtOper == GT_DIV))
8087 else if (gtOverflowEx())
8096 // Otherwise for other architectures we should return false
8100 #endif // !FEATURE_SET_FLAGS
8103 bool GenTree::gtRequestSetFlags()
8105 bool result = false;
8107 #if FEATURE_SET_FLAGS
8108 // This method is a Nop unless FEATURE_SET_FLAGS is defined
8110 // In order to set GTF_SET_FLAGS
8111 // we must have a GTK_SMPOP
8112 // and we have a integer or machine size type (not floating point or TYP_LONG on 32-bit)
8114 if (!OperIsSimple())
8117 if (!varTypeIsIntegralOrI(TypeGet()))
8124 // These will turn into simple load from memory instructions
8125 // and we can't force the setting of the flags on load from memory
8130 // These instructions don't set the flags (on x86/x64)
8135 // Otherwise we can set the flags for this gtOper
8136 // and codegen must set the condition flags.
8138 gtFlags |= GTF_SET_FLAGS;
8142 #endif // FEATURE_SET_FLAGS
8144 // Codegen for this tree must set the condition flags if
8145 // this method returns true.
8150 /*****************************************************************************/
8151 void GenTree::CopyTo(class Compiler* comp, const GenTree& gt)
8155 gtAssertionNum = gt.gtAssertionNum;
8157 gtRegNum = gt.gtRegNum; // one union member.
8160 gtFlags = gt.gtFlags;
8161 gtVNPair = gt.gtVNPair;
8163 gtRsvdRegs = gt.gtRsvdRegs;
8165 #ifdef LEGACY_BACKEND
8166 gtUsedRegs = gt.gtUsedRegs;
8167 #endif // LEGACY_BACKEND
8169 #if FEATURE_STACK_FP_X87
8170 gtFPlvl = gt.gtFPlvl;
8171 #endif // FEATURE_STACK_FP_X87
8176 gtTreeID = gt.gtTreeID;
8177 gtSeqNum = gt.gtSeqNum;
8179 // Largest node subtype:
8180 void* remDst = reinterpret_cast<char*>(this) + sizeof(GenTree);
8181 void* remSrc = reinterpret_cast<char*>(const_cast<GenTree*>(>)) + sizeof(GenTree);
8182 memcpy(remDst, remSrc, TREE_NODE_SZ_LARGE - sizeof(GenTree));
8185 void GenTree::CopyToSmall(const GenTree& gt)
8187 // Small node size is defined by GenTreeOp.
8188 void* remDst = reinterpret_cast<char*>(this) + sizeof(GenTree);
8189 void* remSrc = reinterpret_cast<char*>(const_cast<GenTree*>(>)) + sizeof(GenTree);
8190 memcpy(remDst, remSrc, TREE_NODE_SZ_SMALL - sizeof(GenTree));
8193 unsigned GenTree::NumChildren()
8195 if (OperIsConst() || OperIsLeaf())
8199 else if (OperIsUnary())
8201 if (OperGet() == GT_NOP || OperGet() == GT_RETURN || OperGet() == GT_RETFILT)
8203 if (gtOp.gtOp1 == nullptr)
8217 else if (OperIsBinary())
8219 // All binary operators except LEA have at least one arg; the second arg may sometimes be null, however.
8220 if (OperGet() == GT_LEA)
8222 unsigned childCount = 0;
8223 if (gtOp.gtOp1 != nullptr)
8227 if (gtOp.gtOp2 != nullptr)
8233 assert(gtOp.gtOp1 != nullptr);
8234 if (gtOp.gtOp2 == nullptr)
8251 case GT_ARR_BOUNDS_CHECK:
8254 #endif // FEATURE_SIMD
8262 return 1 + AsArrElem()->gtArrRank;
8269 GenTreeCall* call = AsCall();
8270 unsigned res = 0; // arg list(s) (including late args).
8271 if (call->gtCallObjp != nullptr)
8275 if (call->gtCallArgs != nullptr)
8279 if (call->gtCallLateArgs != nullptr)
8281 res++; // Add late args?
8283 if (call->gtControlExpr != nullptr)
8288 if (call->gtCallType == CT_INDIRECT)
8290 if (call->gtCallCookie != nullptr)
8294 if (call->gtCallAddr != nullptr)
8309 GenTreePtr GenTree::GetChild(unsigned childNum)
8311 assert(childNum < NumChildren()); // Precondition.
8312 assert(NumChildren() <= MAX_CHILDREN);
8313 assert(!(OperIsConst() || OperIsLeaf()));
8316 return AsUnOp()->gtOp1;
8318 else if (OperIsBinary())
8320 if (OperIsAddrMode())
8322 // If this is the first (0th) child, only return op1 if it is non-null
8323 // Otherwise, we return gtOp2.
8324 if (childNum == 0 && AsOp()->gtOp1 != nullptr)
8326 return AsOp()->gtOp1;
8328 return AsOp()->gtOp2;
8330 // TODO-Cleanup: Consider handling ReverseOps here, and then we wouldn't have to handle it in
8331 // fgGetFirstNode(). However, it seems that it causes loop hoisting behavior to change.
8334 return AsOp()->gtOp1;
8338 return AsOp()->gtOp2;
8350 return AsCmpXchg()->gtOpLocation;
8352 return AsCmpXchg()->gtOpValue;
8354 return AsCmpXchg()->gtOpComparand;
8358 case GT_ARR_BOUNDS_CHECK:
8361 #endif // FEATURE_SIMD
8365 return AsBoundsChk()->gtArrLen;
8367 return AsBoundsChk()->gtIndex;
8373 return AsField()->gtFldObj;
8376 return AsStmt()->gtStmtExpr;
8381 return AsArrElem()->gtArrObj;
8385 return AsArrElem()->gtArrInds[childNum - 1];
8392 return AsArrOffs()->gtOffset;
8394 return AsArrOffs()->gtIndex;
8396 return AsArrOffs()->gtArrObj;
8403 // The if chain below assumes that all possible children are non-null.
8404 // If some are null, "virtually skip them."
8405 // If there isn't "virtually skip it."
8406 GenTreeCall* call = AsCall();
8408 if (call->gtCallObjp == nullptr)
8412 if (childNum >= 1 && call->gtCallArgs == nullptr)
8416 if (childNum >= 2 && call->gtCallLateArgs == nullptr)
8420 if (childNum >= 3 && call->gtControlExpr == nullptr)
8424 if (call->gtCallType == CT_INDIRECT)
8426 if (childNum >= 4 && call->gtCallCookie == nullptr)
8434 return call->gtCallObjp;
8436 else if (childNum == 1)
8438 return call->gtCallArgs;
8440 else if (childNum == 2)
8442 return call->gtCallLateArgs;
8444 else if (childNum == 3)
8446 return call->gtControlExpr;
8450 assert(call->gtCallType == CT_INDIRECT);
8453 return call->gtCallCookie;
8457 assert(childNum == 5);
8458 return call->gtCallAddr;
8470 GenTreeUseEdgeIterator::GenTreeUseEdgeIterator()
8473 , m_argList(nullptr)
8478 GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node)
8481 , m_argList(nullptr)
8484 assert(m_node != nullptr);
8486 // Advance to the first operand.
8490 //------------------------------------------------------------------------
8491 // GenTreeUseEdgeIterator::GetNextUseEdge:
8492 // Gets the next operand of a node with a fixed number of operands.
8493 // This covers all nodes besides GT_CALL, GT_PHI, and GT_SIMD. For the
8494 // node types handled by this method, the `m_state` field indicates the
8495 // index of the next operand to produce.
8498 // The node's next operand or nullptr if all operands have been
8501 GenTree** GenTreeUseEdgeIterator::GetNextUseEdge() const
8503 switch (m_node->OperGet())
8509 return &m_node->AsCmpXchg()->gtOpLocation;
8511 return &m_node->AsCmpXchg()->gtOpValue;
8513 return &m_node->AsCmpXchg()->gtOpComparand;
8517 case GT_ARR_BOUNDS_CHECK:
8520 #endif // FEATURE_SIMD
8524 return &m_node->AsBoundsChk()->gtArrLen;
8526 return &m_node->AsBoundsChk()->gtIndex;
8534 return &m_node->AsField()->gtFldObj;
8541 return &m_node->AsStmt()->gtStmtExpr;
8548 return &m_node->AsArrElem()->gtArrObj;
8550 else if (m_state <= m_node->AsArrElem()->gtArrRank)
8552 return &m_node->AsArrElem()->gtArrInds[m_state - 1];
8560 return &m_node->AsArrOffs()->gtOffset;
8562 return &m_node->AsArrOffs()->gtIndex;
8564 return &m_node->AsArrOffs()->gtArrObj;
8569 // Call, phi, and SIMD nodes are handled by MoveNext{Call,Phi,SIMD}UseEdge, repsectively.
8581 GenTreeBlkOp* blkOp = m_node->AsBlkOp();
8583 bool blkOpReversed = (blkOp->gtFlags & GTF_REVERSE_OPS) != 0;
8584 bool srcDstReversed = (blkOp->gtOp1->gtFlags & GTF_REVERSE_OPS) != 0;
8591 return !srcDstReversed ? &blkOp->gtOp1->AsArgList()->gtOp1 : &blkOp->gtOp1->AsArgList()->gtOp2;
8593 return !srcDstReversed ? &blkOp->gtOp1->AsArgList()->gtOp2 : &blkOp->gtOp1->AsArgList()->gtOp1;
8595 return &blkOp->gtOp2;
8605 return &blkOp->gtOp2;
8607 return !srcDstReversed ? &blkOp->gtOp1->AsArgList()->gtOp1 : &blkOp->gtOp1->AsArgList()->gtOp2;
8609 return !srcDstReversed ? &blkOp->gtOp1->AsArgList()->gtOp2 : &blkOp->gtOp1->AsArgList()->gtOp1;
8619 GenTreeAddrMode* lea = m_node->AsAddrMode();
8621 bool hasOp1 = lea->gtOp1 != nullptr;
8624 return m_state == 0 ? &lea->gtOp2 : nullptr;
8627 bool operandsReversed = (lea->gtFlags & GTF_REVERSE_OPS) != 0;
8631 return !operandsReversed ? &lea->gtOp1 : &lea->gtOp2;
8633 return !operandsReversed ? &lea->gtOp2 : &lea->gtOp1;
8641 if (m_node->AsArgList()->IsAggregate())
8643 // List nodes that represent aggregates are handled by MoveNextAggregateUseEdge.
8649 if (m_node->OperIsConst() || m_node->OperIsLeaf())
8653 else if (m_node->OperIsUnary())
8655 return m_state == 0 ? &m_node->AsUnOp()->gtOp1 : nullptr;
8657 else if (m_node->OperIsBinary())
8659 bool operandsReversed = (m_node->gtFlags & GTF_REVERSE_OPS) != 0;
8663 return !operandsReversed ? &m_node->AsOp()->gtOp1 : &m_node->AsOp()->gtOp2;
8665 return !operandsReversed ? &m_node->AsOp()->gtOp2 : &m_node->AsOp()->gtOp1;
8675 //------------------------------------------------------------------------
8676 // GenTreeUseEdgeIterator::MoveToNextCallUseEdge:
8677 // Moves to the next operand of a call node. Unlike the simple nodes
8678 // handled by `GetNextUseEdge`, call nodes have a variable number of
8679 // operands stored in cons lists. This method expands the cons lists
8680 // into the operands stored within.
8682 void GenTreeUseEdgeIterator::MoveToNextCallUseEdge()
8689 CALL_CONTROL_EXPR = 3,
8695 GenTreeCall* call = m_node->AsCall();
8702 m_state = CALL_ARGS;
8703 m_argList = call->gtCallArgs;
8705 if (call->gtCallObjp != nullptr)
8707 m_edge = &call->gtCallObjp;
8713 case CALL_LATE_ARGS:
8714 if (m_argList == nullptr)
8718 if (m_state == CALL_LATE_ARGS)
8720 m_argList = call->gtCallLateArgs;
8725 GenTreeArgList* argNode = m_argList->AsArgList();
8726 m_edge = &argNode->gtOp1;
8727 m_argList = argNode->Rest();
8732 case CALL_CONTROL_EXPR:
8733 m_state = call->gtCallType == CT_INDIRECT ? CALL_COOKIE : CALL_TERMINAL;
8735 if (call->gtControlExpr != nullptr)
8737 m_edge = &call->gtControlExpr;
8743 assert(call->gtCallType == CT_INDIRECT);
8745 m_state = CALL_ADDRESS;
8747 if (call->gtCallCookie != nullptr)
8749 m_edge = &call->gtCallCookie;
8755 assert(call->gtCallType == CT_INDIRECT);
8757 m_state = CALL_TERMINAL;
8758 if (call->gtCallAddr != nullptr)
8760 m_edge = &call->gtCallAddr;
8768 m_argList = nullptr;
8775 //------------------------------------------------------------------------
8776 // GenTreeUseEdgeIterator::MoveToNextPhiUseEdge:
8777 // Moves to the next operand of a phi node. Unlike the simple nodes
8778 // handled by `GetNextUseEdge`, phi nodes have a variable number of
8779 // operands stored in a cons list. This method expands the cons list
8780 // into the operands stored within.
8782 void GenTreeUseEdgeIterator::MoveToNextPhiUseEdge()
8784 GenTreeUnOp* phi = m_node->AsUnOp();
8792 m_argList = phi->gtOp1;
8796 if (m_argList == nullptr)
8802 GenTreeArgList* argNode = m_argList->AsArgList();
8803 m_edge = &argNode->gtOp1;
8804 m_argList = argNode->Rest();
8812 m_argList = nullptr;
8820 //------------------------------------------------------------------------
8821 // GenTreeUseEdgeIterator::MoveToNextSIMDUseEdge:
8822 // Moves to the next operand of a SIMD node. Most SIMD nodes have a
8823 // fixed number of operands and are handled accordingly.
8824 // `SIMDIntrinsicInitN` nodes, however, have a variable number of
8825 // operands stored in a cons list. This method expands the cons list
8826 // into the operands stored within.
8828 void GenTreeUseEdgeIterator::MoveToNextSIMDUseEdge()
8830 GenTreeSIMD* simd = m_node->AsSIMD();
8832 if (simd->gtSIMDIntrinsicID != SIMDIntrinsicInitN)
8834 bool operandsReversed = (simd->gtFlags & GTF_REVERSE_OPS) != 0;
8838 m_edge = !operandsReversed ? &simd->gtOp1 : &simd->gtOp2;
8841 m_edge = !operandsReversed ? &simd->gtOp2 : &simd->gtOp1;
8848 if (m_edge != nullptr && *m_edge != nullptr)
8867 m_argList = simd->gtOp1;
8871 if (m_argList == nullptr)
8877 GenTreeArgList* argNode = m_argList->AsArgList();
8878 m_edge = &argNode->gtOp1;
8879 m_argList = argNode->Rest();
8887 m_argList = nullptr;
8893 #endif // FEATURE_SIMD
8895 void GenTreeUseEdgeIterator::MoveToNextAggregateUseEdge()
8897 assert(m_node->OperGet() == GT_LIST);
8898 assert(m_node->AsArgList()->IsAggregate());
8910 if (m_argList == nullptr)
8916 GenTreeArgList* aggNode = m_argList->AsArgList();
8917 m_edge = &aggNode->gtOp1;
8918 m_argList = aggNode->Rest();
8926 m_argList = nullptr;
8933 //------------------------------------------------------------------------
8934 // GenTreeUseEdgeIterator::operator++:
8935 // Advances the iterator to the next operand.
8937 GenTreeUseEdgeIterator& GenTreeUseEdgeIterator::operator++()
8941 // If we've reached the terminal state, do nothing.
8942 assert(m_node == nullptr);
8943 assert(m_edge == nullptr);
8944 assert(m_argList == nullptr);
8948 // Otherwise, move to the next operand in the node.
8949 genTreeOps op = m_node->OperGet();
8952 MoveToNextCallUseEdge();
8954 else if (op == GT_PHI)
8956 MoveToNextPhiUseEdge();
8959 else if (op == GT_SIMD)
8961 MoveToNextSIMDUseEdge();
8964 else if ((op == GT_LIST) && (m_node->AsArgList()->IsAggregate()))
8966 MoveToNextAggregateUseEdge();
8970 m_edge = GetNextUseEdge();
8971 if (m_edge != nullptr && *m_edge != nullptr)
8987 GenTreeUseEdgeIterator GenTree::UseEdgesBegin()
8989 return GenTreeUseEdgeIterator(this);
8992 GenTreeUseEdgeIterator GenTree::UseEdgesEnd()
8994 return GenTreeUseEdgeIterator();
8997 IteratorPair<GenTreeUseEdgeIterator> GenTree::UseEdges()
8999 return MakeIteratorPair(UseEdgesBegin(), UseEdgesEnd());
9002 GenTreeOperandIterator GenTree::OperandsBegin()
9004 return GenTreeOperandIterator(this);
9007 GenTreeOperandIterator GenTree::OperandsEnd()
9009 return GenTreeOperandIterator();
9012 IteratorPair<GenTreeOperandIterator> GenTree::Operands()
9014 return MakeIteratorPair(OperandsBegin(), OperandsEnd());
9017 bool GenTree::Precedes(GenTree* other)
9019 assert(other != nullptr);
9021 for (GenTree* node = gtNext; node != nullptr; node = node->gtNext)
9034 /* static */ int GenTree::gtDispFlags(unsigned flags, unsigned debugFlags)
9036 printf("%c", (flags & GTF_ASG) ? 'A' : '-');
9037 printf("%c", (flags & GTF_CALL) ? 'C' : '-');
9038 printf("%c", (flags & GTF_EXCEPT) ? 'X' : '-');
9039 printf("%c", (flags & GTF_GLOB_REF) ? 'G' : '-');
9040 printf("%c", (debugFlags & GTF_DEBUG_NODE_MORPHED) ? '+' : // First print '+' if GTF_DEBUG_NODE_MORPHED is set
9041 (flags & GTF_ORDER_SIDEEFF) ? 'O' : '-'); // otherwise print 'O' or '-'
9042 printf("%c", (flags & GTF_COLON_COND) ? '?' : '-');
9043 printf("%c", (flags & GTF_DONT_CSE) ? 'N' : // N is for No cse
9044 (flags & GTF_MAKE_CSE) ? 'H' : '-'); // H is for Hoist this expr
9045 printf("%c", (flags & GTF_REVERSE_OPS) ? 'R' : '-');
9046 printf("%c", (flags & GTF_UNSIGNED) ? 'U' : (flags & GTF_BOOLEAN) ? 'B' : '-');
9047 #if FEATURE_SET_FLAGS
9048 printf("%c", (flags & GTF_SET_FLAGS) ? 'S' : '-');
9050 printf("%c", (flags & GTF_LATE_ARG) ? 'L' : '-');
9051 printf("%c", (flags & GTF_SPILLED) ? 'z' : (flags & GTF_SPILL) ? 'Z' : '-');
9052 return 12; // displayed 12 flag characters
9055 /*****************************************************************************/
9057 void Compiler::gtDispNodeName(GenTree* tree)
9059 /* print the node name */
9064 if (tree->gtOper < GT_COUNT)
9066 name = GenTree::NodeName(tree->OperGet());
9073 char* bufp = &buf[0];
9075 if ((tree->gtOper == GT_CNS_INT) && tree->IsIconHandle())
9077 sprintf_s(bufp, sizeof(buf), " %s(h)%c", name, 0);
9079 else if (tree->gtOper == GT_PUTARG_STK)
9081 sprintf_s(bufp, sizeof(buf), " %s [+0x%02x]%c", name, tree->AsPutArgStk()->getArgOffset(), 0);
9083 else if (tree->gtOper == GT_CALL)
9085 const char* callType = "call";
9086 const char* gtfType = "";
9087 const char* ctType = "";
9088 char gtfTypeBuf[100];
9090 if (tree->gtCall.gtCallType == CT_USER_FUNC)
9092 if ((tree->gtFlags & GTF_CALL_VIRT_KIND_MASK) != GTF_CALL_NONVIRT)
9097 else if (tree->gtCall.gtCallType == CT_HELPER)
9101 else if (tree->gtCall.gtCallType == CT_INDIRECT)
9107 assert(!"Unknown gtCallType");
9110 if (tree->gtFlags & GTF_CALL_NULLCHECK)
9112 gtfType = " nullcheck";
9114 if (tree->gtFlags & GTF_CALL_VIRT_VTABLE)
9118 else if (tree->gtFlags & GTF_CALL_VIRT_STUB)
9122 #ifdef FEATURE_READYTORUN_COMPILER
9123 else if (tree->gtCall.IsR2RRelativeIndir())
9125 gtfType = " r2r_ind";
9127 #endif // FEATURE_READYTORUN_COMPILER
9128 else if (tree->gtFlags & GTF_CALL_UNMANAGED)
9130 char* gtfTypeBufWalk = gtfTypeBuf;
9131 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " unman");
9132 if (tree->gtFlags & GTF_CALL_POP_ARGS)
9134 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " popargs");
9136 if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
9138 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " thiscall");
9140 gtfType = gtfTypeBuf;
9143 sprintf_s(bufp, sizeof(buf), " %s%s%s%c", callType, ctType, gtfType, 0);
9145 else if (tree->gtOper == GT_ARR_ELEM)
9147 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s[", name);
9148 for (unsigned rank = tree->gtArrElem.gtArrRank - 1; rank; rank--)
9150 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), ",");
9152 SimpleSprintf_s(bufp, buf, sizeof(buf), "]");
9154 else if (tree->gtOper == GT_ARR_OFFSET || tree->gtOper == GT_ARR_INDEX)
9156 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s[", name);
9157 unsigned char currDim;
9159 if (tree->gtOper == GT_ARR_OFFSET)
9161 currDim = tree->gtArrOffs.gtCurrDim;
9162 rank = tree->gtArrOffs.gtArrRank;
9166 currDim = tree->gtArrIndex.gtCurrDim;
9167 rank = tree->gtArrIndex.gtArrRank;
9170 for (unsigned char dim = 0; dim < rank; dim++)
9172 // Use a defacto standard i,j,k for the dimensions.
9173 // Note that we only support up to rank 3 arrays with these nodes, so we won't run out of characters.
9177 dimChar = 'i' + dim;
9179 else if (dim > currDim)
9184 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "%c", dimChar);
9185 if (dim != rank - 1)
9187 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), ",");
9190 SimpleSprintf_s(bufp, buf, sizeof(buf), "]");
9192 else if (tree->gtOper == GT_LEA)
9194 GenTreeAddrMode* lea = tree->AsAddrMode();
9195 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s(", name);
9196 if (lea->Base() != nullptr)
9198 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "b+");
9200 if (lea->Index() != nullptr)
9202 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "(i*%d)+", lea->gtScale);
9204 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "%d)", lea->gtOffset);
9206 else if (tree->gtOper == GT_ARR_BOUNDS_CHECK)
9208 switch (tree->gtBoundsChk.gtThrowKind)
9210 case SCK_RNGCHK_FAIL:
9211 sprintf_s(bufp, sizeof(buf), " %s_Rng", name);
9214 sprintf_s(bufp, sizeof(buf), " %s_Arg", name);
9216 case SCK_ARG_RNG_EXCPN:
9217 sprintf_s(bufp, sizeof(buf), " %s_ArgRng", name);
9223 else if (tree->gtOverflowEx())
9225 sprintf_s(bufp, sizeof(buf), " %s_ovfl%c", name, 0);
9229 sprintf_s(bufp, sizeof(buf), " %s%c", name, 0);
9232 if (strlen(buf) < 10)
9234 printf(" %-10s", buf);
9242 void Compiler::gtDispVN(GenTree* tree)
9244 if (tree->gtVNPair.GetLiberal() != ValueNumStore::NoVN)
9246 assert(tree->gtVNPair.GetConservative() != ValueNumStore::NoVN);
9248 vnpPrint(tree->gtVNPair, 0);
9252 //------------------------------------------------------------------------
9253 // gtDispNode: Print a tree to jitstdout.
9256 // tree - the tree to be printed
9257 // indentStack - the specification for the current level of indentation & arcs
9258 // msg - a contextual method (i.e. from the parent) to print
9264 // 'indentStack' may be null, in which case no indentation or arcs are printed
9265 // 'msg' may be null
9267 void Compiler::gtDispNode(GenTreePtr tree, IndentStack* indentStack, __in __in_z __in_opt const char* msg, bool isLIR)
9269 bool printPointer = true; // always true..
9270 bool printFlags = true; // always true..
9271 bool printCost = true; // always true..
9279 printf("N%03u ", tree->gtSeqNum);
9280 if (tree->gtCostsInitialized)
9282 printf("(%3u,%3u) ", tree->gtCostEx, tree->gtCostSz);
9288 ") "); // This probably indicates a bug: the node has a sequence number, but not costs.
9293 if (tree->gtOper == GT_STMT)
9295 prev = tree->gtStmt.gtStmtExpr;
9302 bool hasSeqNum = true;
9303 unsigned dotNum = 0;
9307 prev = prev->gtPrev;
9309 if ((prev == nullptr) || (prev == tree))
9316 } while (prev->gtSeqNum == 0);
9318 // If we have an indent stack, don't add additional characters,
9319 // as it will mess up the alignment.
9320 bool displayDotNum = tree->gtOper != GT_STMT && hasSeqNum && (indentStack == nullptr);
9323 printf("N%03u.%02u ", prev->gtSeqNum, dotNum);
9330 if (tree->gtCostsInitialized)
9332 printf("(%3u,%3u) ", tree->gtCostEx, tree->gtCostSz);
9338 // Do better alignment in this case
9348 if (optValnumCSE_phase)
9350 if (IS_CSE_INDEX(tree->gtCSEnum))
9352 printf("CSE #%02d (%s)", GET_CSE_INDEX(tree->gtCSEnum), (IS_CSE_USE(tree->gtCSEnum) ? "use" : "def"));
9360 /* Print the node ID */
9364 if (tree->gtOper >= GT_COUNT)
9366 printf(" **** ILLEGAL NODE ****");
9372 /* First print the flags associated with the node */
9373 switch (tree->gtOper)
9377 // We prefer printing R, V or U
9378 if ((tree->gtFlags & (GTF_IND_REFARR_LAYOUT | GTF_IND_VOLATILE | GTF_IND_UNALIGNED)) == 0)
9380 if (tree->gtFlags & GTF_IND_TGTANYWHERE)
9386 if (tree->gtFlags & GTF_IND_INVARIANT)
9392 if (tree->gtFlags & GTF_IND_ARR_INDEX)
9403 if ((tree->gtFlags & (GTF_IND_VOLATILE | GTF_IND_UNALIGNED)) == 0) // We prefer printing V or U over R
9405 if (tree->gtFlags & GTF_IND_REFARR_LAYOUT)
9410 } // R means RefArray
9416 if (tree->gtFlags & GTF_IND_VOLATILE)
9422 if (tree->gtFlags & GTF_IND_UNALIGNED)
9433 if (tree->AsBlkOp()->IsVolatile())
9439 if (tree->gtFlags & GTF_BLK_UNALIGNED)
9448 if (tree->gtFlags & GTF_CALL_INLINE_CANDIDATE)
9454 if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_RETBUFFARG)
9460 if (tree->gtFlags & GTF_CALL_HOISTABLE)
9470 if (tree->gtFlags & GTF_MUL_64RSLT)
9479 if (tree->gtFlags & GTF_ADDR_ONSTACK)
9489 case GT_LCL_VAR_ADDR:
9490 case GT_LCL_FLD_ADDR:
9491 case GT_STORE_LCL_FLD:
9492 case GT_STORE_LCL_VAR:
9494 if (tree->gtFlags & GTF_VAR_USEASG)
9500 if (tree->gtFlags & GTF_VAR_USEDEF)
9506 if (tree->gtFlags & GTF_VAR_DEF)
9512 if (tree->gtFlags & GTF_VAR_CAST)
9518 if (tree->gtFlags & GTF_VAR_ARR_INDEX)
9532 if (tree->gtFlags & GTF_RELOP_NAN_UN)
9538 if (tree->gtFlags & GTF_RELOP_JMP_USED)
9544 if (tree->gtFlags & GTF_RELOP_QMARK)
9550 if (tree->gtFlags & GTF_RELOP_SMALL)
9565 /* Then print the general purpose flags */
9566 unsigned flags = tree->gtFlags;
9568 if (tree->OperIsBinary())
9570 genTreeOps oper = tree->OperGet();
9572 // Check for GTF_ADDRMODE_NO_CSE flag on add/mul/shl Binary Operators
9573 if ((oper == GT_ADD) || (oper == GT_MUL) || (oper == GT_LSH))
9575 if ((tree->gtFlags & GTF_ADDRMODE_NO_CSE) != 0)
9577 flags |= GTF_DONT_CSE; // Force the GTF_ADDRMODE_NO_CSE flag to print out like GTF_DONT_CSE
9581 else // !tree->OperIsBinary()
9583 // the GTF_REVERSE flag only applies to binary operations
9584 flags &= ~GTF_REVERSE_OPS; // we use this value for GTF_VAR_ARR_INDEX above
9587 msgLength -= GenTree::gtDispFlags(flags, tree->gtDebugFlags);
9589 printf("%c", (flags & GTF_ASG ) ? 'A' : '-');
9590 printf("%c", (flags & GTF_CALL ) ? 'C' : '-');
9591 printf("%c", (flags & GTF_EXCEPT ) ? 'X' : '-');
9592 printf("%c", (flags & GTF_GLOB_REF ) ? 'G' : '-');
9593 printf("%c", (flags & GTF_ORDER_SIDEEFF ) ? 'O' : '-');
9594 printf("%c", (flags & GTF_COLON_COND ) ? '?' : '-');
9595 printf("%c", (flags & GTF_DONT_CSE ) ? 'N' : // N is for No cse
9596 (flags & GTF_MAKE_CSE ) ? 'H' : '-'); // H is for Hoist this expr
9597 printf("%c", (flags & GTF_REVERSE_OPS ) ? 'R' : '-');
9598 printf("%c", (flags & GTF_UNSIGNED ) ? 'U' :
9599 (flags & GTF_BOOLEAN ) ? 'B' : '-');
9600 printf("%c", (flags & GTF_SET_FLAGS ) ? 'S' : '-');
9601 printf("%c", (flags & GTF_SPILLED ) ? 'z' : '-');
9602 printf("%c", (flags & GTF_SPILL ) ? 'Z' : '-');
9605 #if FEATURE_STACK_FP_X87
9606 BYTE fpLvl = (BYTE)tree->gtFPlvl;
9607 if (IsUninitialized(fpLvl) || fpLvl == 0x00)
9613 printf("%1u", tree->gtFPlvl);
9615 #endif // FEATURE_STACK_FP_X87
9618 // If we're printing a node for LIR, we use the space normally associated with the message
9619 // to display the node's temp name (if any)
9620 const bool hasOperands = tree->OperandsBegin() != tree->OperandsEnd();
9623 assert(msg == nullptr);
9625 // If the tree does not have any operands, we do not display the indent stack. This gives us
9626 // two additional characters for alignment.
9632 if (tree->IsValue())
9634 const size_t bufLength = msgLength - 1;
9635 msg = reinterpret_cast<char*>(alloca(bufLength * sizeof(char)));
9636 sprintf_s(const_cast<char*>(msg), bufLength, "t%d = %s", tree->gtTreeID, hasOperands ? "" : " ");
9640 /* print the msg associated with the node */
9651 printf(isLIR ? " %+*s" : " %-*s", msgLength, msg);
9653 /* Indent the node accordingly */
9654 if (!isLIR || hasOperands)
9656 printIndent(indentStack);
9659 gtDispNodeName(tree);
9661 assert(tree == nullptr || tree->gtOper < GT_COUNT);
9665 /* print the type of the node */
9666 if (tree->gtOper != GT_CAST)
9668 printf(" %-6s", varTypeName(tree->TypeGet()));
9669 if (tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_STORE_LCL_VAR)
9671 LclVarDsc* varDsc = &lvaTable[tree->gtLclVarCommon.gtLclNum];
9672 if (varDsc->lvAddrExposed)
9674 printf("(AX)"); // Variable has address exposed.
9677 if (varDsc->lvUnusedStruct)
9679 assert(varDsc->lvPromoted);
9680 printf("(U)"); // Unused struct
9682 else if (varDsc->lvPromoted)
9684 assert(varTypeIsPromotable(varDsc));
9685 printf("(P)"); // Promoted struct
9689 if (tree->gtOper == GT_STMT)
9691 if (opts.compDbgInfo)
9693 IL_OFFSET endIL = tree->gtStmt.gtStmtLastILoffs;
9696 if (tree->gtStmt.gtStmtILoffsx == BAD_IL_OFFSET)
9702 printf("0x%03X", jitGetILoffs(tree->gtStmt.gtStmtILoffsx));
9705 if (endIL == BAD_IL_OFFSET)
9711 printf("0x%03X", endIL);
9717 if (tree->IsArgPlaceHolderNode() && (tree->gtArgPlace.gtArgPlaceClsHnd != nullptr))
9719 printf(" => [clsHnd=%08X]", dspPtr(tree->gtArgPlace.gtArgPlaceClsHnd));
9723 // for tracking down problems in reguse prediction or liveness tracking
9728 dspRegMask(tree->gtRsvdRegs);
9729 #ifdef LEGACY_BACKEND
9731 dspRegMask(tree->gtUsedRegs);
9732 #endif // LEGACY_BACKEND
9738 void Compiler::gtDispRegVal(GenTree* tree)
9740 switch (tree->GetRegTag())
9742 // Don't display NOREG; the absence of this tag will imply this state
9743 // case GenTree::GT_REGTAG_NONE: printf(" NOREG"); break;
9745 case GenTree::GT_REGTAG_REG:
9746 printf(" REG %s", compRegVarName(tree->gtRegNum));
9749 #if CPU_LONG_USES_REGPAIR
9750 case GenTree::GT_REGTAG_REGPAIR:
9751 printf(" PAIR %s", compRegPairName(tree->gtRegPair));
9759 if (tree->IsMultiRegCall())
9761 // 0th reg is gtRegNum, which is already printed above.
9762 // Print the remaining regs of a multi-reg call node.
9763 GenTreeCall* call = tree->AsCall();
9764 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
9765 for (unsigned i = 1; i < regCount; ++i)
9767 printf(",%s", compRegVarName(call->GetRegNumByIdx(i)));
9770 else if (tree->IsCopyOrReloadOfMultiRegCall())
9772 GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
9773 GenTreeCall* call = tree->gtGetOp1()->AsCall();
9774 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
9775 for (unsigned i = 1; i < regCount; ++i)
9777 printf(",%s", compRegVarName(copyOrReload->GetRegNumByIdx(i)));
9781 if (tree->gtFlags & GTF_REG_VAL)
9787 // We usually/commonly don't expect to print anything longer than this string,
9788 #define LONGEST_COMMON_LCL_VAR_DISPLAY "V99 PInvokeFrame"
9789 #define LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH (sizeof(LONGEST_COMMON_LCL_VAR_DISPLAY))
9790 #define BUF_SIZE (LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH * 2)
9792 void Compiler::gtGetLclVarNameInfo(unsigned lclNum, const char** ilKindOut, const char** ilNameOut, unsigned* ilNumOut)
9794 const char* ilKind = nullptr;
9795 const char* ilName = nullptr;
9797 unsigned ilNum = compMap2ILvarNum(lclNum);
9799 if (ilNum == (unsigned)ICorDebugInfo::RETBUF_ILNUM)
9803 else if (ilNum == (unsigned)ICorDebugInfo::VARARGS_HND_ILNUM)
9805 ilName = "VarArgHandle";
9807 else if (ilNum == (unsigned)ICorDebugInfo::TYPECTXT_ILNUM)
9811 else if (ilNum == (unsigned)ICorDebugInfo::UNKNOWN_ILNUM)
9814 if (lclNumIsTrueCSE(lclNum))
9817 ilNum = lclNum - optCSEstart;
9819 else if (lclNum >= optCSEstart)
9821 // Currently any new LclVar's introduced after the CSE phase
9822 // are believed to be created by the "rationalizer" that is what is meant by the "rat" prefix.
9824 ilNum = lclNum - (optCSEstart + optCSEcount);
9827 #endif // FEATURE_ANYCSE
9829 if (lclNum == info.compLvFrameListRoot)
9831 ilName = "FramesRoot";
9833 else if (lclNum == lvaInlinedPInvokeFrameVar)
9835 ilName = "PInvokeFrame";
9837 else if (lclNum == lvaGSSecurityCookie)
9839 ilName = "GsCookie";
9841 #if FEATURE_FIXED_OUT_ARGS
9842 else if (lclNum == lvaPInvokeFrameRegSaveVar)
9844 ilName = "PInvokeFrameRegSave";
9846 else if (lclNum == lvaOutgoingArgSpaceVar)
9850 #endif // FEATURE_FIXED_OUT_ARGS
9852 else if (lclNum == lvaPromotedStructAssemblyScratchVar)
9854 ilName = "PromotedStructScratch";
9856 #endif // _TARGET_ARM_
9857 #if !FEATURE_EH_FUNCLETS
9858 else if (lclNum == lvaShadowSPslotsVar)
9862 #endif // !FEATURE_EH_FUNCLETS
9863 else if (lclNum == lvaLocAllocSPvar)
9865 ilName = "LocAllocSP";
9867 #if FEATURE_EH_FUNCLETS
9868 else if (lclNum == lvaPSPSym)
9872 #endif // FEATURE_EH_FUNCLETS
9876 if (compIsForInlining())
9878 ilNum = lclNum - impInlineInfo->InlinerCompiler->info.compLocalsCount;
9882 ilNum = lclNum - info.compLocalsCount;
9887 else if (lclNum < (compIsForInlining() ? impInlineInfo->InlinerCompiler->info.compArgsCount : info.compArgsCount))
9889 if (ilNum == 0 && !info.compIsStatic)
9900 if (!lvaTable[lclNum].lvIsStructField)
9904 if (compIsForInlining())
9906 ilNum -= impInlineInfo->InlinerCompiler->info.compILargsCount;
9910 ilNum -= info.compILargsCount;
9914 *ilKindOut = ilKind;
9915 *ilNameOut = ilName;
9919 /*****************************************************************************/
9920 int Compiler::gtGetLclVarName(unsigned lclNum, char* buf, unsigned buf_remaining)
9922 char* bufp_next = buf;
9923 unsigned charsPrinted = 0;
9926 sprintf_result = sprintf_s(bufp_next, buf_remaining, "V%02u", lclNum);
9928 if (sprintf_result < 0)
9930 return sprintf_result;
9933 charsPrinted += sprintf_result;
9934 bufp_next += sprintf_result;
9935 buf_remaining -= sprintf_result;
9937 const char* ilKind = nullptr;
9938 const char* ilName = nullptr;
9941 Compiler::gtGetLclVarNameInfo(lclNum, &ilKind, &ilName, &ilNum);
9943 if (ilName != nullptr)
9945 sprintf_result = sprintf_s(bufp_next, buf_remaining, " %s", ilName);
9946 if (sprintf_result < 0)
9948 return sprintf_result;
9950 charsPrinted += sprintf_result;
9951 bufp_next += sprintf_result;
9952 buf_remaining -= sprintf_result;
9954 else if (ilKind != nullptr)
9956 sprintf_result = sprintf_s(bufp_next, buf_remaining, " %s%d", ilKind, ilNum);
9957 if (sprintf_result < 0)
9959 return sprintf_result;
9961 charsPrinted += sprintf_result;
9962 bufp_next += sprintf_result;
9963 buf_remaining -= sprintf_result;
9966 assert(charsPrinted > 0);
9967 assert(buf_remaining > 0);
9969 return (int)charsPrinted;
9972 /*****************************************************************************
9973 * Get the local var name, and create a copy of the string that can be used in debug output.
9975 char* Compiler::gtGetLclVarName(unsigned lclNum)
9978 int charsPrinted = gtGetLclVarName(lclNum, buf, sizeof(buf) / sizeof(buf[0]));
9979 if (charsPrinted < 0)
9984 char* retBuf = new (this, CMK_DebugOnly) char[charsPrinted + 1];
9985 strcpy_s(retBuf, charsPrinted + 1, buf);
9989 /*****************************************************************************/
9990 void Compiler::gtDispLclVar(unsigned lclNum, bool padForBiggestDisp)
9993 int charsPrinted = gtGetLclVarName(lclNum, buf, sizeof(buf) / sizeof(buf[0]));
9995 if (charsPrinted < 0)
10002 if (padForBiggestDisp && (charsPrinted < LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH))
10004 printf("%*c", LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH - charsPrinted, ' ');
10008 /*****************************************************************************/
10009 void Compiler::gtDispConst(GenTree* tree)
10011 assert(tree->OperKind() & GTK_CONST);
10013 switch (tree->gtOper)
10016 if (tree->IsIconHandle(GTF_ICON_STR_HDL))
10018 printf(" 0x%X \"%S\"", dspPtr(tree->gtIntCon.gtIconVal), eeGetCPString(tree->gtIntCon.gtIconVal));
10022 ssize_t dspIconVal = tree->IsIconHandle() ? dspPtr(tree->gtIntCon.gtIconVal) : tree->gtIntCon.gtIconVal;
10024 if (tree->TypeGet() == TYP_REF)
10026 assert(tree->gtIntCon.gtIconVal == 0);
10029 else if ((tree->gtIntCon.gtIconVal > -1000) && (tree->gtIntCon.gtIconVal < 1000))
10031 printf(" %ld", dspIconVal);
10032 #ifdef _TARGET_64BIT_
10034 else if ((tree->gtIntCon.gtIconVal & 0xFFFFFFFF00000000LL) != 0)
10036 printf(" 0x%llx", dspIconVal);
10041 printf(" 0x%X", dspIconVal);
10044 if (tree->IsIconHandle())
10046 switch (tree->GetIconHandleFlag())
10048 case GTF_ICON_SCOPE_HDL:
10051 case GTF_ICON_CLASS_HDL:
10054 case GTF_ICON_METHOD_HDL:
10057 case GTF_ICON_FIELD_HDL:
10060 case GTF_ICON_STATIC_HDL:
10063 case GTF_ICON_STR_HDL:
10064 unreached(); // This case is handled above
10066 case GTF_ICON_PSTR_HDL:
10069 case GTF_ICON_PTR_HDL:
10072 case GTF_ICON_VARG_HDL:
10075 case GTF_ICON_PINVKI_HDL:
10076 printf(" pinvoke");
10078 case GTF_ICON_TOKEN_HDL:
10081 case GTF_ICON_TLS_HDL:
10084 case GTF_ICON_FTN_ADDR:
10087 case GTF_ICON_CIDMID_HDL:
10090 case GTF_ICON_BBC_PTR:
10094 printf(" UNKNOWN");
10099 if ((tree->gtFlags & GTF_ICON_FIELD_OFF) != 0)
10101 printf(" field offset");
10104 if ((tree->IsReuseRegVal()) != 0)
10106 printf(" reuse reg val");
10110 gtDispFieldSeq(tree->gtIntCon.gtFieldSeq);
10115 printf(" 0x%016I64x", tree->gtLngCon.gtLconVal);
10119 if (*((__int64*)&tree->gtDblCon.gtDconVal) == (__int64)I64(0x8000000000000000))
10121 printf(" -0.00000");
10125 printf(" %#.17g", tree->gtDblCon.gtDconVal);
10129 printf("<string constant>");
10132 assert(!"unexpected constant node");
10135 gtDispRegVal(tree);
10138 void Compiler::gtDispFieldSeq(FieldSeqNode* pfsn)
10140 if (pfsn == FieldSeqStore::NotAField() || (pfsn == nullptr))
10147 while (pfsn != nullptr)
10149 assert(pfsn != FieldSeqStore::NotAField()); // Can't exist in a field sequence list except alone
10150 CORINFO_FIELD_HANDLE fldHnd = pfsn->m_fieldHnd;
10151 // First check the "pseudo" field handles...
10152 if (fldHnd == FieldSeqStore::FirstElemPseudoField)
10154 printf("#FirstElem");
10156 else if (fldHnd == FieldSeqStore::ConstantIndexPseudoField)
10158 printf("#ConstantIndex");
10162 printf("%s", eeGetFieldName(fldHnd));
10164 pfsn = pfsn->m_next;
10165 if (pfsn != nullptr)
10173 //------------------------------------------------------------------------
10174 // gtDispLeaf: Print a single leaf node to jitstdout.
10177 // tree - the tree to be printed
10178 // indentStack - the specification for the current level of indentation & arcs
10184 // 'indentStack' may be null, in which case no indentation or arcs are printed
10186 void Compiler::gtDispLeaf(GenTree* tree, IndentStack* indentStack)
10188 if (tree->OperKind() & GTK_CONST)
10194 bool isLclFld = false;
10196 switch (tree->gtOper)
10202 case GT_LCL_FLD_ADDR:
10203 case GT_STORE_LCL_FLD:
10209 case GT_LCL_VAR_ADDR:
10210 case GT_STORE_LCL_VAR:
10212 varNum = tree->gtLclVarCommon.gtLclNum;
10213 varDsc = &lvaTable[varNum];
10214 gtDispLclVar(varNum);
10215 if (tree->gtLclVarCommon.HasSsaName())
10217 if (tree->gtFlags & GTF_VAR_USEASG)
10219 assert(tree->gtFlags & GTF_VAR_DEF);
10220 printf("ud:%d->%d", tree->gtLclVarCommon.gtSsaNum, GetSsaNumForLocalVarDef(tree));
10224 printf("%s:%d", (tree->gtFlags & GTF_VAR_DEF) ? "d" : "u", tree->gtLclVarCommon.gtSsaNum);
10230 printf("[+%u]", tree->gtLclFld.gtLclOffs);
10231 gtDispFieldSeq(tree->gtLclFld.gtFieldSeq);
10234 if (varDsc->lvRegister)
10237 varDsc->PrintVarReg();
10239 #ifndef LEGACY_BACKEND
10240 else if (tree->InReg())
10242 #if CPU_LONG_USES_REGPAIR
10243 if (isRegPairType(tree->TypeGet()))
10244 printf(" %s", compRegPairName(tree->gtRegPair));
10247 printf(" %s", compRegVarName(tree->gtRegNum));
10249 #endif // !LEGACY_BACKEND
10251 if (varDsc->lvPromoted)
10253 assert(varTypeIsPromotable(varDsc) || varDsc->lvUnusedStruct);
10255 CORINFO_CLASS_HANDLE typeHnd = varDsc->lvVerTypeInfo.GetClassHandle();
10256 CORINFO_FIELD_HANDLE fldHnd;
10258 for (unsigned i = varDsc->lvFieldLclStart; i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++i)
10260 LclVarDsc* fieldVarDsc = &lvaTable[i];
10261 const char* fieldName;
10262 #if !defined(_TARGET_64BIT_)
10263 if (varTypeIsLong(varDsc))
10265 fieldName = (i == 0) ? "lo" : "hi";
10268 #endif // !defined(_TARGET_64BIT_)
10270 fldHnd = info.compCompHnd->getFieldInClass(typeHnd, fieldVarDsc->lvFldOrdinal);
10271 fieldName = eeGetFieldName(fldHnd);
10276 printIndent(indentStack);
10277 printf(" %-6s V%02u.%s (offs=0x%02x) -> ", varTypeName(fieldVarDsc->TypeGet()),
10278 tree->gtLclVarCommon.gtLclNum, fieldName, fieldVarDsc->lvFldOffset);
10281 if (fieldVarDsc->lvRegister)
10284 fieldVarDsc->PrintVarReg();
10287 if (fieldVarDsc->lvTracked && fgLocalVarLivenessDone && // Includes local variable liveness
10288 ((tree->gtFlags & GTF_VAR_DEATH) != 0))
10290 printf(" (last use)");
10294 else // a normal not-promoted lclvar
10296 if (varDsc->lvTracked && fgLocalVarLivenessDone && ((tree->gtFlags & GTF_VAR_DEATH) != 0))
10298 printf(" (last use)");
10305 gtDispLclVar(tree->gtRegVar.gtLclNum);
10306 if (isFloatRegType(tree->gtType))
10308 assert(tree->gtRegVar.gtRegNum == tree->gtRegNum);
10309 printf(" FPV%u", tree->gtRegNum);
10313 printf(" %s", compRegVarName(tree->gtRegVar.gtRegNum));
10316 varNum = tree->gtRegVar.gtLclNum;
10317 varDsc = &lvaTable[varNum];
10319 if (varDsc->lvTracked && fgLocalVarLivenessDone && ((tree->gtFlags & GTF_VAR_DEATH) != 0))
10321 printf(" (last use)");
10328 const char* methodName;
10329 const char* className;
10331 methodName = eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtVal.gtVal1, &className);
10332 printf(" %s.%s\n", className, methodName);
10337 printf(" Hnd=%#x", dspPtr(tree->gtClsVar.gtClsVarHnd));
10338 gtDispFieldSeq(tree->gtClsVar.gtFieldSeq);
10341 case GT_CLS_VAR_ADDR:
10342 printf(" Hnd=%#x", dspPtr(tree->gtClsVar.gtClsVarHnd));
10346 if (tree->gtLabel.gtLabBB)
10348 printf(" dst=BB%02u", tree->gtLabel.gtLabBB->bbNum);
10352 printf(" dst=<null>");
10359 const char* methodName;
10360 const char* className;
10362 methodName = eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtFptrVal.gtFptrMethod, &className);
10363 printf(" %s.%s\n", className, methodName);
10367 #if !FEATURE_EH_FUNCLETS
10369 printf(" endNstLvl=%d", tree->gtVal.gtVal1);
10371 #endif // !FEATURE_EH_FUNCLETS
10373 // Vanilla leaves. No qualifying information available. So do nothing
10376 case GT_START_NONGC:
10379 case GT_MEMORYBARRIER:
10381 case GT_PINVOKE_PROLOG:
10382 #ifndef LEGACY_BACKEND
10384 #endif // !LEGACY_BACKEND
10388 printf("(inl return from call ");
10389 printTreeID(tree->gtRetExpr.gtInlineCandidate);
10394 printf(" %s", getRegName(tree->gtPhysReg.gtSrcReg, varTypeIsFloating(tree)));
10398 printf(" IL offset: ");
10399 if (tree->gtStmt.gtStmtILoffsx == BAD_IL_OFFSET)
10405 printf("%d", jitGetILoffs(tree->gtStmt.gtStmtILoffsx));
10410 assert(!"don't know how to display tree leaf node");
10413 gtDispRegVal(tree);
10416 //------------------------------------------------------------------------
10417 // gtDispLeaf: Print a child node to jitstdout.
10420 // tree - the tree to be printed
10421 // indentStack - the specification for the current level of indentation & arcs
10422 // arcType - the type of arc to use for this child
10423 // msg - a contextual method (i.e. from the parent) to print
10424 // topOnly - a boolean indicating whether to print the children, or just the top node
10430 // 'indentStack' may be null, in which case no indentation or arcs are printed
10431 // 'msg' has a default value of null
10432 // 'topOnly' is an optional argument that defaults to false
10434 void Compiler::gtDispChild(GenTreePtr child,
10435 IndentStack* indentStack,
10436 IndentInfo arcType,
10437 __in_opt const char* msg, /* = nullptr */
10438 bool topOnly) /* = false */
10441 indentStack->Push(arcType);
10442 gtDispTree(child, indentStack, msg, topOnly);
10443 indentStack->Pop();
10446 #ifdef FEATURE_SIMD
10447 // Intrinsic Id to name map
10448 extern const char* const simdIntrinsicNames[] = {
10449 #define SIMD_INTRINSIC(mname, inst, id, name, r, ac, arg1, arg2, arg3, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) name,
10450 #include "simdintrinsiclist.h"
10452 #endif // FEATURE_SIMD
10454 /*****************************************************************************/
10456 void Compiler::gtDispTree(GenTreePtr tree,
10457 IndentStack* indentStack, /* = nullptr */
10458 __in __in_z __in_opt const char* msg, /* = nullptr */
10459 bool topOnly, /* = false */
10460 bool isLIR) /* = false */
10462 if (tree == nullptr)
10464 printf(" [%08X] <NULL>\n", tree);
10465 printf(""); // null string means flush
10469 if (indentStack == nullptr)
10471 indentStack = new (this, CMK_DebugOnly) IndentStack(this);
10474 if (IsUninitialized(tree))
10476 /* Value used to initalize nodes */
10477 printf("Uninitialized tree node!");
10481 if (tree->gtOper >= GT_COUNT)
10483 gtDispNode(tree, indentStack, msg, isLIR);
10484 printf("Bogus operator!");
10488 /* Is tree a leaf node? */
10490 if (tree->OperIsLeaf() || tree->OperIsLocalStore()) // local stores used to be leaves
10492 gtDispNode(tree, indentStack, msg, isLIR);
10493 gtDispLeaf(tree, indentStack);
10496 if (tree->OperIsLocalStore() && !topOnly)
10498 gtDispChild(tree->gtOp.gtOp1, indentStack, IINone);
10503 // Determine what kind of arc to propagate.
10504 IndentInfo myArc = IINone;
10505 IndentInfo lowerArc = IINone;
10506 if (indentStack->Depth() > 0)
10508 myArc = indentStack->Pop();
10512 indentStack->Push(IIArc);
10516 indentStack->Push(IIArc);
10520 indentStack->Push(IINone);
10524 indentStack->Push(IIEmbedded);
10525 lowerArc = IIEmbedded;
10528 // Should never get here; just use IINone.
10533 // Special case formatting for PHI nodes -- arg lists like calls.
10535 if (tree->OperGet() == GT_PHI)
10537 gtDispNode(tree, indentStack, msg, isLIR);
10543 if (tree->gtOp.gtOp1 != nullptr)
10545 IndentInfo arcType = IIArcTop;
10546 for (GenTreeArgList* args = tree->gtOp.gtOp1->AsArgList(); args != nullptr; args = args->Rest())
10548 if (args->Rest() == nullptr)
10550 arcType = IIArcBottom;
10552 gtDispChild(args->Current(), indentStack, arcType);
10560 /* Is it a 'simple' unary/binary operator? */
10562 const char* childMsg = nullptr;
10564 if (tree->OperIsSimple())
10568 if (tree->gtGetOp2())
10570 // Label the childMsgs of the GT_COLON operator
10571 // op2 is the then part
10573 if (tree->gtOper == GT_COLON)
10577 gtDispChild(tree->gtOp.gtOp2, indentStack, IIArcTop, childMsg, topOnly);
10581 // Now, get the right type of arc for this node
10582 if (myArc != IINone)
10584 indentStack->Pop();
10585 indentStack->Push(myArc);
10588 gtDispNode(tree, indentStack, msg, isLIR);
10590 // Propagate lowerArc to the lower children.
10591 if (indentStack->Depth() > 0)
10593 (void)indentStack->Pop();
10594 indentStack->Push(lowerArc);
10597 if (tree->gtOper == GT_CAST)
10599 /* Format a message that explains the effect of this GT_CAST */
10601 var_types fromType = genActualType(tree->gtCast.CastOp()->TypeGet());
10602 var_types toType = tree->CastToType();
10603 var_types finalType = tree->TypeGet();
10605 /* if GTF_UNSIGNED is set then force fromType to an unsigned type */
10606 if (tree->gtFlags & GTF_UNSIGNED)
10608 fromType = genUnsignedType(fromType);
10611 if (finalType != toType)
10613 printf(" %s <-", varTypeName(finalType));
10616 printf(" %s <- %s", varTypeName(toType), varTypeName(fromType));
10619 if (tree->gtOper == GT_OBJ && (tree->gtFlags & GTF_VAR_DEATH))
10621 printf(" (last use)");
10624 IndirectAssignmentAnnotation* pIndirAnnote;
10625 if (tree->gtOper == GT_ASG && GetIndirAssignMap()->Lookup(tree, &pIndirAnnote))
10627 printf(" indir assign of V%02d:", pIndirAnnote->m_lclNum);
10628 if (pIndirAnnote->m_isEntire)
10630 printf("d:%d", pIndirAnnote->m_defSsaNum);
10634 printf("ud:%d->%d", pIndirAnnote->m_useSsaNum, pIndirAnnote->m_defSsaNum);
10638 if (tree->gtOper == GT_INTRINSIC)
10640 switch (tree->gtIntrinsic.gtIntrinsicId)
10642 case CORINFO_INTRINSIC_Sin:
10645 case CORINFO_INTRINSIC_Cos:
10648 case CORINFO_INTRINSIC_Sqrt:
10651 case CORINFO_INTRINSIC_Abs:
10654 case CORINFO_INTRINSIC_Round:
10657 case CORINFO_INTRINSIC_Cosh:
10660 case CORINFO_INTRINSIC_Sinh:
10663 case CORINFO_INTRINSIC_Tan:
10666 case CORINFO_INTRINSIC_Tanh:
10669 case CORINFO_INTRINSIC_Asin:
10672 case CORINFO_INTRINSIC_Acos:
10675 case CORINFO_INTRINSIC_Atan:
10678 case CORINFO_INTRINSIC_Atan2:
10681 case CORINFO_INTRINSIC_Log10:
10684 case CORINFO_INTRINSIC_Pow:
10687 case CORINFO_INTRINSIC_Exp:
10690 case CORINFO_INTRINSIC_Ceiling:
10691 printf(" ceiling");
10693 case CORINFO_INTRINSIC_Floor:
10696 case CORINFO_INTRINSIC_Object_GetType:
10697 printf(" objGetType");
10705 #ifdef FEATURE_SIMD
10706 if (tree->gtOper == GT_SIMD)
10708 printf(" %s %s", varTypeName(tree->gtSIMD.gtSIMDBaseType),
10709 simdIntrinsicNames[tree->gtSIMD.gtSIMDIntrinsicID]);
10711 #endif // FEATURE_SIMD
10713 gtDispRegVal(tree);
10717 if (!topOnly && tree->gtOp.gtOp1)
10720 // Label the child of the GT_COLON operator
10721 // op1 is the else part
10723 if (tree->gtOper == GT_COLON)
10727 else if (tree->gtOper == GT_QMARK)
10731 gtDispChild(tree->gtOp.gtOp1, indentStack, IIArcBottom, childMsg, topOnly);
10737 // Now, get the right type of arc for this node
10738 if (myArc != IINone)
10740 indentStack->Pop();
10741 indentStack->Push(myArc);
10743 gtDispNode(tree, indentStack, msg, isLIR);
10745 // Propagate lowerArc to the lower children.
10746 if (indentStack->Depth() > 0)
10748 (void)indentStack->Pop();
10749 indentStack->Push(lowerArc);
10752 // See what kind of a special operator we have here, and handle its special children.
10754 switch (tree->gtOper)
10757 printf(" %s", eeGetFieldName(tree->gtField.gtFldHnd), 0);
10759 if (tree->gtField.gtFldObj && !topOnly)
10763 gtDispChild(tree->gtField.gtFldObj, indentStack, IIArcBottom);
10767 gtDispRegVal(tree);
10775 assert(tree->gtFlags & GTF_CALL);
10776 unsigned numChildren = tree->NumChildren();
10777 GenTree* lastChild = nullptr;
10778 if (numChildren != 0)
10780 lastChild = tree->GetChild(numChildren - 1);
10783 if (tree->gtCall.gtCallType != CT_INDIRECT)
10785 const char* methodName;
10786 const char* className;
10788 methodName = eeGetMethodName(tree->gtCall.gtCallMethHnd, &className);
10790 printf(" %s.%s", className, methodName);
10793 if ((tree->gtFlags & GTF_CALL_UNMANAGED) && (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_FRAME_VAR_DEATH))
10795 printf(" (FramesRoot last use)");
10798 if (((tree->gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0) && (tree->gtCall.gtInlineCandidateInfo != nullptr) &&
10799 (tree->gtCall.gtInlineCandidateInfo->exactContextHnd != nullptr))
10801 printf(" (exactContextHnd=0x%p)", dspPtr(tree->gtCall.gtInlineCandidateInfo->exactContextHnd));
10805 if (tree->IsMultiRegCall())
10807 gtDispRegVal(tree);
10818 if ((tree->gtCall.gtCallObjp != nullptr) && (tree->gtCall.gtCallObjp->gtOper != GT_NOP) &&
10819 (!tree->gtCall.gtCallObjp->IsArgPlaceHolderNode()))
10821 if (tree->gtCall.gtCallObjp->gtOper == GT_ASG)
10823 sprintf_s(bufp, sizeof(buf), "this SETUP%c", 0);
10827 sprintf_s(bufp, sizeof(buf), "this in %s%c", compRegVarName(REG_ARG_0), 0);
10829 gtDispChild(tree->gtCall.gtCallObjp, indentStack,
10830 (tree->gtCall.gtCallObjp == lastChild) ? IIArcBottom : IIArc, bufp, topOnly);
10833 if (tree->gtCall.gtCallArgs)
10835 gtDispArgList(tree, indentStack);
10838 if (tree->gtCall.gtCallType == CT_INDIRECT)
10840 gtDispChild(tree->gtCall.gtCallAddr, indentStack,
10841 (tree->gtCall.gtCallAddr == lastChild) ? IIArcBottom : IIArc, "calli tgt", topOnly);
10844 if (tree->gtCall.gtControlExpr != nullptr)
10846 gtDispChild(tree->gtCall.gtControlExpr, indentStack,
10847 (tree->gtCall.gtControlExpr == lastChild) ? IIArcBottom : IIArc, "control expr",
10851 #if !FEATURE_FIXED_OUT_ARGS
10852 regList list = tree->gtCall.regArgList;
10854 /* process the late argument list */
10855 int lateArgIndex = 0;
10856 for (GenTreeArgList* lateArgs = tree->gtCall.gtCallLateArgs; lateArgs;
10857 (lateArgIndex++, lateArgs = lateArgs->Rest()))
10861 argx = lateArgs->Current();
10863 IndentInfo arcType = (lateArgs->Rest() == nullptr) ? IIArcBottom : IIArc;
10864 gtGetLateArgMsg(tree, argx, lateArgIndex, -1, bufp, sizeof(buf));
10865 gtDispChild(argx, indentStack, arcType, bufp, topOnly);
10876 gtDispChild(tree->gtStmt.gtStmtExpr, indentStack, IIArcBottom);
10886 gtDispChild(tree->gtArrElem.gtArrObj, indentStack, IIArc, nullptr, topOnly);
10889 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
10891 IndentInfo arcType = ((dim + 1) == tree->gtArrElem.gtArrRank) ? IIArcBottom : IIArc;
10892 gtDispChild(tree->gtArrElem.gtArrInds[dim], indentStack, arcType, nullptr, topOnly);
10897 case GT_ARR_OFFSET:
10902 gtDispChild(tree->gtArrOffs.gtOffset, indentStack, IIArc, nullptr, topOnly);
10903 gtDispChild(tree->gtArrOffs.gtIndex, indentStack, IIArc, nullptr, topOnly);
10904 gtDispChild(tree->gtArrOffs.gtArrObj, indentStack, IIArcBottom, nullptr, topOnly);
10913 gtDispChild(tree->gtCmpXchg.gtOpLocation, indentStack, IIArc, nullptr, topOnly);
10914 gtDispChild(tree->gtCmpXchg.gtOpValue, indentStack, IIArc, nullptr, topOnly);
10915 gtDispChild(tree->gtCmpXchg.gtOpComparand, indentStack, IIArcBottom, nullptr, topOnly);
10919 case GT_ARR_BOUNDS_CHECK:
10920 #ifdef FEATURE_SIMD
10922 #endif // FEATURE_SIMD
10927 gtDispChild(tree->gtBoundsChk.gtArrLen, indentStack, IIArc, nullptr, topOnly);
10928 gtDispChild(tree->gtBoundsChk.gtIndex, indentStack, IIArcBottom, nullptr, topOnly);
10933 printf("<DON'T KNOW HOW TO DISPLAY THIS NODE> :");
10934 printf(""); // null string means flush
10939 //------------------------------------------------------------------------
10940 // gtGetArgMsg: Construct a message about the given argument
10943 // call - The call for which 'arg' is an argument
10944 // arg - The argument for which a message should be constructed
10945 // argNum - The ordinal number of the arg in the argument list
10946 // listCount - When printing in LIR form this is the count for a multireg GT_LIST
10947 // or -1 if we are not printing in LIR form
10948 // bufp - A pointer to the buffer into which the message is written
10949 // bufLength - The length of the buffer pointed to by bufp
10952 // No return value, but bufp is written.
10955 // 'call' must be a call node
10956 // 'arg' must be an argument to 'call' (else gtArgEntryByNode will assert)
10958 void Compiler::gtGetArgMsg(
10959 GenTreePtr call, GenTreePtr arg, unsigned argNum, int listCount, char* bufp, unsigned bufLength)
10961 if (call->gtCall.gtCallLateArgs != nullptr)
10963 fgArgTabEntryPtr curArgTabEntry = gtArgEntryByArgNum(call, argNum);
10964 assert(curArgTabEntry);
10966 if (arg->gtFlags & GTF_LATE_ARG)
10968 sprintf_s(bufp, bufLength, "arg%d SETUP%c", argNum, 0);
10972 #if FEATURE_FIXED_OUT_ARGS
10973 if (listCount == -1)
10975 sprintf_s(bufp, bufLength, "arg%d out+%02x%c", argNum, curArgTabEntry->slotNum * TARGET_POINTER_SIZE,
10978 else // listCount is 0,1,2 or 3
10980 assert(listCount <= MAX_ARG_REG_COUNT);
10981 sprintf_s(bufp, bufLength, "arg%d out+%02x%c", argNum,
10982 (curArgTabEntry->slotNum + listCount) * TARGET_POINTER_SIZE, 0);
10985 sprintf_s(bufp, bufLength, "arg%d on STK%c", argNum, 0);
10991 sprintf_s(bufp, bufLength, "arg%d%c", argNum, 0);
10995 //------------------------------------------------------------------------
10996 // gtGetLateArgMsg: Construct a message about the given argument
10999 // call - The call for which 'arg' is an argument
11000 // argx - The argument for which a message should be constructed
11001 // lateArgIndex - The ordinal number of the arg in the lastArg list
11002 // listCount - When printing in LIR form this is the count for a multireg GT_LIST
11003 // or -1 if we are not printing in LIR form
11004 // bufp - A pointer to the buffer into which the message is written
11005 // bufLength - The length of the buffer pointed to by bufp
11008 // No return value, but bufp is written.
11011 // 'call' must be a call node
11012 // 'arg' must be an argument to 'call' (else gtArgEntryByNode will assert)
11014 void Compiler::gtGetLateArgMsg(
11015 GenTreePtr call, GenTreePtr argx, int lateArgIndex, int listCount, char* bufp, unsigned bufLength)
11017 assert(!argx->IsArgPlaceHolderNode()); // No place holders nodes are in gtCallLateArgs;
11019 fgArgTabEntryPtr curArgTabEntry = gtArgEntryByLateArgIndex(call, lateArgIndex);
11020 assert(curArgTabEntry);
11021 regNumber argReg = curArgTabEntry->regNum;
11023 #if !FEATURE_FIXED_OUT_ARGS
11024 assert(lateArgIndex < call->gtCall.regArgListCount);
11025 assert(argReg == call->gtCall.regArgList[lateArgIndex]);
11027 if (argReg == REG_STK)
11029 sprintf_s(bufp, bufLength, "arg%d in out+%02x%c", curArgTabEntry->argNum,
11030 curArgTabEntry->slotNum * TARGET_POINTER_SIZE, 0);
11035 if (gtArgIsThisPtr(curArgTabEntry))
11037 sprintf_s(bufp, bufLength, "this in %s%c", compRegVarName(argReg), 0);
11041 #if FEATURE_MULTIREG_ARGS
11042 if (curArgTabEntry->numRegs >= 2)
11044 regNumber otherRegNum;
11045 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
11046 assert(curArgTabEntry->numRegs == 2);
11047 otherRegNum = curArgTabEntry->otherRegNum;
11049 otherRegNum = (regNumber)(((unsigned)curArgTabEntry->regNum) + curArgTabEntry->numRegs - 1);
11050 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
11052 if (listCount == -1)
11054 char seperator = (curArgTabEntry->numRegs == 2) ? ',' : '-';
11056 sprintf_s(bufp, bufLength, "arg%d %s%c%s%c", curArgTabEntry->argNum, compRegVarName(argReg),
11057 seperator, compRegVarName(otherRegNum), 0);
11059 else // listCount is 0,1,2 or 3
11061 assert(listCount <= MAX_ARG_REG_COUNT);
11062 regNumber curReg = (listCount == 1) ? otherRegNum : (regNumber)((unsigned)(argReg) + listCount);
11063 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", curArgTabEntry->argNum, listCount,
11064 compRegVarName(curReg), 0);
11070 sprintf_s(bufp, bufLength, "arg%d in %s%c", curArgTabEntry->argNum, compRegVarName(argReg), 0);
11076 //------------------------------------------------------------------------
11077 // gtDispArgList: Dump the tree for a call arg list
11080 // tree - The call for which 'arg' is an argument
11081 // indentStack - the specification for the current level of indentation & arcs
11087 // 'tree' must be a call node
11089 void Compiler::gtDispArgList(GenTreePtr tree, IndentStack* indentStack)
11091 GenTree* args = tree->gtCall.gtCallArgs;
11092 unsigned argnum = 0;
11093 const int BufLength = 256;
11094 char buf[BufLength];
11095 char* bufp = &buf[0];
11096 unsigned numChildren = tree->NumChildren();
11097 assert(numChildren != 0);
11098 bool argListIsLastChild = (args == tree->GetChild(numChildren - 1));
11100 IndentInfo arcType = IIArc;
11101 if (tree->gtCall.gtCallObjp != nullptr)
11106 while (args != nullptr)
11108 assert(args->gtOper == GT_LIST);
11109 GenTree* arg = args->gtOp.gtOp1;
11110 if (!arg->IsNothingNode() && !arg->IsArgPlaceHolderNode())
11112 gtGetArgMsg(tree, arg, argnum, -1, bufp, BufLength);
11113 if (argListIsLastChild && (args->gtOp.gtOp2 == nullptr))
11115 arcType = IIArcBottom;
11117 gtDispChild(arg, indentStack, arcType, bufp, false);
11119 args = args->gtOp.gtOp2;
11124 //------------------------------------------------------------------------
11125 // gtDispArgList: Dump the tree for a call arg list
11128 // tree - The call for which 'arg' is an argument
11129 // indentStack - the specification for the current level of indentation & arcs
11135 // 'tree' must be a GT_LIST node
11137 void Compiler::gtDispTreeList(GenTreePtr tree, IndentStack* indentStack /* = nullptr */)
11139 for (/*--*/; tree != nullptr; tree = tree->gtNext)
11141 gtDispTree(tree, indentStack);
11146 //------------------------------------------------------------------------
11147 // Compiler::gtDispRange: dumps a range of LIR.
11150 // range - the range of LIR to display.
11152 void Compiler::gtDispRange(LIR::ReadOnlyRange const& range)
11154 for (GenTree* node : range)
11156 gtDispLIRNode(node);
11160 //------------------------------------------------------------------------
11161 // Compiler::gtDispTreeRange: dumps the LIR range that contains all of the
11162 // nodes in the dataflow tree rooted at a given
11166 // containingRange - the LIR range that contains the root node.
11167 // tree - the root of the dataflow tree.
11169 void Compiler::gtDispTreeRange(LIR::Range& containingRange, GenTree* tree)
11172 gtDispRange(containingRange.GetTreeRange(tree, &unused));
11175 //------------------------------------------------------------------------
11176 // Compiler::gtDispLIRNode: dumps a single LIR node.
11179 // node - the LIR node to dump.
11181 void Compiler::gtDispLIRNode(GenTree* node)
11183 auto displayOperand = [](GenTree* operand, const char* message, IndentInfo operandArc, IndentStack& indentStack)
11185 assert(operand != nullptr);
11186 assert(message != nullptr);
11188 // 49 spaces for alignment
11189 printf("%-49s", "");
11191 indentStack.Push(operandArc);
11192 indentStack.print();
11194 operandArc = IIArc;
11196 printf(" t%-5d %-6s %s\n", operand->gtTreeID, varTypeName(operand->TypeGet()), message);
11200 IndentStack indentStack(this);
11202 const int bufLength = 256;
11203 char buf[bufLength];
11205 const bool nodeIsCall = node->IsCall();
11207 int numCallEarlyArgs = 0;
11210 GenTreeCall* call = node->AsCall();
11211 for (GenTreeArgList* args = call->gtCallArgs; args != nullptr; args = args->Rest())
11213 if (!args->Current()->IsArgPlaceHolderNode() && args->Current()->IsValue())
11215 numCallEarlyArgs++;
11221 IndentInfo operandArc = IIArcTop;
11222 int callArgNumber = 0;
11223 for (GenTree* operand : node->Operands())
11225 if (operand->IsArgPlaceHolderNode() || !operand->IsValue())
11227 // Either of these situations may happen with calls.
11233 GenTreeCall* call = node->AsCall();
11234 if (operand == call->gtCallObjp)
11236 sprintf_s(buf, sizeof(buf), "this in %s", compRegVarName(REG_ARG_0));
11237 displayOperand(operand, buf, operandArc, indentStack);
11239 else if (operand == call->gtCallAddr)
11241 displayOperand(operand, "calli tgt", operandArc, indentStack);
11243 else if (operand == call->gtControlExpr)
11245 displayOperand(operand, "control expr", operandArc, indentStack);
11247 else if (operand == call->gtCallCookie)
11249 displayOperand(operand, "cookie", operandArc, indentStack);
11253 int callLateArgNumber = callArgNumber - numCallEarlyArgs;
11254 if (operand->OperGet() == GT_LIST)
11257 for (GenTreeArgList* element = operand->AsArgList(); element != nullptr; element = element->Rest())
11259 operand = element->Current();
11260 if (callLateArgNumber < 0)
11262 gtGetArgMsg(call, operand, callArgNumber, listIndex, buf, sizeof(buf));
11266 gtGetLateArgMsg(call, operand, callLateArgNumber, listIndex, buf, sizeof(buf));
11269 displayOperand(operand, buf, operandArc, indentStack);
11270 operandArc = IIArc;
11275 if (callLateArgNumber < 0)
11277 gtGetArgMsg(call, operand, callArgNumber, -1, buf, sizeof(buf));
11281 gtGetLateArgMsg(call, operand, callLateArgNumber, -1, buf, sizeof(buf));
11284 displayOperand(operand, buf, operandArc, indentStack);
11292 displayOperand(operand, "", operandArc, indentStack);
11295 operandArc = IIArc;
11298 // Visit the operator
11299 const bool topOnly = true;
11300 const bool isLIR = true;
11301 gtDispTree(node, &indentStack, nullptr, topOnly, isLIR);
11306 /*****************************************************************************/
11309 /*****************************************************************************
11311 * Check if the given node can be folded,
11312 * and call the methods to perform the folding
11315 GenTreePtr Compiler::gtFoldExpr(GenTreePtr tree)
11317 unsigned kind = tree->OperKind();
11319 /* We must have a simple operation to fold */
11321 // If we're in CSE, it's not safe to perform tree
11322 // folding given that it can will potentially
11323 // change considered CSE candidates.
11324 if (optValnumCSE_phase)
11329 if (!(kind & GTK_SMPOP))
11334 GenTreePtr op1 = tree->gtOp.gtOp1;
11336 /* Filter out non-foldable trees that can have constant children */
11338 assert(kind & (GTK_UNOP | GTK_BINOP));
11339 switch (tree->gtOper)
11349 /* try to fold the current node */
11351 if ((kind & GTK_UNOP) && op1)
11353 if (op1->OperKind() & GTK_CONST)
11355 return gtFoldExprConst(tree);
11358 else if ((kind & GTK_BINOP) && op1 && tree->gtOp.gtOp2 &&
11359 // Don't take out conditionals for debugging
11360 !((opts.compDbgCode || opts.MinOpts()) && tree->OperIsCompare()))
11362 GenTreePtr op2 = tree->gtOp.gtOp2;
11364 // The atomic operations are exempted here because they are never computable statically;
11365 // one of their arguments is an address.
11366 if (((op1->OperKind() & op2->OperKind()) & GTK_CONST) && !tree->OperIsAtomicOp())
11368 /* both nodes are constants - fold the expression */
11369 return gtFoldExprConst(tree);
11371 else if ((op1->OperKind() | op2->OperKind()) & GTK_CONST)
11373 /* at least one is a constant - see if we have a
11374 * special operator that can use only one constant
11375 * to fold - e.g. booleans */
11377 return gtFoldExprSpecial(tree);
11379 else if (tree->OperIsCompare())
11381 /* comparisons of two local variables can sometimes be folded */
11383 return gtFoldExprCompare(tree);
11385 else if (op2->OperGet() == GT_COLON)
11387 assert(tree->OperGet() == GT_QMARK);
11389 GenTreePtr colon_op1 = op2->gtOp.gtOp1;
11390 GenTreePtr colon_op2 = op2->gtOp.gtOp2;
11392 if (gtCompareTree(colon_op1, colon_op2))
11394 // Both sides of the GT_COLON are the same tree
11396 GenTreePtr sideEffList = nullptr;
11397 gtExtractSideEffList(op1, &sideEffList);
11399 fgUpdateRefCntForExtract(op1, sideEffList); // Decrement refcounts for op1, Keeping any side-effects
11400 fgUpdateRefCntForExtract(colon_op1, nullptr); // Decrement refcounts for colon_op1
11402 // Clear colon flags only if the qmark itself is not conditionaly executed
11403 if ((tree->gtFlags & GTF_COLON_COND) == 0)
11405 fgWalkTreePre(&colon_op2, gtClearColonCond);
11408 if (sideEffList == nullptr)
11410 // No side-effects, just return colon_op2
11418 printf("\nIdentical GT_COLON trees with side effects! Extracting side effects...\n");
11419 gtDispTree(sideEffList);
11423 // Change the GT_COLON into a GT_COMMA node with the side-effects
11424 op2->ChangeOper(GT_COMMA);
11425 op2->gtFlags |= (sideEffList->gtFlags & GTF_ALL_EFFECT);
11426 op2->gtOp.gtOp1 = sideEffList;
11433 /* Return the original node (folded/bashed or not) */
11438 /*****************************************************************************
11440 * Some comparisons can be folded:
11443 * classVarA == classVarA
11444 * locA + locB == locB + locA
11448 GenTreePtr Compiler::gtFoldExprCompare(GenTreePtr tree)
11450 GenTreePtr op1 = tree->gtOp.gtOp1;
11451 GenTreePtr op2 = tree->gtOp.gtOp2;
11453 assert(tree->OperIsCompare());
11455 /* Filter out cases that cannot be folded here */
11457 /* Do not fold floats or doubles (e.g. NaN != Nan) */
11459 if (varTypeIsFloating(op1->TypeGet()))
11464 /* Currently we can only fold when the two subtrees exactly match */
11466 if ((tree->gtFlags & GTF_SIDE_EFFECT) || GenTree::Compare(op1, op2, true) == false)
11468 return tree; /* return unfolded tree */
11473 switch (tree->gtOper)
11478 cons = gtNewIconNode(true); /* Folds to GT_CNS_INT(true) */
11484 cons = gtNewIconNode(false); /* Folds to GT_CNS_INT(false) */
11488 assert(!"Unexpected relOp");
11492 /* The node has beeen folded into 'cons' */
11496 if (!fgIsInlining())
11498 fgMorphTreeDone(cons);
11503 cons->gtNext = tree->gtNext;
11504 cons->gtPrev = tree->gtPrev;
11506 if (lvaLocalVarRefCounted)
11508 lvaRecursiveDecRefCounts(tree);
11513 /*****************************************************************************
11515 * Some binary operators can be folded even if they have only one
11516 * operand constant - e.g. boolean operators, add with 0
11517 * multiply with 1, etc
11520 GenTreePtr Compiler::gtFoldExprSpecial(GenTreePtr tree)
11522 GenTreePtr op1 = tree->gtOp.gtOp1;
11523 GenTreePtr op2 = tree->gtOp.gtOp2;
11524 genTreeOps oper = tree->OperGet();
11526 GenTreePtr op, cons;
11529 assert(tree->OperKind() & GTK_BINOP);
11531 /* Filter out operators that cannot be folded here */
11532 if (oper == GT_CAST)
11537 /* We only consider TYP_INT for folding
11538 * Do not fold pointer arithmetic (e.g. addressing modes!) */
11540 if (oper != GT_QMARK && !varTypeIsIntOrI(tree->gtType))
11545 /* Find out which is the constant node */
11547 if (op1->IsCnsIntOrI())
11552 else if (op2->IsCnsIntOrI())
11562 /* Get the constant value */
11564 val = cons->gtIntConCommon.IconValue();
11566 /* Here op is the non-constant operand, val is the constant,
11567 first is true if the constant is op1 */
11574 // Optimize boxed value classes; these are always false. This IL is
11575 // generated when a generic value is tested against null:
11576 // <T> ... foo(T x) { ... if ((object)x == null) ...
11577 if (val == 0 && op->IsBoxedValue())
11579 // Change the assignment node so we don't generate any code for it.
11581 GenTreePtr asgStmt = op->gtBox.gtAsgStmtWhenInlinedBoxValue;
11582 assert(asgStmt->gtOper == GT_STMT);
11583 GenTreePtr asg = asgStmt->gtStmt.gtStmtExpr;
11584 assert(asg->gtOper == GT_ASG);
11588 printf("Bashing ");
11590 printf(" to NOP as part of dead box operation\n");
11594 asg->gtBashToNOP();
11596 op = gtNewIconNode(oper == GT_NE);
11599 if (!fgIsInlining())
11601 fgMorphTreeDone(op);
11606 op->gtNext = tree->gtNext;
11607 op->gtPrev = tree->gtPrev;
11609 fgSetStmtSeq(asgStmt);
11630 /* Multiply by zero - return the 'zero' node, but not if side effects */
11631 if (!(op->gtFlags & GTF_SIDE_EFFECT))
11633 if (lvaLocalVarRefCounted)
11635 lvaRecursiveDecRefCounts(op);
11646 if ((op2 == cons) && (val == 1) && !(op1->OperKind() & GTK_CONST))
11654 if ((op2 == cons) && (val == 0) && !(op1->OperKind() & GTK_CONST))
11663 /* AND with zero - return the 'zero' node, but not if side effects */
11665 if (!(op->gtFlags & GTF_SIDE_EFFECT))
11667 if (lvaLocalVarRefCounted)
11669 lvaRecursiveDecRefCounts(op);
11677 /* The GTF_BOOLEAN flag is set for nodes that are part
11678 * of a boolean expression, thus all their children
11679 * are known to evaluate to only 0 or 1 */
11681 if (tree->gtFlags & GTF_BOOLEAN)
11684 /* The constant value must be 1
11685 * AND with 1 stays the same */
11697 else if (tree->gtFlags & GTF_BOOLEAN)
11699 /* The constant value must be 1 - OR with 1 is 1 */
11703 /* OR with one - return the 'one' node, but not if side effects */
11705 if (!(op->gtFlags & GTF_SIDE_EFFECT))
11707 if (lvaLocalVarRefCounted)
11709 lvaRecursiveDecRefCounts(op);
11731 else if (!(op->gtFlags & GTF_SIDE_EFFECT))
11733 if (lvaLocalVarRefCounted)
11735 lvaRecursiveDecRefCounts(op);
11745 assert(op1 == cons && op2 == op && op2->gtOper == GT_COLON);
11746 assert(op2->gtOp.gtOp1 && op2->gtOp.gtOp2);
11748 assert(val == 0 || val == 1);
11750 GenTree* opToDelete;
11753 op = op2->AsColon()->ThenNode();
11754 opToDelete = op2->AsColon()->ElseNode();
11758 op = op2->AsColon()->ElseNode();
11759 opToDelete = op2->AsColon()->ThenNode();
11761 if (lvaLocalVarRefCounted)
11763 lvaRecursiveDecRefCounts(opToDelete);
11766 // Clear colon flags only if the qmark itself is not conditionaly executed
11767 if ((tree->gtFlags & GTF_COLON_COND) == 0)
11769 fgWalkTreePre(&op, gtClearColonCond);
11779 /* The node is not foldable */
11785 /* The node has beeen folded into 'op' */
11787 // If there was an assigment update, we just morphed it into
11788 // a use, update the flags appropriately
11789 if (op->gtOper == GT_LCL_VAR)
11791 assert((tree->OperKind() & GTK_ASGOP) || (op->gtFlags & (GTF_VAR_USEASG | GTF_VAR_USEDEF | GTF_VAR_DEF)) == 0);
11793 op->gtFlags &= ~(GTF_VAR_USEASG | GTF_VAR_USEDEF | GTF_VAR_DEF);
11796 op->gtNext = tree->gtNext;
11797 op->gtPrev = tree->gtPrev;
11802 /*****************************************************************************
11804 * Fold the given constant tree.
11808 #pragma warning(push)
11809 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
11811 GenTreePtr Compiler::gtFoldExprConst(GenTreePtr tree)
11813 unsigned kind = tree->OperKind();
11815 SSIZE_T i1, i2, itemp;
11816 INT64 lval1, lval2, ltemp;
11819 var_types switchType;
11820 FieldSeqNode* fieldSeq = FieldSeqStore::NotAField(); // default unless we override it when folding
11822 assert(kind & (GTK_UNOP | GTK_BINOP));
11824 GenTreePtr op1 = tree->gtOp.gtOp1;
11825 GenTreePtr op2 = tree->gtGetOp2();
11827 if (!opts.OptEnabled(CLFLG_CONSTANTFOLD))
11832 if (tree->OperGet() == GT_NOP)
11837 #ifdef FEATURE_SIMD
11838 if (tree->OperGet() == GT_SIMD)
11842 #endif // FEATURE_SIMD
11844 if (tree->gtOper == GT_ALLOCOBJ)
11849 if (kind & GTK_UNOP)
11851 assert(op1->OperKind() & GTK_CONST);
11853 switch (op1->gtType)
11857 /* Fold constant INT unary operator */
11858 assert(op1->gtIntCon.ImmedValCanBeFolded(this, tree->OperGet()));
11859 i1 = (int)op1->gtIntCon.gtIconVal;
11861 // If we fold a unary oper, then the folded constant
11862 // is considered a ConstantIndexField if op1 was one
11865 if ((op1->gtIntCon.gtFieldSeq != nullptr) && op1->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
11867 fieldSeq = op1->gtIntCon.gtFieldSeq;
11870 switch (tree->gtOper)
11882 // assert (genActualType(tree->CastToType()) == tree->gtType);
11883 switch (tree->CastToType())
11886 itemp = INT32(INT8(i1));
11890 itemp = INT32(INT16(i1));
11892 if (tree->gtOverflow() && ((itemp != i1) || ((tree->gtFlags & GTF_UNSIGNED) && i1 < 0)))
11900 itemp = INT32(UINT16(i1));
11901 if (tree->gtOverflow())
11913 itemp = INT32(UINT8(i1));
11914 if (tree->gtOverflow())
11925 if (!(tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && i1 < 0)
11932 if ((tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && i1 < 0)
11939 if (!(tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && i1 < 0)
11941 op1->ChangeOperConst(GT_CNS_NATIVELONG); // need type of oper to be same as tree
11942 op1->gtType = TYP_LONG;
11943 // We don't care about the value as we are throwing an exception
11946 lval1 = UINT64(UINT32(i1));
11950 if (tree->gtFlags & GTF_UNSIGNED)
11952 lval1 = INT64(UINT32(i1));
11956 lval1 = INT64(INT32(i1));
11961 if (tree->gtFlags & GTF_UNSIGNED)
11963 f1 = forceCastToFloat(UINT32(i1));
11967 f1 = forceCastToFloat(INT32(i1));
11973 if (tree->gtFlags & GTF_UNSIGNED)
11975 d1 = (double)UINT32(i1);
11979 d1 = (double)INT32(i1);
11984 assert(!"BAD_TYP");
11997 /* Fold constant LONG unary operator */
11999 assert(op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()));
12000 lval1 = op1->gtIntConCommon.LngValue();
12002 switch (tree->gtOper)
12014 assert(genActualType(tree->CastToType()) == tree->gtType);
12015 switch (tree->CastToType())
12018 i1 = INT32(INT8(lval1));
12019 goto CHECK_INT_OVERFLOW;
12022 i1 = INT32(INT16(lval1));
12023 goto CHECK_INT_OVERFLOW;
12026 i1 = INT32(UINT16(lval1));
12027 goto CHECK_UINT_OVERFLOW;
12030 i1 = INT32(UINT8(lval1));
12031 goto CHECK_UINT_OVERFLOW;
12036 CHECK_INT_OVERFLOW:
12037 if (tree->gtOverflow())
12043 if ((tree->gtFlags & GTF_UNSIGNED) && i1 < 0)
12051 i1 = UINT32(lval1);
12053 CHECK_UINT_OVERFLOW:
12054 if (tree->gtOverflow() && UINT32(i1) != lval1)
12061 if (!(tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && lval1 < 0)
12068 if ((tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && lval1 < 0)
12076 if ((tree->gtFlags & GTF_UNSIGNED) && lval1 < 0)
12078 d1 = FloatingPointUtils::convertUInt64ToDouble((unsigned __int64)lval1);
12082 d1 = (double)lval1;
12085 if (tree->CastToType() == TYP_FLOAT)
12087 f1 = forceCastToFloat(d1); // truncate precision
12092 assert(!"BAD_TYP");
12105 assert(op1->gtOper == GT_CNS_DBL);
12107 /* Fold constant DOUBLE unary operator */
12109 d1 = op1->gtDblCon.gtDconVal;
12111 switch (tree->gtOper)
12120 if (tree->gtOverflowEx())
12125 assert(genActualType(tree->CastToType()) == tree->gtType);
12127 if ((op1->gtType == TYP_FLOAT && !_finite(forceCastToFloat(d1))) ||
12128 (op1->gtType == TYP_DOUBLE && !_finite(d1)))
12130 // The floating point constant is not finite. The ECMA spec says, in
12131 // III 3.27, that "...if overflow occurs converting a floating point type
12132 // to an integer, ..., the value returned is unspecified." However, it would
12133 // at least be desirable to have the same value returned for casting an overflowing
12134 // constant to an int as would obtained by passing that constant as a parameter
12135 // then casting that parameter to an int type. We will assume that the C compiler's
12136 // cast logic will yield the desired result (and trust testing to tell otherwise).
12137 // Cross-compilation is an issue here; if that becomes an important scenario, we should
12138 // capture the target-specific values of overflow casts to the various integral types as
12139 // constants in a target-specific function.
12140 CLANG_FORMAT_COMMENT_ANCHOR;
12142 #ifdef _TARGET_XARCH_
12143 // Don't fold conversions of +inf/-inf to integral value as the value returned by JIT helper
12144 // doesn't match with the C compiler's cast result.
12146 #else //!_TARGET_XARCH_
12148 switch (tree->CastToType())
12151 i1 = ssize_t(INT8(d1));
12154 i1 = ssize_t(UINT8(d1));
12157 i1 = ssize_t(INT16(d1));
12160 i1 = ssize_t(UINT16(d1));
12163 i1 = ssize_t(INT32(d1));
12166 i1 = ssize_t(UINT32(d1));
12172 lval1 = UINT64(d1);
12176 if (op1->gtType == TYP_FLOAT)
12177 d1 = forceCastToFloat(d1); // it's only !_finite() after this conversion
12182 #endif //!_TARGET_XARCH_
12185 switch (tree->CastToType())
12188 i1 = INT32(INT8(d1));
12192 i1 = INT32(INT16(d1));
12196 i1 = INT32(UINT16(d1));
12200 i1 = INT32(UINT8(d1));
12208 i1 = forceCastToUInt32(d1);
12216 lval1 = FloatingPointUtils::convertDoubleToUInt64(d1);
12220 d1 = forceCastToFloat(d1);
12224 if (op1->gtType == TYP_FLOAT)
12226 d1 = forceCastToFloat(d1); // truncate precision
12228 goto CNS_DOUBLE; // redundant cast
12231 assert(!"BAD_TYP");
12242 /* not a foldable typ - e.g. RET const */
12247 /* We have a binary operator */
12249 assert(kind & GTK_BINOP);
12251 assert(op1->OperKind() & GTK_CONST);
12252 assert(op2->OperKind() & GTK_CONST);
12254 if (tree->gtOper == GT_COMMA)
12259 if (tree->gtOper == GT_LIST)
12264 switchType = op1->gtType;
12266 // Normally we will just switch on op1 types, but for the case where
12267 // only op2 is a GC type and op1 is not a GC type, we use the op2 type.
12268 // This makes us handle this as a case of folding for GC type.
12270 if (varTypeIsGC(op2->gtType) && !varTypeIsGC(op1->gtType))
12272 switchType = op2->gtType;
12275 switch (switchType)
12278 /*-------------------------------------------------------------------------
12279 * Fold constant REF of BYREF binary operator
12280 * These can only be comparisons or null pointers
12285 /* String nodes are an RVA at this point */
12287 if (op1->gtOper == GT_CNS_STR || op2->gtOper == GT_CNS_STR)
12296 i1 = op1->gtIntConCommon.IconValue();
12297 i2 = op2->gtIntConCommon.IconValue();
12299 switch (tree->gtOper)
12310 noway_assert(tree->gtType != TYP_REF);
12311 // We only fold a GT_ADD that involves a null reference.
12312 if (((op1->TypeGet() == TYP_REF) && (i1 == 0)) || ((op2->TypeGet() == TYP_REF) && (i2 == 0)))
12317 printf("\nFolding operator with constant nodes into a constant:\n");
12321 // Fold into GT_IND of null byref
12322 tree->ChangeOperConst(GT_CNS_INT);
12323 tree->gtType = TYP_BYREF;
12324 tree->gtIntCon.gtIconVal = 0;
12325 tree->gtIntCon.gtFieldSeq = FieldSeqStore::NotAField();
12326 if (vnStore != nullptr)
12328 fgValueNumberTreeConst(tree);
12333 printf("\nFolded to null byref:\n");
12346 /*-------------------------------------------------------------------------
12347 * Fold constant INT binary operator
12352 if (tree->OperIsCompare() && (tree->gtType == TYP_BYTE))
12354 tree->gtType = TYP_INT;
12357 assert(tree->gtType == TYP_INT || varTypeIsGC(tree->TypeGet()) || tree->gtOper == GT_MKREFANY);
12359 // No GC pointer types should be folded here...
12361 assert(!varTypeIsGC(op1->gtType) && !varTypeIsGC(op2->gtType));
12363 assert(op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()));
12364 assert(op2->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()));
12366 i1 = op1->gtIntConCommon.IconValue();
12367 i2 = op2->gtIntConCommon.IconValue();
12369 switch (tree->gtOper)
12372 i1 = (INT32(i1) == INT32(i2));
12375 i1 = (INT32(i1) != INT32(i2));
12379 if (tree->gtFlags & GTF_UNSIGNED)
12381 i1 = (UINT32(i1) < UINT32(i2));
12385 i1 = (INT32(i1) < INT32(i2));
12390 if (tree->gtFlags & GTF_UNSIGNED)
12392 i1 = (UINT32(i1) <= UINT32(i2));
12396 i1 = (INT32(i1) <= INT32(i2));
12401 if (tree->gtFlags & GTF_UNSIGNED)
12403 i1 = (UINT32(i1) >= UINT32(i2));
12407 i1 = (INT32(i1) >= INT32(i2));
12412 if (tree->gtFlags & GTF_UNSIGNED)
12414 i1 = (UINT32(i1) > UINT32(i2));
12418 i1 = (INT32(i1) > INT32(i2));
12424 if (tree->gtOverflow())
12426 if (tree->gtFlags & GTF_UNSIGNED)
12428 if (INT64(UINT32(itemp)) != INT64(UINT32(i1)) + INT64(UINT32(i2)))
12435 if (INT64(INT32(itemp)) != INT64(INT32(i1)) + INT64(INT32(i2)))
12442 fieldSeq = GetFieldSeqStore()->Append(op1->gtIntCon.gtFieldSeq, op2->gtIntCon.gtFieldSeq);
12446 if (tree->gtOverflow())
12448 if (tree->gtFlags & GTF_UNSIGNED)
12450 if (INT64(UINT32(itemp)) != ((INT64)((UINT32)i1) - (INT64)((UINT32)i2)))
12457 if (INT64(INT32(itemp)) != INT64(INT32(i1)) - INT64(INT32(i2)))
12467 if (tree->gtOverflow())
12469 if (tree->gtFlags & GTF_UNSIGNED)
12471 if (INT64(UINT32(itemp)) != ((INT64)((UINT32)i1) * (INT64)((UINT32)i2)))
12478 if (INT64(INT32(itemp)) != INT64(INT32(i1)) * INT64(INT32(i2)))
12484 // For the very particular case of the "constant array index" pseudo-field, we
12485 // assume that multiplication is by the field width, and preserves that field.
12486 // This could obviously be made more robust by a more complicated set of annotations...
12487 if ((op1->gtIntCon.gtFieldSeq != nullptr) && op1->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
12489 assert(op2->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField());
12490 fieldSeq = op1->gtIntCon.gtFieldSeq;
12492 else if ((op2->gtIntCon.gtFieldSeq != nullptr) &&
12493 op2->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
12495 assert(op1->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField());
12496 fieldSeq = op2->gtIntCon.gtFieldSeq;
12512 i1 <<= (i2 & 0x1f);
12515 i1 >>= (i2 & 0x1f);
12518 /* logical shift -> make it unsigned to not propagate the sign bit */
12519 i1 = UINT32(i1) >> (i2 & 0x1f);
12522 i1 = (i1 << (i2 & 0x1f)) | (UINT32(i1) >> ((32 - i2) & 0x1f));
12525 i1 = (i1 << ((32 - i2) & 0x1f)) | (UINT32(i1) >> (i2 & 0x1f));
12528 /* DIV and MOD can generate an INT 0 - if division by 0
12529 * or overflow - when dividing MIN by -1 */
12535 if (INT32(i2) == 0)
12537 // Division by zero:
12538 // We have to evaluate this expression and throw an exception
12541 else if ((INT32(i2) == -1) && (UINT32(i1) == 0x80000000))
12543 // Overflow Division:
12544 // We have to evaluate this expression and throw an exception
12548 if (tree->gtOper == GT_DIV)
12550 i1 = INT32(i1) / INT32(i2);
12552 else if (tree->gtOper == GT_MOD)
12554 i1 = INT32(i1) % INT32(i2);
12556 else if (tree->gtOper == GT_UDIV)
12558 i1 = UINT32(i1) / UINT32(i2);
12562 assert(tree->gtOper == GT_UMOD);
12563 i1 = UINT32(i1) % UINT32(i2);
12571 /* We get here after folding to a GT_CNS_INT type
12572 * change the node to the new type / value and make sure the node sizes are OK */
12579 printf("\nFolding operator with constant nodes into a constant:\n");
12584 #ifdef _TARGET_64BIT_
12585 // we need to properly re-sign-extend or truncate as needed.
12586 if (tree->gtFlags & GTF_UNSIGNED)
12594 #endif // _TARGET_64BIT_
12596 /* Also all conditional folding jumps here since the node hanging from
12597 * GT_JTRUE has to be a GT_CNS_INT - value 0 or 1 */
12599 tree->ChangeOperConst(GT_CNS_INT);
12600 tree->gtType = TYP_INT;
12601 tree->gtIntCon.gtIconVal = i1;
12602 tree->gtIntCon.gtFieldSeq = fieldSeq;
12603 if (vnStore != nullptr)
12605 fgValueNumberTreeConst(tree);
12610 printf("Bashed to int constant:\n");
12616 /* This operation is going to cause an overflow exception. Morph into
12617 an overflow helper. Put a dummy constant value for code generation.
12619 We could remove all subsequent trees in the current basic block,
12620 unless this node is a child of GT_COLON
12622 NOTE: Since the folded value is not constant we should not change the
12623 "tree" node - otherwise we confuse the logic that checks if the folding
12624 was successful - instead use one of the operands, e.g. op1
12628 // Don't fold overflow operations if not global morph phase.
12629 // The reason for this is that this optimization is replacing a gentree node
12630 // with another new gentree node. Say a GT_CALL(arglist) has one 'arg'
12631 // involving overflow arithmetic. During assertion prop, it is possible
12632 // that the 'arg' could be constant folded and the result could lead to an
12633 // overflow. In such a case 'arg' will get replaced with GT_COMMA node
12634 // but fgMorphArgs() - see the logic around "if(lateArgsComputed)" - doesn't
12635 // update args table. For this reason this optimization is enabled only
12636 // for global morphing phase.
12638 // X86/Arm32 legacy codegen note: This is not an issue on x86 for the reason that
12639 // it doesn't use arg table for calls. In addition x86/arm32 legacy codegen doesn't
12640 // expect long constants to show up as an operand of overflow cast operation.
12642 // TODO-CQ: Once fgMorphArgs() is fixed this restriction could be removed.
12643 CLANG_FORMAT_COMMENT_ANCHOR;
12645 #ifndef LEGACY_BACKEND
12646 if (!fgGlobalMorph)
12648 assert(tree->gtOverflow());
12651 #endif // !LEGACY_BACKEND
12653 op1 = gtNewLconNode(0);
12654 if (vnStore != nullptr)
12656 op1->gtVNPair.SetBoth(vnStore->VNZeroForType(TYP_LONG));
12661 #ifndef LEGACY_BACKEND
12662 // Don't fold overflow operations if not global morph phase.
12663 // The reason for this is that this optimization is replacing a gentree node
12664 // with another new gentree node. Say a GT_CALL(arglist) has one 'arg'
12665 // involving overflow arithmetic. During assertion prop, it is possible
12666 // that the 'arg' could be constant folded and the result could lead to an
12667 // overflow. In such a case 'arg' will get replaced with GT_COMMA node
12668 // but fgMorphArgs() - see the logic around "if(lateArgsComputed)" - doesn't
12669 // update args table. For this reason this optimization is enabled only
12670 // for global morphing phase.
12672 // X86/Arm32 legacy codegen note: This is not an issue on x86 for the reason that
12673 // it doesn't use arg table for calls. In addition x86/arm32 legacy codegen doesn't
12674 // expect long constants to show up as an operand of overflow cast operation.
12676 // TODO-CQ: Once fgMorphArgs() is fixed this restriction could be removed.
12678 if (!fgGlobalMorph)
12680 assert(tree->gtOverflow());
12683 #endif // !LEGACY_BACKEND
12685 op1 = gtNewIconNode(0);
12686 if (vnStore != nullptr)
12688 op1->gtVNPair.SetBoth(vnStore->VNZeroForType(TYP_INT));
12696 printf("\nFolding binary operator with constant nodes into a comma throw:\n");
12700 /* We will change the cast to a GT_COMMA and attach the exception helper as gtOp.gtOp1.
12701 * The constant expression zero becomes op2. */
12703 assert(tree->gtOverflow());
12704 assert(tree->gtOper == GT_ADD || tree->gtOper == GT_SUB || tree->gtOper == GT_CAST ||
12705 tree->gtOper == GT_MUL);
12709 op1 = gtNewHelperCallNode(CORINFO_HELP_OVERFLOW, TYP_VOID, GTF_EXCEPT,
12710 gtNewArgList(gtNewIconNode(compCurBB->bbTryIndex)));
12712 if (vnStore != nullptr)
12715 vnStore->VNPWithExc(ValueNumPair(ValueNumStore::VNForVoid(), ValueNumStore::VNForVoid()),
12716 vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_OverflowExc)));
12719 tree = gtNewOperNode(GT_COMMA, tree->gtType, op1, op2);
12723 /*-------------------------------------------------------------------------
12724 * Fold constant LONG binary operator
12729 // No GC pointer types should be folded here...
12731 assert(!varTypeIsGC(op1->gtType) && !varTypeIsGC(op2->gtType));
12733 // op1 is known to be a TYP_LONG, op2 is normally a TYP_LONG, unless we have a shift operator in which case
12736 assert((op2->gtType == TYP_LONG) || (op2->gtType == TYP_INT));
12738 assert(op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()));
12739 assert(op2->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()));
12741 lval1 = op1->gtIntConCommon.LngValue();
12743 // For the shift operators we can have a op2 that is a TYP_INT and thus will be GT_CNS_INT
12744 if (op2->OperGet() == GT_CNS_INT)
12746 lval2 = op2->gtIntConCommon.IconValue();
12750 lval2 = op2->gtIntConCommon.LngValue();
12753 switch (tree->gtOper)
12756 i1 = (lval1 == lval2);
12759 i1 = (lval1 != lval2);
12763 if (tree->gtFlags & GTF_UNSIGNED)
12765 i1 = (UINT64(lval1) < UINT64(lval2));
12769 i1 = (lval1 < lval2);
12774 if (tree->gtFlags & GTF_UNSIGNED)
12776 i1 = (UINT64(lval1) <= UINT64(lval2));
12780 i1 = (lval1 <= lval2);
12785 if (tree->gtFlags & GTF_UNSIGNED)
12787 i1 = (UINT64(lval1) >= UINT64(lval2));
12791 i1 = (lval1 >= lval2);
12796 if (tree->gtFlags & GTF_UNSIGNED)
12798 i1 = (UINT64(lval1) > UINT64(lval2));
12802 i1 = (lval1 > lval2);
12807 ltemp = lval1 + lval2;
12810 /* For the SIGNED case - If there is one positive and one negative operand, there can be no overflow
12811 * If both are positive, the result has to be positive, and similary for negatives.
12813 * For the UNSIGNED case - If a UINT32 operand is bigger than the result then OVF */
12815 if (tree->gtOverflow())
12817 if (tree->gtFlags & GTF_UNSIGNED)
12819 if ((UINT64(lval1) > UINT64(ltemp)) || (UINT64(lval2) > UINT64(ltemp)))
12824 else if (((lval1 < 0) == (lval2 < 0)) && ((lval1 < 0) != (ltemp < 0)))
12833 ltemp = lval1 - lval2;
12834 if (tree->gtOverflow())
12836 if (tree->gtFlags & GTF_UNSIGNED)
12838 if (UINT64(lval2) > UINT64(lval1))
12845 /* If both operands are +ve or both are -ve, there can be no
12846 overflow. Else use the logic for : lval1 + (-lval2) */
12848 if ((lval1 < 0) != (lval2 < 0))
12850 if (lval2 == INT64_MIN)
12855 goto LNG_ADD_CHKOVF;
12863 ltemp = lval1 * lval2;
12865 if (tree->gtOverflow() && lval2 != 0)
12868 if (tree->gtFlags & GTF_UNSIGNED)
12870 UINT64 ultemp = ltemp;
12871 UINT64 ulval1 = lval1;
12872 UINT64 ulval2 = lval2;
12873 if ((ultemp / ulval2) != ulval1)
12880 // This does a multiply and then reverses it. This test works great except for MIN_INT *
12881 //-1. In that case we mess up the sign on ltmp. Make sure to double check the sign.
12882 // if either is 0, then no overflow
12883 if (lval1 != 0) // lval2 checked above.
12885 if (((lval1 < 0) == (lval2 < 0)) && (ltemp < 0))
12889 if (((lval1 < 0) != (lval2 < 0)) && (ltemp > 0))
12894 // TODO-Amd64-Unix: Remove the code that disables optimizations for this method when the
12896 // optimizer is fixed and/or the method implementation is refactored in a simpler code.
12897 // There is a bug in the clang-3.5 optimizer. The issue is that in release build the
12898 // optimizer is mistyping (or just wrongly decides to use 32 bit operation for a corner
12899 // case of MIN_LONG) the args of the (ltemp / lval2) to int (it does a 32 bit div
12900 // operation instead of 64 bit.). For the case of lval1 and lval2 equal to MIN_LONG
12901 // (0x8000000000000000) this results in raising a SIGFPE.
12902 // Optimizations disabled for now. See compiler.h.
12903 if ((ltemp / lval2) != lval1)
12925 lval1 <<= (lval2 & 0x3f);
12928 lval1 >>= (lval2 & 0x3f);
12931 /* logical shift -> make it unsigned to not propagate the sign bit */
12932 lval1 = UINT64(lval1) >> (lval2 & 0x3f);
12935 lval1 = (lval1 << (lval2 & 0x3f)) | (UINT64(lval1) >> ((64 - lval2) & 0x3f));
12938 lval1 = (lval1 << ((64 - lval2) & 0x3f)) | (UINT64(lval1) >> (lval2 & 0x3f));
12941 // Both DIV and IDIV on x86 raise an exception for min_int (and min_long) / -1. So we preserve
12942 // that behavior here.
12949 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
12961 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
12973 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
12977 lval1 = UINT64(lval1) / UINT64(lval2);
12985 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
12989 lval1 = UINT64(lval1) % UINT64(lval2);
13000 printf("\nFolding long operator with constant nodes into a constant:\n");
13004 assert((GenTree::s_gtNodeSizes[GT_CNS_NATIVELONG] == TREE_NODE_SZ_SMALL) ||
13005 (tree->gtDebugFlags & GTF_DEBUG_NODE_LARGE));
13007 tree->ChangeOperConst(GT_CNS_NATIVELONG);
13008 tree->gtIntConCommon.SetLngValue(lval1);
13009 if (vnStore != nullptr)
13011 fgValueNumberTreeConst(tree);
13017 printf("Bashed to long constant:\n");
13023 /*-------------------------------------------------------------------------
13024 * Fold constant FLOAT or DOUBLE binary operator
13030 if (tree->gtOverflowEx())
13035 assert(op1->gtOper == GT_CNS_DBL);
13036 d1 = op1->gtDblCon.gtDconVal;
13038 assert(varTypeIsFloating(op2->gtType));
13039 assert(op2->gtOper == GT_CNS_DBL);
13040 d2 = op2->gtDblCon.gtDconVal;
13042 /* Special case - check if we have NaN operands.
13043 * For comparisons if not an unordered operation always return 0.
13044 * For unordered operations (i.e. the GTF_RELOP_NAN_UN flag is set)
13045 * the result is always true - return 1. */
13047 if (_isnan(d1) || _isnan(d2))
13052 printf("Double operator(s) is NaN\n");
13055 if (tree->OperKind() & GTK_RELOP)
13057 if (tree->gtFlags & GTF_RELOP_NAN_UN)
13059 /* Unordered comparison with NaN always succeeds */
13065 /* Normal comparison with NaN always fails */
13072 switch (tree->gtOper)
13094 #if FEATURE_STACK_FP_X87
13109 #else //! FEATURE_STACK_FP_X87
13110 // non-x86 arch: floating point arithmetic should be done in declared
13111 // precision while doing constant folding. For this reason though TYP_FLOAT
13112 // constants are stored as double constants, while performing float arithmetic,
13113 // double constants should be converted to float. Here is an example case
13114 // where performing arithmetic in double precision would lead to incorrect
13118 // float a = float.MaxValue;
13119 // float b = a*a; This will produce +inf in single precision and 1.1579207543382391e+077 in double
13121 // flaot c = b/b; This will produce NaN in single precision and 1 in double precision.
13123 if (op1->TypeGet() == TYP_FLOAT)
13125 f1 = forceCastToFloat(d1);
13126 f2 = forceCastToFloat(d2);
13136 if (op1->TypeGet() == TYP_FLOAT)
13138 f1 = forceCastToFloat(d1);
13139 f2 = forceCastToFloat(d2);
13149 if (op1->TypeGet() == TYP_FLOAT)
13151 f1 = forceCastToFloat(d1);
13152 f2 = forceCastToFloat(d2);
13166 if (op1->TypeGet() == TYP_FLOAT)
13168 f1 = forceCastToFloat(d1);
13169 f2 = forceCastToFloat(d2);
13177 #endif //! FEATURE_STACK_FP_X87
13188 printf("\nFolding fp operator with constant nodes into a fp constant:\n");
13193 assert((GenTree::s_gtNodeSizes[GT_CNS_DBL] == TREE_NODE_SZ_SMALL) ||
13194 (tree->gtDebugFlags & GTF_DEBUG_NODE_LARGE));
13196 tree->ChangeOperConst(GT_CNS_DBL);
13197 tree->gtDblCon.gtDconVal = d1;
13198 if (vnStore != nullptr)
13200 fgValueNumberTreeConst(tree);
13205 printf("Bashed to fp constant:\n");
13212 /* not a foldable typ */
13216 //-------------------------------------------------------------------------
13220 /* Make sure no side effect flags are set on this constant node */
13222 tree->gtFlags &= ~GTF_ALL_EFFECT;
13227 #pragma warning(pop)
13230 /*****************************************************************************
13232 * Create an assignment of the given value to a temp.
13235 GenTreePtr Compiler::gtNewTempAssign(unsigned tmp, GenTreePtr val)
13237 LclVarDsc* varDsc = lvaTable + tmp;
13239 if (varDsc->TypeGet() == TYP_I_IMPL && val->TypeGet() == TYP_BYREF)
13241 impBashVarAddrsToI(val);
13244 var_types valTyp = val->TypeGet();
13245 if (val->OperGet() == GT_LCL_VAR && lvaTable[val->gtLclVar.gtLclNum].lvNormalizeOnLoad())
13247 valTyp = lvaGetRealType(val->gtLclVar.gtLclNum);
13248 val = gtNewLclvNode(val->gtLclVar.gtLclNum, valTyp, val->gtLclVar.gtLclILoffs);
13250 var_types dstTyp = varDsc->TypeGet();
13252 /* If the variable's lvType is not yet set then set it here */
13253 if (dstTyp == TYP_UNDEF)
13255 varDsc->lvType = dstTyp = genActualType(valTyp);
13256 if (varTypeIsGC(dstTyp))
13258 varDsc->lvStructGcCount = 1;
13261 else if (varTypeIsSIMD(dstTyp))
13263 varDsc->lvSIMDType = 1;
13269 /* Make sure the actual types match */
13270 if (genActualType(valTyp) != genActualType(dstTyp))
13272 // Plus some other exceptions that are apparently legal:
13273 // 1) TYP_REF or BYREF = TYP_I_IMPL
13275 if (varTypeIsGC(dstTyp) && (valTyp == TYP_I_IMPL))
13279 // 2) TYP_DOUBLE = TYP_FLOAT or TYP_FLOAT = TYP_DOUBLE
13280 else if (varTypeIsFloating(dstTyp) && varTypeIsFloating(valTyp))
13288 assert(!"Incompatible types for gtNewTempAssign");
13293 // Floating Point assignments can be created during inlining
13294 // see "Zero init inlinee locals:" in fgInlinePrependStatements
13295 // thus we may need to set compFloatingPointUsed to true here.
13297 if (varTypeIsFloating(dstTyp) && (compFloatingPointUsed == false))
13299 compFloatingPointUsed = true;
13302 /* Create the assignment node */
13305 GenTreePtr dest = gtNewLclvNode(tmp, dstTyp);
13306 dest->gtFlags |= GTF_VAR_DEF;
13308 // With first-class structs, we should be propagating the class handle on all non-primitive
13309 // struct types. We don't have a convenient way to do that for all SIMD temps, since some
13310 // internal trees use SIMD types that are not used by the input IL. In this case, we allow
13311 // a null type handle and derive the necessary information about the type from its varType.
13312 CORINFO_CLASS_HANDLE structHnd = gtGetStructHandleIfPresent(val);
13313 if (varTypeIsStruct(valTyp) && ((structHnd != NO_CLASS_HANDLE) || (varTypeIsSIMD(valTyp))))
13315 // The GT_OBJ may be be a child of a GT_COMMA.
13316 GenTreePtr valx = val->gtEffectiveVal(/*commaOnly*/ true);
13318 if (valx->gtOper == GT_OBJ)
13320 assert(structHnd != nullptr);
13321 lvaSetStruct(tmp, structHnd, false);
13323 dest->gtFlags |= GTF_DONT_CSE;
13324 valx->gtFlags |= GTF_DONT_CSE;
13325 asg = impAssignStruct(dest, val, structHnd, (unsigned)CHECK_SPILL_NONE);
13329 asg = gtNewAssignNode(dest, val);
13332 #ifndef LEGACY_BACKEND
13333 if (compRationalIRForm)
13335 Rationalizer::RewriteAssignmentIntoStoreLcl(asg->AsOp());
13337 #endif // !LEGACY_BACKEND
13342 /*****************************************************************************
13344 * Create a helper call to access a COM field (iff 'assg' is non-zero this is
13345 * an assignment and 'assg' is the new value).
13348 GenTreePtr Compiler::gtNewRefCOMfield(GenTreePtr objPtr,
13349 CORINFO_RESOLVED_TOKEN* pResolvedToken,
13350 CORINFO_ACCESS_FLAGS access,
13351 CORINFO_FIELD_INFO* pFieldInfo,
13353 CORINFO_CLASS_HANDLE structType,
13356 assert(pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER ||
13357 pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_ADDR_HELPER ||
13358 pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_ADDR_HELPER);
13360 /* If we can't access it directly, we need to call a helper function */
13361 GenTreeArgList* args = nullptr;
13362 var_types helperType = TYP_BYREF;
13364 if (pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER)
13366 if (access & CORINFO_ACCESS_SET)
13368 assert(assg != nullptr);
13369 // helper needs pointer to struct, not struct itself
13370 if (pFieldInfo->helper == CORINFO_HELP_SETFIELDSTRUCT)
13372 assert(structType != nullptr);
13373 assg = impGetStructAddr(assg, structType, (unsigned)CHECK_SPILL_ALL, true);
13375 else if (lclTyp == TYP_DOUBLE && assg->TypeGet() == TYP_FLOAT)
13377 assg = gtNewCastNode(TYP_DOUBLE, assg, TYP_DOUBLE);
13379 else if (lclTyp == TYP_FLOAT && assg->TypeGet() == TYP_DOUBLE)
13381 assg = gtNewCastNode(TYP_FLOAT, assg, TYP_FLOAT);
13384 args = gtNewArgList(assg);
13385 helperType = TYP_VOID;
13387 else if (access & CORINFO_ACCESS_GET)
13389 helperType = lclTyp;
13391 // The calling convention for the helper does not take into
13392 // account optimization of primitive structs.
13393 if ((pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT) && !varTypeIsStruct(lclTyp))
13395 helperType = TYP_STRUCT;
13400 if (pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT || pFieldInfo->helper == CORINFO_HELP_SETFIELDSTRUCT)
13402 assert(pFieldInfo->structType != nullptr);
13403 args = gtNewListNode(gtNewIconEmbClsHndNode(pFieldInfo->structType), args);
13406 GenTreePtr fieldHnd = impTokenToHandle(pResolvedToken);
13407 if (fieldHnd == nullptr)
13408 { // compDonotInline()
13412 args = gtNewListNode(fieldHnd, args);
13414 // If it's a static field, we shouldn't have an object node
13415 // If it's an instance field, we have an object node
13416 assert((pFieldInfo->fieldAccessor != CORINFO_FIELD_STATIC_ADDR_HELPER) ^ (objPtr == nullptr));
13418 if (objPtr != nullptr)
13420 args = gtNewListNode(objPtr, args);
13423 GenTreePtr tree = gtNewHelperCallNode(pFieldInfo->helper, genActualType(helperType), 0, args);
13425 if (pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER)
13427 if (access & CORINFO_ACCESS_GET)
13429 if (pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT)
13431 if (!varTypeIsStruct(lclTyp))
13433 // get the result as primitive type
13434 tree = impGetStructAddr(tree, structType, (unsigned)CHECK_SPILL_ALL, true);
13435 tree = gtNewOperNode(GT_IND, lclTyp, tree);
13438 else if (varTypeIsIntegral(lclTyp) && genTypeSize(lclTyp) < genTypeSize(TYP_INT))
13440 // The helper does not extend the small return types.
13441 tree = gtNewCastNode(genActualType(lclTyp), tree, lclTyp);
13447 // OK, now do the indirection
13448 if (access & CORINFO_ACCESS_GET)
13450 if (varTypeIsStruct(lclTyp))
13452 tree = gtNewObjNode(structType, tree);
13456 tree = gtNewOperNode(GT_IND, lclTyp, tree);
13458 tree->gtFlags |= (GTF_EXCEPT | GTF_GLOB_REF);
13460 else if (access & CORINFO_ACCESS_SET)
13462 if (varTypeIsStruct(lclTyp))
13464 tree = impAssignStructPtr(tree, assg, structType, (unsigned)CHECK_SPILL_ALL);
13468 tree = gtNewOperNode(GT_IND, lclTyp, tree);
13469 tree->gtFlags |= (GTF_EXCEPT | GTF_GLOB_REF | GTF_IND_TGTANYWHERE);
13470 tree = gtNewAssignNode(tree, assg);
13478 /*****************************************************************************
13480 * Return true if the given node (excluding children trees) contains side effects.
13481 * Note that it does not recurse, and children need to be handled separately.
13482 * It may return false even if the node has GTF_SIDE_EFFECT (because of its children).
13484 * Similar to OperMayThrow() (but handles GT_CALLs specially), but considers
13488 bool Compiler::gtNodeHasSideEffects(GenTreePtr tree, unsigned flags)
13490 if (flags & GTF_ASG)
13492 if ((tree->OperKind() & GTK_ASGOP) ||
13493 (tree->gtOper == GT_INITBLK || tree->gtOper == GT_COPYBLK || tree->gtOper == GT_COPYOBJ))
13499 // Are there only GTF_CALL side effects remaining? (and no other side effect kinds)
13500 if (flags & GTF_CALL)
13502 if (tree->OperGet() == GT_CALL)
13504 // Generally all GT_CALL nodes are considered to have side-effects.
13505 // But we may have a helper call that doesn't have any important side effects.
13507 if (tree->gtCall.gtCallType == CT_HELPER)
13509 // But if this tree is a helper call we may not care about the side-effects
13511 CorInfoHelpFunc helper = eeGetHelperNum(tree->AsCall()->gtCallMethHnd);
13513 // We definitely care about the side effects if MutatesHeap is true
13515 if (s_helperCallProperties.MutatesHeap(helper))
13520 // with GTF_PERSISTENT_SIDE_EFFECTS_IN_CSE we will CSE helper calls that can run cctors.
13522 if ((flags != GTF_PERSISTENT_SIDE_EFFECTS_IN_CSE) && (s_helperCallProperties.MayRunCctor(helper)))
13527 // If we also care about exceptions then check if the helper can throw
13529 if (((flags & GTF_EXCEPT) != 0) && !s_helperCallProperties.NoThrow(helper))
13534 // If this is a Pure helper call or an allocator (that will not need to run a finalizer)
13535 // then we don't need to preserve the side effects (of this call -- we may care about those of the
13537 if (s_helperCallProperties.IsPure(helper) ||
13538 (s_helperCallProperties.IsAllocator(helper) && !s_helperCallProperties.MayFinalize(helper)))
13540 GenTreeCall* call = tree->AsCall();
13541 for (GenTreeArgList* args = call->gtCallArgs; args != nullptr; args = args->Rest())
13543 if (gtTreeHasSideEffects(args->Current(), flags))
13548 // I'm a little worried that args that assign to temps that are late args will look like
13549 // side effects...but better to be conservative for now.
13550 for (GenTreeArgList* args = call->gtCallLateArgs; args != nullptr; args = args->Rest())
13552 if (gtTreeHasSideEffects(args->Current(), flags))
13562 // Otherwise the GT_CALL is considered to have side-effects.
13567 if (flags & GTF_EXCEPT)
13569 if (tree->OperMayThrow())
13575 // Expressions declared as CSE by (e.g.) hoisting code are considered to have relevant side
13576 // effects (if we care about GTF_MAKE_CSE).
13577 if ((flags & GTF_MAKE_CSE) && (tree->gtFlags & GTF_MAKE_CSE))
13585 /*****************************************************************************
13586 * Returns true if the expr tree has any side effects.
13589 bool Compiler::gtTreeHasSideEffects(GenTreePtr tree, unsigned flags /* = GTF_SIDE_EFFECT*/)
13591 // These are the side effect flags that we care about for this tree
13592 unsigned sideEffectFlags = tree->gtFlags & flags;
13594 // Does this tree have any Side-effect flags set that we care about?
13595 if (sideEffectFlags == 0)
13601 if (sideEffectFlags == GTF_CALL)
13603 if (tree->OperGet() == GT_CALL)
13605 // Generally all trees that contain GT_CALL nodes are considered to have side-effects.
13607 if (tree->gtCall.gtCallType == CT_HELPER)
13609 // If this node is a helper call we may not care about the side-effects.
13610 // Note that gtNodeHasSideEffects checks the side effects of the helper itself
13611 // as well as the side effects of its arguments.
13612 return gtNodeHasSideEffects(tree, flags);
13615 else if (tree->OperGet() == GT_INTRINSIC)
13617 if (gtNodeHasSideEffects(tree, flags))
13622 if (gtNodeHasSideEffects(tree->gtOp.gtOp1, flags))
13627 if ((tree->gtOp.gtOp2 != nullptr) && gtNodeHasSideEffects(tree->gtOp.gtOp2, flags))
13639 GenTreePtr Compiler::gtBuildCommaList(GenTreePtr list, GenTreePtr expr)
13641 // 'list' starts off as null,
13642 // and when it is null we haven't started the list yet.
13644 if (list != nullptr)
13646 // Create a GT_COMMA that appends 'expr' in front of the remaining set of expressions in (*list)
13647 GenTreePtr result = gtNewOperNode(GT_COMMA, TYP_VOID, expr, list);
13649 // Set the flags in the comma node
13650 result->gtFlags |= (list->gtFlags & GTF_ALL_EFFECT);
13651 result->gtFlags |= (expr->gtFlags & GTF_ALL_EFFECT);
13653 // 'list' and 'expr' should have valuenumbers defined for both or for neither one
13654 noway_assert(list->gtVNPair.BothDefined() == expr->gtVNPair.BothDefined());
13656 // Set the ValueNumber 'gtVNPair' for the new GT_COMMA node
13658 if (expr->gtVNPair.BothDefined())
13660 // The result of a GT_COMMA node is op2, the normal value number is op2vnp
13661 // But we also need to include the union of side effects from op1 and op2.
13662 // we compute this value into exceptions_vnp.
13663 ValueNumPair op1vnp;
13664 ValueNumPair op1Xvnp = ValueNumStore::VNPForEmptyExcSet();
13665 ValueNumPair op2vnp;
13666 ValueNumPair op2Xvnp = ValueNumStore::VNPForEmptyExcSet();
13668 vnStore->VNPUnpackExc(expr->gtVNPair, &op1vnp, &op1Xvnp);
13669 vnStore->VNPUnpackExc(list->gtVNPair, &op2vnp, &op2Xvnp);
13671 ValueNumPair exceptions_vnp = ValueNumStore::VNPForEmptyExcSet();
13673 exceptions_vnp = vnStore->VNPExcSetUnion(exceptions_vnp, op1Xvnp);
13674 exceptions_vnp = vnStore->VNPExcSetUnion(exceptions_vnp, op2Xvnp);
13676 result->gtVNPair = vnStore->VNPWithExc(op2vnp, exceptions_vnp);
13683 // The 'expr' will start the list of expressions
13688 /*****************************************************************************
13690 * Extracts side effects from the given expression
13691 * and appends them to a given list (actually a GT_COMMA list)
13692 * If ignore root is specified, the method doesn't treat the top
13693 * level tree node as having side-effect.
13696 void Compiler::gtExtractSideEffList(GenTreePtr expr,
13698 unsigned flags /* = GTF_SIDE_EFFECT*/,
13699 bool ignoreRoot /* = false */)
13702 assert(expr->gtOper != GT_STMT);
13704 /* If no side effect in the expression return */
13706 if (!gtTreeHasSideEffects(expr, flags))
13711 genTreeOps oper = expr->OperGet();
13712 unsigned kind = expr->OperKind();
13714 // Look for any side effects that we care about
13716 if (!ignoreRoot && gtNodeHasSideEffects(expr, flags))
13718 // Add the side effect to the list and return
13720 *pList = gtBuildCommaList(*pList, expr);
13724 if (kind & GTK_LEAF)
13729 if (oper == GT_LOCKADD || oper == GT_XADD || oper == GT_XCHG || oper == GT_CMPXCHG)
13731 // XADD both adds to the memory location and also fetches the old value. If we only need the side
13732 // effect of this instruction, change it into a GT_LOCKADD node (the add only)
13733 if (oper == GT_XADD)
13735 expr->gtOper = GT_LOCKADD;
13736 expr->gtType = TYP_VOID;
13739 // These operations are kind of important to keep
13740 *pList = gtBuildCommaList(*pList, expr);
13744 if (kind & GTK_SMPOP)
13746 GenTreePtr op1 = expr->gtOp.gtOp1;
13747 GenTreePtr op2 = expr->gtGetOp2();
13749 if (flags & GTF_EXCEPT)
13751 // Special case - GT_ADDR of GT_IND nodes of TYP_STRUCT
13752 // have to be kept together
13754 if (oper == GT_ADDR && op1->OperIsIndir() && op1->gtType == TYP_STRUCT)
13756 *pList = gtBuildCommaList(*pList, expr);
13761 printf("Keep the GT_ADDR and GT_IND together:\n");
13768 /* Continue searching for side effects in the subtrees of the expression
13769 * NOTE: Be careful to preserve the right ordering - side effects are prepended
13772 /* Continue searching for side effects in the subtrees of the expression
13773 * NOTE: Be careful to preserve the right ordering
13774 * as side effects are prepended to the list */
13776 if (expr->gtFlags & GTF_REVERSE_OPS)
13778 assert(oper != GT_COMMA);
13781 gtExtractSideEffList(op1, pList, flags);
13785 gtExtractSideEffList(op2, pList, flags);
13792 gtExtractSideEffList(op2, pList, flags);
13796 gtExtractSideEffList(op1, pList, flags);
13801 if (expr->OperGet() == GT_CALL)
13803 // Generally all GT_CALL nodes are considered to have side-effects.
13804 // So if we get here it must be a Helper call that we decided does
13805 // not have side effects that we needed to keep
13807 assert(expr->gtCall.gtCallType == CT_HELPER);
13809 // We can remove this Helper call, but there still could be
13810 // side-effects in the arguments that we may need to keep
13813 for (args = expr->gtCall.gtCallArgs; args; args = args->gtOp.gtOp2)
13815 assert(args->IsList());
13816 gtExtractSideEffList(args->Current(), pList, flags);
13818 for (args = expr->gtCall.gtCallLateArgs; args; args = args->gtOp.gtOp2)
13820 assert(args->IsList());
13821 gtExtractSideEffList(args->Current(), pList, flags);
13825 if (expr->OperGet() == GT_ARR_BOUNDS_CHECK
13826 #ifdef FEATURE_SIMD
13827 || expr->OperGet() == GT_SIMD_CHK
13828 #endif // FEATURE_SIMD
13831 gtExtractSideEffList(expr->AsBoundsChk()->gtArrLen, pList, flags);
13832 gtExtractSideEffList(expr->AsBoundsChk()->gtIndex, pList, flags);
13836 /*****************************************************************************
13838 * For debugging only - displays a tree node list and makes sure all the
13839 * links are correctly set.
13844 void dispNodeList(GenTreePtr list, bool verbose)
13846 GenTreePtr last = nullptr;
13856 next = list->gtNext;
13860 printf("%08X -> %08X -> %08X\n", last, list, next);
13863 assert(!last || last->gtNext == list);
13865 assert(next == nullptr || next->gtPrev == list);
13875 printf(""); // null string means flush
13878 /*****************************************************************************
13879 * Callback to assert that the nodes of a qmark-colon subtree are marked
13883 Compiler::fgWalkResult Compiler::gtAssertColonCond(GenTreePtr* pTree, fgWalkData* data)
13885 assert(data->pCallbackData == nullptr);
13887 assert((*pTree)->gtFlags & GTF_COLON_COND);
13889 return WALK_CONTINUE;
13893 /*****************************************************************************
13894 * Callback to mark the nodes of a qmark-colon subtree that are conditionally
13899 Compiler::fgWalkResult Compiler::gtMarkColonCond(GenTreePtr* pTree, fgWalkData* data)
13901 assert(data->pCallbackData == nullptr);
13903 (*pTree)->gtFlags |= GTF_COLON_COND;
13905 return WALK_CONTINUE;
13908 /*****************************************************************************
13909 * Callback to clear the conditionally executed flags of nodes that no longer
13910 will be conditionally executed. Note that when we find another colon we must
13911 stop, as the nodes below this one WILL be conditionally executed. This callback
13912 is called when folding a qmark condition (ie the condition is constant).
13916 Compiler::fgWalkResult Compiler::gtClearColonCond(GenTreePtr* pTree, fgWalkData* data)
13918 GenTreePtr tree = *pTree;
13920 assert(data->pCallbackData == nullptr);
13922 if (tree->OperGet() == GT_COLON)
13924 // Nodes below this will be conditionally executed.
13925 return WALK_SKIP_SUBTREES;
13928 tree->gtFlags &= ~GTF_COLON_COND;
13929 return WALK_CONTINUE;
13932 struct FindLinkData
13934 GenTreePtr nodeToFind;
13935 GenTreePtr* result;
13938 /*****************************************************************************
13940 * Callback used by the tree walker to implement fgFindLink()
13942 static Compiler::fgWalkResult gtFindLinkCB(GenTreePtr* pTree, Compiler::fgWalkData* cbData)
13944 FindLinkData* data = (FindLinkData*)cbData->pCallbackData;
13945 if (*pTree == data->nodeToFind)
13947 data->result = pTree;
13948 return Compiler::WALK_ABORT;
13951 return Compiler::WALK_CONTINUE;
13954 GenTreePtr* Compiler::gtFindLink(GenTreePtr stmt, GenTreePtr node)
13956 assert(stmt->gtOper == GT_STMT);
13958 FindLinkData data = {node, nullptr};
13960 fgWalkResult result = fgWalkTreePre(&stmt->gtStmt.gtStmtExpr, gtFindLinkCB, &data);
13962 if (result == WALK_ABORT)
13964 assert(data.nodeToFind == *data.result);
13965 return data.result;
13973 /*****************************************************************************
13975 * Callback that checks if a tree node has oper type GT_CATCH_ARG
13978 static Compiler::fgWalkResult gtFindCatchArg(GenTreePtr* pTree, Compiler::fgWalkData* /* data */)
13980 return ((*pTree)->OperGet() == GT_CATCH_ARG) ? Compiler::WALK_ABORT : Compiler::WALK_CONTINUE;
13983 /*****************************************************************************/
13984 bool Compiler::gtHasCatchArg(GenTreePtr tree)
13986 if (((tree->gtFlags & GTF_ORDER_SIDEEFF) != 0) && (fgWalkTreePre(&tree, gtFindCatchArg) == WALK_ABORT))
13993 //------------------------------------------------------------------------
13994 // gtHasCallOnStack:
13997 // parentStack: a context (stack of parent nodes)
14000 // returns true if any of the parent nodes are a GT_CALL
14003 // We have a stack of parent nodes. This generally requires that
14004 // we are performing a recursive tree walk using struct fgWalkData
14006 //------------------------------------------------------------------------
14007 /* static */ bool Compiler::gtHasCallOnStack(GenTreeStack* parentStack)
14009 for (int i = 0; i < parentStack->Height(); i++)
14011 GenTree* node = parentStack->Index(i);
14012 if (node->OperGet() == GT_CALL)
14020 //------------------------------------------------------------------------
14021 // gtCheckQuirkAddrExposedLclVar:
14024 // tree: an address taken GenTree node that is a GT_LCL_VAR
14025 // parentStack: a context (stack of parent nodes)
14026 // The 'parentStack' is used to ensure that we are in an argument context.
14032 // When allocation size of this LclVar is 32-bits we will quirk the size to 64-bits
14033 // because some PInvoke signatures incorrectly specify a ByRef to an INT32
14034 // when they actually write a SIZE_T or INT64. There are cases where overwriting
14035 // these extra 4 bytes corrupts some data (such as a saved register) that leads to A/V
14036 // Wheras previously the JIT64 codegen did not lead to an A/V
14039 // 'tree' is known to be address taken and that we have a stack
14040 // of parent nodes. Both of these generally requires that
14041 // we are performing a recursive tree walk using struct fgWalkData
14042 //------------------------------------------------------------------------
14043 void Compiler::gtCheckQuirkAddrExposedLclVar(GenTreePtr tree, GenTreeStack* parentStack)
14045 #ifdef _TARGET_64BIT_
14046 // We only need to Quirk for _TARGET_64BIT_
14048 // Do we have a parent node that is a Call?
14049 if (!Compiler::gtHasCallOnStack(parentStack))
14051 // No, so we don't apply the Quirk
14054 noway_assert(tree->gtOper == GT_LCL_VAR);
14055 unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
14056 LclVarDsc* varDsc = &lvaTable[lclNum];
14057 var_types vartype = varDsc->TypeGet();
14059 if (varDsc->lvIsParam)
14061 // We can't Quirk the size of an incoming parameter
14065 // We may need to Quirk the storage size for this LCL_VAR
14066 if (genActualType(vartype) == TYP_INT)
14068 varDsc->lvQuirkToLong = true;
14072 printf("\nAdding a Quirk for the storage size of LvlVar V%02d:", lclNum);
14073 printf(" (%s ==> %s)\n", varTypeName(vartype), varTypeName(TYP_LONG));
14080 // Checks to see if we're allowed to optimize Type::op_Equality or Type::op_Inequality on this operand.
14081 // We're allowed to convert to GT_EQ/GT_NE if one of the operands is:
14082 // 1) The result of Object::GetType
14083 // 2) The result of typeof(...)
14084 // 3) a local variable of type RuntimeType.
14085 bool Compiler::gtCanOptimizeTypeEquality(GenTreePtr tree)
14087 if (tree->gtOper == GT_CALL)
14089 if (tree->gtCall.gtCallType == CT_HELPER)
14091 if (gtIsTypeHandleToRuntimeTypeHelper(tree))
14096 else if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC)
14098 if (info.compCompHnd->getIntrinsicID(tree->gtCall.gtCallMethHnd) == CORINFO_INTRINSIC_Object_GetType)
14104 else if ((tree->gtOper == GT_INTRINSIC) && (tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType))
14108 else if (tree->gtOper == GT_LCL_VAR)
14110 LclVarDsc* lcl = &(lvaTable[tree->gtLclVarCommon.gtLclNum]);
14111 if (lcl->TypeGet() == TYP_REF)
14113 if (lcl->lvVerTypeInfo.GetClassHandle() == info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE))
14122 bool Compiler::gtIsTypeHandleToRuntimeTypeHelper(GenTreePtr tree)
14124 return tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE) ||
14125 tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL);
14128 bool Compiler::gtIsActiveCSE_Candidate(GenTreePtr tree)
14130 return (optValnumCSE_phase && IS_CSE_INDEX(tree->gtCSEnum));
14133 /*****************************************************************************/
14135 struct ComplexityStruct
14137 unsigned m_numNodes;
14138 unsigned m_nodeLimit;
14139 ComplexityStruct(unsigned nodeLimit) : m_numNodes(0), m_nodeLimit(nodeLimit)
14144 static Compiler::fgWalkResult ComplexityExceedsWalker(GenTreePtr* pTree, Compiler::fgWalkData* data)
14146 ComplexityStruct* pComplexity = (ComplexityStruct*)data->pCallbackData;
14147 if (++pComplexity->m_numNodes > pComplexity->m_nodeLimit)
14149 return Compiler::WALK_ABORT;
14153 return Compiler::WALK_CONTINUE;
14157 bool Compiler::gtComplexityExceeds(GenTreePtr* tree, unsigned limit)
14159 ComplexityStruct complexity(limit);
14160 if (fgWalkTreePre(tree, &ComplexityExceedsWalker, &complexity) == WALK_ABORT)
14171 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
14172 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
14176 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
14177 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
14180 #if MEASURE_BLOCK_SIZE
14182 size_t BasicBlock::s_Size;
14184 size_t BasicBlock::s_Count;
14185 #endif // MEASURE_BLOCK_SIZE
14188 // The max # of tree nodes in any BB
14190 unsigned BasicBlock::s_nMaxTrees;
14193 /*****************************************************************************
14195 * Allocate a basic block but don't append it to the current BB list.
14198 BasicBlock* Compiler::bbNewBasicBlock(BBjumpKinds jumpKind)
14202 /* Allocate the block descriptor and zero it out */
14203 assert(fgSafeBasicBlockCreation);
14205 block = new (this, CMK_BasicBlock) BasicBlock;
14207 #if MEASURE_BLOCK_SIZE
14208 BasicBlock::s_Count += 1;
14209 BasicBlock::s_Size += sizeof(*block);
14213 // fgLookupBB() is invalid until fgInitBBLookup() is called again.
14214 fgBBs = (BasicBlock**)0xCDCD;
14217 // TODO-Throughput: The following memset is pretty expensive - do something else?
14218 // Note that some fields have to be initialized to 0 (like bbFPStateX87)
14219 memset(block, 0, sizeof(*block));
14221 // scopeInfo needs to be able to differentiate between blocks which
14222 // correspond to some instrs (and so may have some LocalVarInfo
14223 // boundaries), or have been inserted by the JIT
14224 block->bbCodeOffs = BAD_IL_OFFSET;
14225 block->bbCodeOffsEnd = BAD_IL_OFFSET;
14227 /* Give the block a number, set the ancestor count and weight */
14231 if (compIsForInlining())
14233 block->bbNum = ++impInlineInfo->InlinerCompiler->fgBBNumMax;
14237 block->bbNum = ++fgBBNumMax;
14240 #ifndef LEGACY_BACKEND
14241 if (compRationalIRForm)
14243 block->bbFlags |= BBF_IS_LIR;
14245 #endif // !LEGACY_BACKEND
14248 block->bbWeight = BB_UNITY_WEIGHT;
14250 block->bbStkTempsIn = NO_BASE_TMP;
14251 block->bbStkTempsOut = NO_BASE_TMP;
14253 block->bbEntryState = nullptr;
14255 /* Record the jump kind in the block */
14257 block->bbJumpKind = jumpKind;
14259 if (jumpKind == BBJ_THROW)
14261 block->bbSetRunRarely();
14267 printf("New Basic Block BB%02u [%p] created.\n", block->bbNum, dspPtr(block));
14271 // We will give all the blocks var sets after the number of tracked variables
14272 // is determined and frozen. After that, if we dynamically create a basic block,
14273 // we will initialize its var sets.
14274 if (fgBBVarSetsInited)
14276 VarSetOps::AssignNoCopy(this, block->bbVarUse, VarSetOps::MakeEmpty(this));
14277 VarSetOps::AssignNoCopy(this, block->bbVarDef, VarSetOps::MakeEmpty(this));
14278 VarSetOps::AssignNoCopy(this, block->bbVarTmp, VarSetOps::MakeEmpty(this));
14279 VarSetOps::AssignNoCopy(this, block->bbLiveIn, VarSetOps::MakeEmpty(this));
14280 VarSetOps::AssignNoCopy(this, block->bbLiveOut, VarSetOps::MakeEmpty(this));
14281 VarSetOps::AssignNoCopy(this, block->bbScope, VarSetOps::MakeEmpty(this));
14285 VarSetOps::AssignNoCopy(this, block->bbVarUse, VarSetOps::UninitVal());
14286 VarSetOps::AssignNoCopy(this, block->bbVarDef, VarSetOps::UninitVal());
14287 VarSetOps::AssignNoCopy(this, block->bbVarTmp, VarSetOps::UninitVal());
14288 VarSetOps::AssignNoCopy(this, block->bbLiveIn, VarSetOps::UninitVal());
14289 VarSetOps::AssignNoCopy(this, block->bbLiveOut, VarSetOps::UninitVal());
14290 VarSetOps::AssignNoCopy(this, block->bbScope, VarSetOps::UninitVal());
14293 block->bbHeapUse = false;
14294 block->bbHeapDef = false;
14295 block->bbHeapLiveIn = false;
14296 block->bbHeapLiveOut = false;
14298 block->bbHeapSsaPhiFunc = nullptr;
14299 block->bbHeapSsaNumIn = 0;
14300 block->bbHeapSsaNumOut = 0;
14302 // Make sure we reserve a NOT_IN_LOOP value that isn't a legal table index.
14303 static_assert_no_msg(MAX_LOOP_NUM < BasicBlock::NOT_IN_LOOP);
14305 block->bbNatLoopNum = BasicBlock::NOT_IN_LOOP;
14310 //------------------------------------------------------------------------------
14311 // containsStatement - return true if the block contains the given statement
14312 //------------------------------------------------------------------------------
14314 bool BasicBlock::containsStatement(GenTree* statement)
14316 assert(statement->gtOper == GT_STMT);
14318 GenTree* curr = bbTreeList;
14321 if (curr == statement)
14325 curr = curr->gtNext;
14327 return curr != nullptr;
14330 GenTreeStmt* BasicBlock::FirstNonPhiDef()
14332 GenTreePtr stmt = bbTreeList;
14333 if (stmt == nullptr)
14337 GenTreePtr tree = stmt->gtStmt.gtStmtExpr;
14338 while ((tree->OperGet() == GT_ASG && tree->gtOp.gtOp2->OperGet() == GT_PHI) ||
14339 (tree->OperGet() == GT_STORE_LCL_VAR && tree->gtOp.gtOp1->OperGet() == GT_PHI))
14341 stmt = stmt->gtNext;
14342 if (stmt == nullptr)
14346 tree = stmt->gtStmt.gtStmtExpr;
14348 return stmt->AsStmt();
14351 GenTreePtr BasicBlock::FirstNonPhiDefOrCatchArgAsg()
14353 GenTreePtr stmt = FirstNonPhiDef();
14354 if (stmt == nullptr)
14358 GenTreePtr tree = stmt->gtStmt.gtStmtExpr;
14359 if ((tree->OperGet() == GT_ASG && tree->gtOp.gtOp2->OperGet() == GT_CATCH_ARG) ||
14360 (tree->OperGet() == GT_STORE_LCL_VAR && tree->gtOp.gtOp1->OperGet() == GT_CATCH_ARG))
14362 stmt = stmt->gtNext;
14367 /*****************************************************************************
14369 * Mark a block as rarely run, we also don't want to have a loop in a
14370 * rarely run block, and we set it's weight to zero.
14373 void BasicBlock::bbSetRunRarely()
14375 setBBWeight(BB_ZERO_WEIGHT);
14376 if (bbWeight == BB_ZERO_WEIGHT)
14378 bbFlags |= BBF_RUN_RARELY; // This block is never/rarely run
14382 /*****************************************************************************
14384 * Can a BasicBlock be inserted after this without altering the flowgraph
14387 bool BasicBlock::bbFallsThrough()
14389 switch (bbJumpKind)
14393 case BBJ_EHFINALLYRET:
14394 case BBJ_EHFILTERRET:
14395 case BBJ_EHCATCHRET:
14406 case BBJ_CALLFINALLY:
14407 return ((bbFlags & BBF_RETLESS_CALL) == 0);
14410 assert(!"Unknown bbJumpKind in bbFallsThrough()");
14415 unsigned BasicBlock::NumSucc(Compiler* comp)
14417 // As described in the spec comment of NumSucc at its declaration, whether "comp" is null determines
14418 // whether NumSucc and GetSucc yield successors of finally blocks.
14420 switch (bbJumpKind)
14427 case BBJ_EHFILTERRET:
14428 if (comp == nullptr)
14437 case BBJ_EHFINALLYRET:
14439 if (comp == nullptr)
14445 // The first block of the handler is labelled with the catch type.
14446 BasicBlock* hndBeg = comp->fgFirstBlockOfHandler(this);
14447 if (hndBeg->bbCatchTyp == BBCT_FINALLY)
14449 return comp->fgNSuccsOfFinallyRet(this);
14453 assert(hndBeg->bbCatchTyp == BBCT_FAULT); // We can only BBJ_EHFINALLYRET from FINALLY and FAULT.
14454 // A FAULT block has no successors.
14459 case BBJ_CALLFINALLY:
14461 case BBJ_EHCATCHRET:
14466 if (bbJumpDest == bbNext)
14475 if (comp == nullptr)
14477 return bbJumpSwt->bbsCount;
14481 Compiler::SwitchUniqueSuccSet sd = comp->GetDescriptorForSwitch(this);
14482 return sd.numDistinctSuccs;
14490 BasicBlock* BasicBlock::GetSucc(unsigned i, Compiler* comp)
14492 // As described in the spec comment of GetSucc at its declaration, whether "comp" is null determines
14493 // whether NumSucc and GetSucc yield successors of finally blocks.
14495 assert(i < NumSucc(comp)); // Index bounds check.
14496 // printf("bbjk=%d\n", bbJumpKind);
14497 switch (bbJumpKind)
14502 unreached(); // Should have been covered by assert above.
14504 case BBJ_EHFILTERRET:
14506 assert(comp != nullptr); // Or else we're not looking for successors.
14507 BasicBlock* result = comp->fgFirstBlockOfHandler(this);
14508 noway_assert(result == bbJumpDest);
14509 // Handler is the (sole) normal successor of the filter.
14513 case BBJ_EHFINALLYRET:
14514 return comp->fgSuccOfFinallyRet(this, i);
14516 case BBJ_CALLFINALLY:
14518 case BBJ_EHCATCHRET:
14535 if (comp == nullptr)
14537 assert(i < bbJumpSwt->bbsCount); // Range check.
14538 return bbJumpSwt->bbsDstTab[i];
14542 // Remove duplicates.
14543 Compiler::SwitchUniqueSuccSet sd = comp->GetDescriptorForSwitch(this);
14544 assert(i < sd.numDistinctSuccs); // Range check.
14545 return sd.nonDuplicates[i];
14553 // -------------------------------------------------------------------------
14554 // IsRegOptional: Returns true if this gentree node is marked by lowering to
14555 // indicate that codegen can still generate code even if it wasn't allocated
14557 bool GenTree::IsRegOptional() const
14559 #ifdef LEGACY_BACKEND
14562 return gtLsraInfo.regOptional;
14566 bool GenTree::IsPhiNode()
14568 return (OperGet() == GT_PHI_ARG) || (OperGet() == GT_PHI) || IsPhiDefn();
14571 bool GenTree::IsPhiDefn()
14573 bool res = ((OperGet() == GT_ASG) && (gtOp.gtOp2 != nullptr) && (gtOp.gtOp2->OperGet() == GT_PHI)) ||
14574 ((OperGet() == GT_STORE_LCL_VAR) && (gtOp.gtOp1 != nullptr) && (gtOp.gtOp1->OperGet() == GT_PHI));
14575 assert(!res || OperGet() == GT_STORE_LCL_VAR || gtOp.gtOp1->OperGet() == GT_LCL_VAR);
14579 bool GenTree::IsPhiDefnStmt()
14581 if (OperGet() != GT_STMT)
14585 GenTreePtr asg = gtStmt.gtStmtExpr;
14586 return asg->IsPhiDefn();
14589 // IsPartialLclFld: Check for a GT_LCL_FLD whose type is a different size than the lclVar.
14592 // comp - the Compiler object.
14595 // Returns "true" iff 'this' is a GT_LCL_FLD or GT_STORE_LCL_FLD on which the type
14596 // is not the same size as the type of the GT_LCL_VAR
14598 bool GenTree::IsPartialLclFld(Compiler* comp)
14600 return ((gtOper == GT_LCL_FLD) &&
14601 (comp->lvaTable[this->gtLclVarCommon.gtLclNum].lvExactSize != genTypeSize(gtType)));
14604 bool GenTree::DefinesLocal(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, bool* pIsEntire)
14606 if (OperIsAssignment())
14608 if (gtOp.gtOp1->IsLocal())
14610 GenTreeLclVarCommon* lclVarTree = gtOp.gtOp1->AsLclVarCommon();
14611 *pLclVarTree = lclVarTree;
14612 if (pIsEntire != nullptr)
14614 if (lclVarTree->IsPartialLclFld(comp))
14616 *pIsEntire = false;
14625 else if (gtOp.gtOp1->OperGet() == GT_IND)
14627 GenTreePtr indArg = gtOp.gtOp1->gtOp.gtOp1;
14628 return indArg->DefinesLocalAddr(comp, genTypeSize(gtOp.gtOp1->TypeGet()), pLclVarTree, pIsEntire);
14631 else if (OperIsBlkOp())
14633 GenTreePtr destAddr = gtOp.gtOp1->gtOp.gtOp1;
14634 unsigned width = 0;
14635 // Do we care about whether this assigns the entire variable?
14636 if (pIsEntire != nullptr)
14638 GenTreePtr blockWidth = gtOp.gtOp2;
14639 if (blockWidth->IsCnsIntOrI())
14641 if (blockWidth->IsIconHandle())
14643 // If it's a handle, it must be a class handle. We only create such block operations
14644 // for initialization of struct types, so the type of the argument(s) will match this
14645 // type, by construction, and be "entire".
14646 assert(blockWidth->IsIconHandle(GTF_ICON_CLASS_HDL));
14647 width = comp->info.compCompHnd->getClassSize(
14648 CORINFO_CLASS_HANDLE(blockWidth->gtIntConCommon.IconValue()));
14652 ssize_t swidth = blockWidth->AsIntConCommon()->IconValue();
14653 assert(swidth >= 0);
14654 // cpblk of size zero exists in the wild (in yacc-generated code in SQL) and is valid IL.
14659 width = unsigned(swidth);
14663 return destAddr->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
14669 // Returns true if this GenTree defines a result which is based on the address of a local.
14670 bool GenTree::DefinesLocalAddr(Compiler* comp, unsigned width, GenTreeLclVarCommon** pLclVarTree, bool* pIsEntire)
14672 if (OperGet() == GT_ADDR || OperGet() == GT_LCL_VAR_ADDR)
14674 GenTreePtr addrArg = this;
14675 if (OperGet() == GT_ADDR)
14677 addrArg = gtOp.gtOp1;
14680 if (addrArg->IsLocal() || addrArg->OperIsLocalAddr())
14682 GenTreeLclVarCommon* addrArgLcl = addrArg->AsLclVarCommon();
14683 *pLclVarTree = addrArgLcl;
14684 if (pIsEntire != nullptr)
14686 unsigned lclOffset = 0;
14687 if (addrArg->OperIsLocalField())
14689 lclOffset = addrArg->gtLclFld.gtLclOffs;
14692 if (lclOffset != 0)
14694 // We aren't updating the bytes at [0..lclOffset-1] so *pIsEntire should be set to false
14695 *pIsEntire = false;
14699 unsigned lclNum = addrArgLcl->GetLclNum();
14700 unsigned varWidth = comp->lvaLclExactSize(lclNum);
14701 if (comp->lvaTable[lclNum].lvNormalizeOnStore())
14703 // It's normalize on store, so use the full storage width -- writing to low bytes won't
14704 // necessarily yield a normalized value.
14705 varWidth = genTypeStSz(var_types(comp->lvaTable[lclNum].lvType)) * sizeof(int);
14707 *pIsEntire = (varWidth == width);
14712 else if (addrArg->OperGet() == GT_IND)
14714 // A GT_ADDR of a GT_IND can both be optimized away, recurse using the child of the GT_IND
14715 return addrArg->gtOp.gtOp1->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
14718 else if (OperGet() == GT_ADD)
14720 if (gtOp.gtOp1->IsCnsIntOrI())
14722 // If we just adding a zero then we allow an IsEntire match against width
14723 // otherwise we change width to zero to disallow an IsEntire Match
14724 return gtOp.gtOp2->DefinesLocalAddr(comp, gtOp.gtOp1->IsIntegralConst(0) ? width : 0, pLclVarTree,
14727 else if (gtOp.gtOp2->IsCnsIntOrI())
14729 // If we just adding a zero then we allow an IsEntire match against width
14730 // otherwise we change width to zero to disallow an IsEntire Match
14731 return gtOp.gtOp1->DefinesLocalAddr(comp, gtOp.gtOp2->IsIntegralConst(0) ? width : 0, pLclVarTree,
14735 // Post rationalization we could have GT_IND(GT_LEA(..)) trees.
14736 else if (OperGet() == GT_LEA)
14738 // This method gets invoked during liveness computation and therefore it is critical
14739 // that we don't miss 'use' of any local. The below logic is making the assumption
14740 // that in case of LEA(base, index, offset) - only base can be a GT_LCL_VAR_ADDR
14741 // and index is not.
14742 CLANG_FORMAT_COMMENT_ANCHOR;
14745 GenTreePtr index = gtOp.gtOp2;
14746 if (index != nullptr)
14748 assert(!index->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire));
14753 GenTreePtr base = gtOp.gtOp1;
14754 if (base != nullptr)
14756 // Lea could have an Indir as its base.
14757 if (base->OperGet() == GT_IND)
14759 base = base->gtOp.gtOp1->gtEffectiveVal(/*commas only*/ true);
14761 return base->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
14768 //------------------------------------------------------------------------
14769 // IsLocalExpr: Determine if this is a LclVarCommon node and return some
14770 // additional info about it in the two out parameters.
14773 // comp - The Compiler instance
14774 // pLclVarTree - An "out" argument that returns the local tree as a
14775 // LclVarCommon, if it is indeed local.
14776 // pFldSeq - An "out" argument that returns the value numbering field
14777 // sequence for the node, if any.
14780 // Returns true, and sets the out arguments accordingly, if this is
14781 // a LclVarCommon node.
14783 bool GenTree::IsLocalExpr(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, FieldSeqNode** pFldSeq)
14785 if (IsLocal()) // Note that this covers "GT_LCL_FLD."
14787 *pLclVarTree = AsLclVarCommon();
14788 if (OperGet() == GT_LCL_FLD)
14790 // Otherwise, prepend this field to whatever we've already accumulated outside in.
14791 *pFldSeq = comp->GetFieldSeqStore()->Append(AsLclFld()->gtFieldSeq, *pFldSeq);
14801 // If this tree evaluates some sum of a local address and some constants,
14802 // return the node for the local being addressed
14804 GenTreeLclVarCommon* GenTree::IsLocalAddrExpr()
14806 if (OperGet() == GT_ADDR)
14808 return gtOp.gtOp1->IsLocal() ? gtOp.gtOp1->AsLclVarCommon() : nullptr;
14810 else if (OperIsLocalAddr())
14812 return this->AsLclVarCommon();
14814 else if (OperGet() == GT_ADD)
14816 if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
14818 return gtOp.gtOp2->IsLocalAddrExpr();
14820 else if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
14822 return gtOp.gtOp1->IsLocalAddrExpr();
14829 bool GenTree::IsLocalAddrExpr(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, FieldSeqNode** pFldSeq)
14831 if (OperGet() == GT_ADDR)
14833 assert(!comp->compRationalIRForm);
14834 GenTreePtr addrArg = gtOp.gtOp1;
14835 if (addrArg->IsLocal()) // Note that this covers "GT_LCL_FLD."
14837 *pLclVarTree = addrArg->AsLclVarCommon();
14838 if (addrArg->OperGet() == GT_LCL_FLD)
14840 // Otherwise, prepend this field to whatever we've already accumulated outside in.
14841 *pFldSeq = comp->GetFieldSeqStore()->Append(addrArg->AsLclFld()->gtFieldSeq, *pFldSeq);
14850 else if (OperIsLocalAddr())
14852 *pLclVarTree = this->AsLclVarCommon();
14853 if (this->OperGet() == GT_LCL_FLD_ADDR)
14855 *pFldSeq = comp->GetFieldSeqStore()->Append(this->AsLclFld()->gtFieldSeq, *pFldSeq);
14859 else if (OperGet() == GT_ADD)
14861 if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
14863 if (gtOp.gtOp1->AsIntCon()->gtFieldSeq == nullptr)
14867 // Otherwise, prepend this field to whatever we've already accumulated outside in.
14868 *pFldSeq = comp->GetFieldSeqStore()->Append(gtOp.gtOp1->AsIntCon()->gtFieldSeq, *pFldSeq);
14869 return gtOp.gtOp2->IsLocalAddrExpr(comp, pLclVarTree, pFldSeq);
14871 else if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
14873 if (gtOp.gtOp2->AsIntCon()->gtFieldSeq == nullptr)
14877 // Otherwise, prepend this field to whatever we've already accumulated outside in.
14878 *pFldSeq = comp->GetFieldSeqStore()->Append(gtOp.gtOp2->AsIntCon()->gtFieldSeq, *pFldSeq);
14879 return gtOp.gtOp1->IsLocalAddrExpr(comp, pLclVarTree, pFldSeq);
14886 //------------------------------------------------------------------------
14887 // IsLclVarUpdateTree: Determine whether this is an assignment tree of the
14888 // form Vn = Vn 'oper' 'otherTree' where Vn is a lclVar
14891 // pOtherTree - An "out" argument in which 'otherTree' will be returned.
14892 // pOper - An "out" argument in which 'oper' will be returned.
14895 // If the tree is of the above form, the lclNum of the variable being
14896 // updated is returned, and 'pOtherTree' and 'pOper' are set.
14897 // Otherwise, returns BAD_VAR_NUM.
14900 // 'otherTree' can have any shape.
14901 // We avoid worrying about whether the op is commutative by only considering the
14902 // first operand of the rhs. It is expected that most trees of this form will
14903 // already have the lclVar on the lhs.
14904 // TODO-CQ: Evaluate whether there are missed opportunities due to this, or
14905 // whether gtSetEvalOrder will already have put the lclVar on the lhs in
14906 // the cases of interest.
14908 unsigned GenTree::IsLclVarUpdateTree(GenTree** pOtherTree, genTreeOps* pOper)
14910 unsigned lclNum = BAD_VAR_NUM;
14911 if (OperIsAssignment())
14913 GenTree* lhs = gtOp.gtOp1;
14914 if (lhs->OperGet() == GT_LCL_VAR)
14916 unsigned lhsLclNum = lhs->AsLclVarCommon()->gtLclNum;
14917 if (gtOper == GT_ASG)
14919 GenTree* rhs = gtOp.gtOp2;
14920 if (rhs->OperIsBinary() && (rhs->gtOp.gtOp1->gtOper == GT_LCL_VAR) &&
14921 (rhs->gtOp.gtOp1->AsLclVarCommon()->gtLclNum == lhsLclNum))
14923 lclNum = lhsLclNum;
14924 *pOtherTree = rhs->gtOp.gtOp2;
14925 *pOper = rhs->gtOper;
14930 lclNum = lhsLclNum;
14931 *pOper = GenTree::OpAsgToOper(gtOper);
14932 *pOtherTree = gtOp.gtOp2;
14939 // return true if this tree node is a subcomponent of parent for codegen purposes
14940 // (essentially, will be rolled into the same instruction)
14941 // Note that this method relies upon the value of gtRegNum field to determine
14942 // if the treenode is contained or not. Therefore you can not call this method
14943 // until after the LSRA phase has allocated physical registers to the treenodes.
14944 bool GenTree::isContained() const
14946 if (isContainedSpillTemp())
14956 // these actually produce a register (the flags reg, we just don't model it)
14957 // and are a separate instruction from the branch that consumes the result
14958 if (OperKind() & GTK_RELOP)
14963 // TODO-Cleanup : this is not clean, would be nice to have some way of marking this.
14970 case GT_STORE_LCL_FLD:
14971 case GT_STORE_LCL_VAR:
14972 case GT_ARR_BOUNDS_CHECK:
14976 case GT_START_NONGC:
14978 case GT_RETURNTRAP:
14980 case GT_PINVOKE_PROLOG:
14981 case GT_PHYSREGDST:
14982 case GT_PUTARG_STK:
14983 case GT_MEMORYBARRIER:
14989 case GT_SWITCH_TABLE:
14995 #ifdef FEATURE_SIMD
14997 #endif // FEATURE_SIMD
14999 #if !FEATURE_EH_FUNCLETS
15004 #if !defined(LEGACY_BACKEND) && !defined(_TARGET_64BIT_)
15006 // GT_LONG nodes are normally contained. The only exception is when the result
15007 // of a TYP_LONG operation is not used and this can only happen if the GT_LONG
15008 // is the last node in the statement (in linear order).
15009 return gtNext != nullptr;
15013 // Note: if you hit this assert you are probably calling isContained()
15014 // before the LSRA phase has allocated physical register to the tree nodes
15016 assert(gtType == TYP_VOID);
15020 // if it's contained it better have a parent
15021 assert(gtNext || OperIsLocal());
15026 // return true if node is contained and an indir
15027 bool GenTree::isContainedIndir() const
15029 return isContained() && isIndir();
15032 bool GenTree::isIndirAddrMode()
15034 return isIndir() && AsIndir()->Addr()->OperIsAddrMode() && AsIndir()->Addr()->isContained();
15037 bool GenTree::isIndir() const
15039 return OperGet() == GT_IND || OperGet() == GT_STOREIND;
15042 bool GenTreeIndir::HasBase()
15044 return Base() != nullptr;
15047 bool GenTreeIndir::HasIndex()
15049 return Index() != nullptr;
15052 GenTreePtr GenTreeIndir::Base()
15054 GenTreePtr addr = Addr();
15056 if (isIndirAddrMode())
15058 GenTree* result = addr->AsAddrMode()->Base();
15059 if (result != nullptr)
15061 result = result->gtEffectiveVal();
15067 return addr; // TODO: why do we return 'addr' here, but we return 'nullptr' in the equivalent Index() case?
15071 GenTree* GenTreeIndir::Index()
15073 if (isIndirAddrMode())
15075 GenTree* result = Addr()->AsAddrMode()->Index();
15076 if (result != nullptr)
15078 result = result->gtEffectiveVal();
15088 unsigned GenTreeIndir::Scale()
15092 return Addr()->AsAddrMode()->gtScale;
15100 size_t GenTreeIndir::Offset()
15102 if (isIndirAddrMode())
15104 return Addr()->AsAddrMode()->gtOffset;
15106 else if (Addr()->gtOper == GT_CLS_VAR_ADDR)
15108 return (size_t)Addr()->gtClsVar.gtClsVarHnd;
15110 else if (Addr()->IsCnsIntOrI() && Addr()->isContained())
15112 return Addr()->AsIntConCommon()->IconValue();
15120 //------------------------------------------------------------------------
15121 // GenTreeIntConCommon::ImmedValNeedsReloc: does this immediate value needs recording a relocation with the VM?
15124 // comp - Compiler instance
15127 // True if this immediate value needs recording a relocation with the VM; false otherwise.
15129 bool GenTreeIntConCommon::ImmedValNeedsReloc(Compiler* comp)
15131 #ifdef RELOC_SUPPORT
15132 return comp->opts.compReloc && (gtOper == GT_CNS_INT) && IsIconHandle();
15138 //------------------------------------------------------------------------
15139 // ImmedValCanBeFolded: can this immediate value be folded for op?
15142 // comp - Compiler instance
15143 // op - Tree operator
15146 // True if this immediate value can be folded for op; false otherwise.
15148 bool GenTreeIntConCommon::ImmedValCanBeFolded(Compiler* comp, genTreeOps op)
15150 // In general, immediate values that need relocations can't be folded.
15151 // There are cases where we do want to allow folding of handle comparisons
15152 // (e.g., typeof(T) == typeof(int)).
15153 return !ImmedValNeedsReloc(comp) || (op == GT_EQ) || (op == GT_NE);
15156 #ifdef _TARGET_AMD64_
15157 // Returns true if this absolute address fits within the base of an addr mode.
15158 // On Amd64 this effectively means, whether an absolute indirect address can
15159 // be encoded as 32-bit offset relative to IP or zero.
15160 bool GenTreeIntConCommon::FitsInAddrBase(Compiler* comp)
15162 #ifndef LEGACY_BACKEND
15164 // Early out if PC-rel encoding of absolute addr is disabled.
15165 if (!comp->opts.compEnablePCRelAddr)
15170 #endif //! LEGACY_BACKEND
15172 if (comp->opts.compReloc)
15174 // During Ngen JIT is always asked to generate relocatable code.
15175 // Hence JIT will try to encode only icon handles as pc-relative offsets.
15176 return IsIconHandle() && (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue()));
15180 // During Jitting, we are allowed to generate non-relocatable code.
15181 // On Amd64 we can encode an absolute indirect addr as an offset relative to zero or RIP.
15182 // An absolute indir addr that can fit within 32-bits can ben encoded as an offset relative
15183 // to zero. All other absolute indir addr could be attempted to be encoded as RIP relative
15184 // based on reloc hint provided by VM. RIP relative encoding is preferred over relative
15185 // to zero, because the former is one byte smaller than the latter. For this reason
15186 // we check for reloc hint first and then whether addr fits in 32-bits next.
15188 // VM starts off with an initial state to allow both data and code address to be encoded as
15189 // pc-relative offsets. Hence JIT will attempt to encode all absolute addresses as pc-relative
15190 // offsets. It is possible while jitting a method, an address could not be encoded as a
15191 // pc-relative offset. In that case VM will note the overflow and will trigger re-jitting
15192 // of the method with reloc hints turned off for all future methods. Second time around
15193 // jitting will succeed since JIT will not attempt to encode data addresses as pc-relative
15194 // offsets. Note that JIT will always attempt to relocate code addresses (.e.g call addr).
15195 // After an overflow, VM will assume any relocation recorded is for a code address and will
15196 // emit jump thunk if it cannot be encoded as pc-relative offset.
15197 return (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue())) || FitsInI32();
15201 // Returns true if this icon value is encoded as addr needs recording a relocation with VM
15202 bool GenTreeIntConCommon::AddrNeedsReloc(Compiler* comp)
15204 if (comp->opts.compReloc)
15206 // During Ngen JIT is always asked to generate relocatable code.
15207 // Hence JIT will try to encode only icon handles as pc-relative offsets.
15208 return IsIconHandle() && (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue()));
15212 return IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue());
15216 #elif defined(_TARGET_X86_)
15217 // Returns true if this absolute address fits within the base of an addr mode.
15218 // On x86 all addresses are 4-bytes and can be directly encoded in an addr mode.
15219 bool GenTreeIntConCommon::FitsInAddrBase(Compiler* comp)
15221 #ifndef LEGACY_BACKEND
15223 // Early out if PC-rel encoding of absolute addr is disabled.
15224 if (!comp->opts.compEnablePCRelAddr)
15229 #endif //! LEGACY_BACKEND
15231 // TODO-x86 - TLS field handles are excluded for now as they are accessed relative to FS segment.
15232 // Handling of TLS field handles is a NYI and this needs to be relooked after implementing it.
15233 return IsCnsIntOrI() && !IsIconHandle(GTF_ICON_TLS_HDL);
15236 // Returns true if this icon value is encoded as addr needs recording a relocation with VM
15237 bool GenTreeIntConCommon::AddrNeedsReloc(Compiler* comp)
15239 // If generating relocatable code, icons should be reported for recording relocatons.
15240 return comp->opts.compReloc && IsIconHandle();
15242 #endif //_TARGET_X86_
15244 bool GenTree::IsFieldAddr(Compiler* comp, GenTreePtr* pObj, GenTreePtr* pStatic, FieldSeqNode** pFldSeq)
15246 FieldSeqNode* newFldSeq = nullptr;
15247 GenTreePtr baseAddr = nullptr;
15248 bool mustBeStatic = false;
15250 FieldSeqNode* statStructFldSeq = nullptr;
15251 if (TypeGet() == TYP_REF)
15253 // Recognize struct static field patterns...
15254 if (OperGet() == GT_IND)
15256 GenTreePtr addr = gtOp.gtOp1;
15257 GenTreeIntCon* icon = nullptr;
15258 if (addr->OperGet() == GT_CNS_INT)
15260 icon = addr->AsIntCon();
15262 else if (addr->OperGet() == GT_ADD)
15264 // op1 should never be a field sequence (or any other kind of handle)
15265 assert((addr->gtOp.gtOp1->gtOper != GT_CNS_INT) || !addr->gtOp.gtOp1->IsIconHandle());
15266 if (addr->gtOp.gtOp2->OperGet() == GT_CNS_INT)
15268 icon = addr->gtOp.gtOp2->AsIntCon();
15271 if (icon != nullptr && !icon->IsIconHandle(GTF_ICON_STR_HDL) // String handles are a source of TYP_REFs.
15272 && icon->gtFieldSeq != nullptr &&
15273 icon->gtFieldSeq->m_next == nullptr // A static field should be a singleton
15274 // TODO-Review: A pseudoField here indicates an issue - this requires investigation
15275 // See test case src\ddsuites\src\clr\x86\CoreMangLib\Dev\Globalization\CalendarRegressions.exe
15276 && !(FieldSeqStore::IsPseudoField(icon->gtFieldSeq->m_fieldHnd)) &&
15277 icon->gtFieldSeq != FieldSeqStore::NotAField()) // Ignore non-fields.
15279 statStructFldSeq = icon->gtFieldSeq;
15283 addr = addr->gtEffectiveVal();
15285 // Perhaps it's a direct indirection of a helper call or a cse with a zero offset annotation.
15286 if ((addr->OperGet() == GT_CALL) || (addr->OperGet() == GT_LCL_VAR))
15288 FieldSeqNode* zeroFieldSeq = nullptr;
15289 if (comp->GetZeroOffsetFieldMap()->Lookup(addr, &zeroFieldSeq))
15291 if (zeroFieldSeq->m_next == nullptr)
15293 statStructFldSeq = zeroFieldSeq;
15299 else if (OperGet() == GT_CLS_VAR)
15301 GenTreeClsVar* clsVar = AsClsVar();
15302 if (clsVar->gtFieldSeq != nullptr && clsVar->gtFieldSeq->m_next == nullptr)
15304 statStructFldSeq = clsVar->gtFieldSeq;
15307 else if (OperIsLocal())
15309 // If we have a GT_LCL_VAR, it can be result of a CSE substitution
15310 // If it is then the CSE assignment will have a ValueNum that
15311 // describes the RHS of the CSE assignment.
15313 // The CSE could be a pointer to a boxed struct
15315 GenTreeLclVarCommon* lclVar = AsLclVarCommon();
15316 ValueNum vn = gtVNPair.GetLiberal();
15317 if (vn != ValueNumStore::NoVN)
15319 // Is the ValueNum a MapSelect involving a SharedStatic helper?
15320 VNFuncApp funcApp1;
15321 if (comp->vnStore->GetVNFunc(vn, &funcApp1) && (funcApp1.m_func == VNF_MapSelect) &&
15322 (comp->vnStore->IsSharedStatic(funcApp1.m_args[1])))
15324 ValueNum mapVN = funcApp1.m_args[0];
15325 // Is this new 'mapVN' ValueNum, a MapSelect involving a handle?
15326 VNFuncApp funcApp2;
15327 if (comp->vnStore->GetVNFunc(mapVN, &funcApp2) && (funcApp2.m_func == VNF_MapSelect) &&
15328 (comp->vnStore->IsVNHandle(funcApp2.m_args[1])))
15330 ValueNum fldHndVN = funcApp2.m_args[1];
15331 // Is this new 'fldHndVN' VNhandle a FieldHandle?
15332 unsigned flags = comp->vnStore->GetHandleFlags(fldHndVN);
15333 if (flags == GTF_ICON_FIELD_HDL)
15335 CORINFO_FIELD_HANDLE fieldHnd =
15336 CORINFO_FIELD_HANDLE(comp->vnStore->ConstantValue<ssize_t>(fldHndVN));
15338 // Record this field sequence in 'statStructFldSeq' as it is likely to be a Boxed Struct
15340 statStructFldSeq = comp->GetFieldSeqStore()->CreateSingleton(fieldHnd);
15347 if (statStructFldSeq != nullptr)
15349 assert(statStructFldSeq->m_next == nullptr);
15350 // Is this a pointer to a boxed struct?
15351 if (comp->gtIsStaticFieldPtrToBoxedStruct(TYP_REF, statStructFldSeq->m_fieldHnd))
15353 *pFldSeq = comp->GetFieldSeqStore()->Append(statStructFldSeq, *pFldSeq);
15362 *pStatic = nullptr;
15365 else if (OperGet() == GT_ADD)
15367 // op1 should never be a field sequence (or any other kind of handle)
15368 assert((gtOp.gtOp1->gtOper != GT_CNS_INT) || !gtOp.gtOp1->IsIconHandle());
15369 if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
15371 newFldSeq = gtOp.gtOp2->AsIntCon()->gtFieldSeq;
15372 baseAddr = gtOp.gtOp1;
15377 // Check if "this" has a zero-offset annotation.
15378 if (!comp->GetZeroOffsetFieldMap()->Lookup(this, &newFldSeq))
15380 // If not, this is not a field address.
15386 mustBeStatic = true;
15390 // If not we don't have a field seq, it's not a field address.
15391 if (newFldSeq == nullptr || newFldSeq == FieldSeqStore::NotAField())
15396 // Prepend this field to whatever we've already accumulated (outside-in).
15397 *pFldSeq = comp->GetFieldSeqStore()->Append(newFldSeq, *pFldSeq);
15399 // Is it a static or instance field?
15400 if (!FieldSeqStore::IsPseudoField(newFldSeq->m_fieldHnd) &&
15401 comp->info.compCompHnd->isFieldStatic(newFldSeq->m_fieldHnd))
15403 // It is a static field. We're done.
15405 *pStatic = baseAddr;
15408 else if ((baseAddr != nullptr) && !mustBeStatic)
15410 // It's an instance field...but it must be for a struct field, since we've not yet encountered
15411 // a "TYP_REF" address. Analyze the reset of the address.
15412 return baseAddr->gtEffectiveVal()->IsFieldAddr(comp, pObj, pStatic, pFldSeq);
15419 bool Compiler::gtIsStaticFieldPtrToBoxedStruct(var_types fieldNodeType, CORINFO_FIELD_HANDLE fldHnd)
15421 if (fieldNodeType != TYP_REF)
15425 CORINFO_CLASS_HANDLE fldCls = nullptr;
15426 noway_assert(fldHnd != nullptr);
15427 CorInfoType cit = info.compCompHnd->getFieldType(fldHnd, &fldCls);
15428 var_types fieldTyp = JITtype2varType(cit);
15429 return fieldTyp != TYP_REF;
15432 CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleIfPresent(GenTree* tree)
15434 CORINFO_CLASS_HANDLE structHnd = NO_CLASS_HANDLE;
15435 tree = tree->gtEffectiveVal();
15436 if (varTypeIsStruct(tree->gtType))
15438 switch (tree->gtOper)
15443 structHnd = impGetRefAnyClass();
15446 structHnd = tree->gtObj.gtClass;
15449 structHnd = tree->gtCall.gtRetClsHnd;
15452 structHnd = tree->gtRetExpr.gtRetClsHnd;
15455 structHnd = tree->gtArgPlace.gtArgPlaceClsHnd;
15458 structHnd = tree->gtIndex.gtStructElemClass;
15461 info.compCompHnd->getFieldType(tree->gtField.gtFldHnd, &structHnd);
15464 structHnd = gtGetStructHandle(tree->gtGetOp1());
15468 structHnd = lvaTable[tree->AsLclVarCommon()->gtLclNum].lvVerTypeInfo.GetClassHandle();
15471 structHnd = gtGetStructHandleIfPresent(tree->gtOp.gtOp1);
15474 #ifdef FEATURE_SIMD
15475 if (varTypeIsSIMD(tree))
15477 structHnd = gtGetStructHandleForSIMD(tree->gtType, TYP_FLOAT);
15481 if (tree->gtFlags & GTF_IND_ARR_INDEX)
15484 bool b = GetArrayInfoMap()->Lookup(tree, &arrInfo);
15486 structHnd = EncodeElemType(arrInfo.m_elemType, arrInfo.m_elemStructType);
15489 #ifdef FEATURE_SIMD
15491 structHnd = gtGetStructHandleForSIMD(tree->gtType, tree->AsSIMD()->gtSIMDBaseType);
15492 #endif // FEATURE_SIMD
15499 CORINFO_CLASS_HANDLE Compiler::gtGetStructHandle(GenTree* tree)
15501 CORINFO_CLASS_HANDLE structHnd = gtGetStructHandleIfPresent(tree);
15502 assert(structHnd != NO_CLASS_HANDLE);
15506 void GenTree::ParseArrayAddress(
15507 Compiler* comp, ArrayInfo* arrayInfo, GenTreePtr* pArr, ValueNum* pInxVN, FieldSeqNode** pFldSeq)
15510 ValueNum inxVN = ValueNumStore::NoVN;
15511 ssize_t offset = 0;
15512 FieldSeqNode* fldSeq = nullptr;
15514 ParseArrayAddressWork(comp, 1, pArr, &inxVN, &offset, &fldSeq);
15516 // If we didn't find an array reference (perhaps it is the constant null?) we will give up.
15517 if (*pArr == nullptr)
15522 // OK, new we have to figure out if any part of the "offset" is a constant contribution to the index.
15523 // First, sum the offsets of any fields in fldSeq.
15524 unsigned fieldOffsets = 0;
15525 FieldSeqNode* fldSeqIter = fldSeq;
15526 // Also, find the first non-pseudo field...
15527 assert(*pFldSeq == nullptr);
15528 while (fldSeqIter != nullptr)
15530 if (fldSeqIter == FieldSeqStore::NotAField())
15532 // TODO-Review: A NotAField here indicates a failure to properly maintain the field sequence
15533 // See test case self_host_tests_x86\jit\regression\CLR-x86-JIT\v1-m12-beta2\ b70992\ b70992.exe
15534 // Safest thing to do here is to drop back to MinOpts
15535 noway_assert(!"fldSeqIter is NotAField() in ParseArrayAddress");
15538 if (!FieldSeqStore::IsPseudoField(fldSeqIter->m_fieldHnd))
15540 if (*pFldSeq == nullptr)
15542 *pFldSeq = fldSeqIter;
15544 CORINFO_CLASS_HANDLE fldCls = nullptr;
15545 noway_assert(fldSeqIter->m_fieldHnd != nullptr);
15546 CorInfoType cit = comp->info.compCompHnd->getFieldType(fldSeqIter->m_fieldHnd, &fldCls);
15547 fieldOffsets += comp->compGetTypeSize(cit, fldCls);
15549 fldSeqIter = fldSeqIter->m_next;
15552 // Is there some portion of the "offset" beyond the first-elem offset and the struct field suffix we just computed?
15553 if (!FitsIn<ssize_t>(fieldOffsets + arrayInfo->m_elemOffset) || !FitsIn<ssize_t>(arrayInfo->m_elemSize))
15555 // This seems unlikely, but no harm in being safe...
15556 *pInxVN = comp->GetValueNumStore()->VNForExpr(nullptr, TYP_INT);
15560 ssize_t offsetAccountedFor = static_cast<ssize_t>(fieldOffsets + arrayInfo->m_elemOffset);
15561 ssize_t elemSize = static_cast<ssize_t>(arrayInfo->m_elemSize);
15563 ssize_t constIndOffset = offset - offsetAccountedFor;
15564 // This should be divisible by the element size...
15565 assert((constIndOffset % elemSize) == 0);
15566 ssize_t constInd = constIndOffset / elemSize;
15568 ValueNumStore* vnStore = comp->GetValueNumStore();
15570 if (inxVN == ValueNumStore::NoVN)
15572 // Must be a constant index.
15573 *pInxVN = vnStore->VNForPtrSizeIntCon(constInd);
15578 // Perform ((inxVN / elemSizeVN) + vnForConstInd)
15581 // The value associated with the index value number (inxVN) is the offset into the array,
15582 // which has been scaled by element size. We need to recover the array index from that offset
15583 if (vnStore->IsVNConstant(inxVN))
15585 ssize_t index = vnStore->CoercedConstantValue<ssize_t>(inxVN);
15586 noway_assert(elemSize > 0 && ((index % elemSize) == 0));
15587 *pInxVN = vnStore->VNForPtrSizeIntCon((index / elemSize) + constInd);
15591 bool canFoldDiv = false;
15593 // If the index VN is a MUL by elemSize, see if we can eliminate it instead of adding
15594 // the division by elemSize.
15596 if (vnStore->GetVNFunc(inxVN, &funcApp) && funcApp.m_func == (VNFunc)GT_MUL)
15598 ValueNum vnForElemSize = vnStore->VNForLongCon(elemSize);
15600 // One of the multiply operand is elemSize, so the resulting
15601 // index VN should simply be the other operand.
15602 if (funcApp.m_args[1] == vnForElemSize)
15604 *pInxVN = funcApp.m_args[0];
15607 else if (funcApp.m_args[0] == vnForElemSize)
15609 *pInxVN = funcApp.m_args[1];
15614 // Perform ((inxVN / elemSizeVN) + vnForConstInd)
15617 ValueNum vnForElemSize = vnStore->VNForPtrSizeIntCon(elemSize);
15618 ValueNum vnForScaledInx =
15619 vnStore->VNForFunc(TYP_I_IMPL, GetVNFuncForOper(GT_DIV, false), inxVN, vnForElemSize);
15620 *pInxVN = vnForScaledInx;
15625 ValueNum vnForConstInd = comp->GetValueNumStore()->VNForPtrSizeIntCon(constInd);
15626 *pInxVN = comp->GetValueNumStore()->VNForFunc(TYP_I_IMPL,
15627 GetVNFuncForOper(GT_ADD, (gtFlags & GTF_UNSIGNED) != 0),
15628 *pInxVN, vnForConstInd);
15634 void GenTree::ParseArrayAddressWork(
15635 Compiler* comp, ssize_t inputMul, GenTreePtr* pArr, ValueNum* pInxVN, ssize_t* pOffset, FieldSeqNode** pFldSeq)
15637 if (TypeGet() == TYP_REF)
15639 // This must be the array pointer.
15641 assert(inputMul == 1); // Can't multiply the array pointer by anything.
15648 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, gtIntCon.gtFieldSeq);
15649 *pOffset += (inputMul * gtIntCon.gtIconVal);
15654 gtOp.gtOp1->ParseArrayAddressWork(comp, inputMul, pArr, pInxVN, pOffset, pFldSeq);
15655 if (OperGet() == GT_SUB)
15657 inputMul = -inputMul;
15659 gtOp.gtOp2->ParseArrayAddressWork(comp, inputMul, pArr, pInxVN, pOffset, pFldSeq);
15664 // If one op is a constant, continue parsing down.
15665 ssize_t subMul = 0;
15666 GenTreePtr nonConst = nullptr;
15667 if (gtOp.gtOp1->IsCnsIntOrI())
15669 // If the other arg is an int constant, and is a "not-a-field", choose
15670 // that as the multiplier, thus preserving constant index offsets...
15671 if (gtOp.gtOp2->OperGet() == GT_CNS_INT &&
15672 gtOp.gtOp2->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField())
15674 subMul = gtOp.gtOp2->gtIntConCommon.IconValue();
15675 nonConst = gtOp.gtOp1;
15679 subMul = gtOp.gtOp1->gtIntConCommon.IconValue();
15680 nonConst = gtOp.gtOp2;
15683 else if (gtOp.gtOp2->IsCnsIntOrI())
15685 subMul = gtOp.gtOp2->gtIntConCommon.IconValue();
15686 nonConst = gtOp.gtOp1;
15688 if (nonConst != nullptr)
15690 nonConst->ParseArrayAddressWork(comp, inputMul * subMul, pArr, pInxVN, pOffset, pFldSeq);
15693 // Otherwise, exit the switch, treat as a contribution to the index.
15698 // If one op is a constant, continue parsing down.
15699 if (gtOp.gtOp2->IsCnsIntOrI())
15701 ssize_t subMul = 1 << gtOp.gtOp2->gtIntConCommon.IconValue();
15702 gtOp.gtOp1->ParseArrayAddressWork(comp, inputMul * subMul, pArr, pInxVN, pOffset, pFldSeq);
15705 // Otherwise, exit the switch, treat as a contribution to the index.
15711 // If we didn't return above, must be a constribution to the non-constant part of the index VN.
15712 ValueNum vn = comp->GetValueNumStore()->VNNormVal(gtVNPair.GetLiberal()); // We don't care about exceptions for
15716 ValueNum mulVN = comp->GetValueNumStore()->VNForLongCon(inputMul);
15717 vn = comp->GetValueNumStore()->VNForFunc(TypeGet(), GetVNFuncForOper(GT_MUL, false), mulVN, vn);
15719 if (*pInxVN == ValueNumStore::NoVN)
15725 *pInxVN = comp->GetValueNumStore()->VNForFunc(TypeGet(), GetVNFuncForOper(GT_ADD, false), *pInxVN, vn);
15730 bool GenTree::ParseArrayElemForm(Compiler* comp, ArrayInfo* arrayInfo, FieldSeqNode** pFldSeq)
15734 if (gtFlags & GTF_IND_ARR_INDEX)
15736 bool b = comp->GetArrayInfoMap()->Lookup(this, arrayInfo);
15742 GenTreePtr addr = AsIndir()->Addr();
15743 return addr->ParseArrayElemAddrForm(comp, arrayInfo, pFldSeq);
15751 bool GenTree::ParseArrayElemAddrForm(Compiler* comp, ArrayInfo* arrayInfo, FieldSeqNode** pFldSeq)
15757 GenTreePtr arrAddr = nullptr;
15758 GenTreePtr offset = nullptr;
15759 if (gtOp.gtOp1->TypeGet() == TYP_BYREF)
15761 arrAddr = gtOp.gtOp1;
15762 offset = gtOp.gtOp2;
15764 else if (gtOp.gtOp2->TypeGet() == TYP_BYREF)
15766 arrAddr = gtOp.gtOp2;
15767 offset = gtOp.gtOp1;
15773 if (!offset->ParseOffsetForm(comp, pFldSeq))
15777 return arrAddr->ParseArrayElemAddrForm(comp, arrayInfo, pFldSeq);
15782 GenTreePtr addrArg = gtOp.gtOp1;
15783 if (addrArg->OperGet() != GT_IND)
15789 // The "Addr" node might be annotated with a zero-offset field sequence.
15790 FieldSeqNode* zeroOffsetFldSeq = nullptr;
15791 if (comp->GetZeroOffsetFieldMap()->Lookup(this, &zeroOffsetFldSeq))
15793 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, zeroOffsetFldSeq);
15795 return addrArg->ParseArrayElemForm(comp, arrayInfo, pFldSeq);
15804 bool GenTree::ParseOffsetForm(Compiler* comp, FieldSeqNode** pFldSeq)
15810 GenTreeIntCon* icon = AsIntCon();
15811 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, icon->gtFieldSeq);
15816 if (!gtOp.gtOp1->ParseOffsetForm(comp, pFldSeq))
15820 return gtOp.gtOp2->ParseOffsetForm(comp, pFldSeq);
15827 void GenTree::LabelIndex(Compiler* comp, bool isConst)
15832 // If we got here, this is a contribution to the constant part of the index.
15835 gtIntCon.gtFieldSeq =
15836 comp->GetFieldSeqStore()->CreateSingleton(FieldSeqStore::ConstantIndexPseudoField);
15841 gtFlags |= GTF_VAR_ARR_INDEX;
15846 gtOp.gtOp1->LabelIndex(comp, isConst);
15847 gtOp.gtOp2->LabelIndex(comp, isConst);
15851 gtOp.gtOp1->LabelIndex(comp, isConst);
15854 case GT_ARR_LENGTH:
15855 gtFlags |= GTF_ARRLEN_ARR_IDX;
15859 // For all other operators, peel off one constant; and then label the other if it's also a constant.
15860 if (OperIsArithmetic() || OperIsCompare())
15862 if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
15864 gtOp.gtOp1->LabelIndex(comp, isConst);
15867 else if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
15869 gtOp.gtOp2->LabelIndex(comp, isConst);
15872 // Otherwise continue downward on both, labeling vars.
15873 gtOp.gtOp1->LabelIndex(comp, false);
15874 gtOp.gtOp2->LabelIndex(comp, false);
15880 // Note that the value of the below field doesn't matter; it exists only to provide a distinguished address.
15883 FieldSeqNode FieldSeqStore::s_notAField(nullptr, nullptr);
15885 // FieldSeqStore methods.
15886 FieldSeqStore::FieldSeqStore(IAllocator* alloc) : m_alloc(alloc), m_canonMap(new (alloc) FieldSeqNodeCanonMap(alloc))
15890 FieldSeqNode* FieldSeqStore::CreateSingleton(CORINFO_FIELD_HANDLE fieldHnd)
15892 FieldSeqNode fsn(fieldHnd, nullptr);
15893 FieldSeqNode* res = nullptr;
15894 if (m_canonMap->Lookup(fsn, &res))
15900 res = reinterpret_cast<FieldSeqNode*>(m_alloc->Alloc(sizeof(FieldSeqNode)));
15902 m_canonMap->Set(fsn, res);
15907 FieldSeqNode* FieldSeqStore::Append(FieldSeqNode* a, FieldSeqNode* b)
15913 else if (a == NotAField())
15915 return NotAField();
15917 else if (b == nullptr)
15921 else if (b == NotAField())
15923 return NotAField();
15924 // Extremely special case for ConstantIndex pseudo-fields -- appending consecutive such
15925 // together collapse to one.
15927 else if (a->m_next == nullptr && a->m_fieldHnd == ConstantIndexPseudoField &&
15928 b->m_fieldHnd == ConstantIndexPseudoField)
15934 FieldSeqNode* tmp = Append(a->m_next, b);
15935 FieldSeqNode fsn(a->m_fieldHnd, tmp);
15936 FieldSeqNode* res = nullptr;
15937 if (m_canonMap->Lookup(fsn, &res))
15943 res = reinterpret_cast<FieldSeqNode*>(m_alloc->Alloc(sizeof(FieldSeqNode)));
15945 m_canonMap->Set(fsn, res);
15952 int FieldSeqStore::FirstElemPseudoFieldStruct;
15953 int FieldSeqStore::ConstantIndexPseudoFieldStruct;
15955 CORINFO_FIELD_HANDLE FieldSeqStore::FirstElemPseudoField =
15956 (CORINFO_FIELD_HANDLE)&FieldSeqStore::FirstElemPseudoFieldStruct;
15957 CORINFO_FIELD_HANDLE FieldSeqStore::ConstantIndexPseudoField =
15958 (CORINFO_FIELD_HANDLE)&FieldSeqStore::ConstantIndexPseudoFieldStruct;
15960 bool FieldSeqNode::IsFirstElemFieldSeq()
15962 // this must be non-null per ISO C++
15963 return m_fieldHnd == FieldSeqStore::FirstElemPseudoField;
15966 bool FieldSeqNode::IsConstantIndexFieldSeq()
15968 // this must be non-null per ISO C++
15969 return m_fieldHnd == FieldSeqStore::ConstantIndexPseudoField;
15972 bool FieldSeqNode::IsPseudoField()
15974 if (this == nullptr)
15978 return m_fieldHnd == FieldSeqStore::FirstElemPseudoField || m_fieldHnd == FieldSeqStore::ConstantIndexPseudoField;
15981 #ifdef FEATURE_SIMD
15982 GenTreeSIMD* Compiler::gtNewSIMDNode(
15983 var_types type, GenTreePtr op1, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size)
15985 // TODO-CQ: An operand may be a GT_OBJ(GT_ADDR(GT_LCL_VAR))), in which case it should be
15986 // marked lvUsedInSIMDIntrinsic.
15987 assert(op1 != nullptr);
15988 if (op1->OperGet() == GT_LCL_VAR)
15990 unsigned lclNum = op1->AsLclVarCommon()->GetLclNum();
15991 LclVarDsc* lclVarDsc = &lvaTable[lclNum];
15992 lclVarDsc->lvUsedInSIMDIntrinsic = true;
15995 return new (this, GT_SIMD) GenTreeSIMD(type, op1, simdIntrinsicID, baseType, size);
15998 GenTreeSIMD* Compiler::gtNewSIMDNode(
15999 var_types type, GenTreePtr op1, GenTreePtr op2, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size)
16001 // TODO-CQ: An operand may be a GT_OBJ(GT_ADDR(GT_LCL_VAR))), in which case it should be
16002 // marked lvUsedInSIMDIntrinsic.
16003 assert(op1 != nullptr);
16004 if (op1->OperIsLocal())
16006 unsigned lclNum = op1->AsLclVarCommon()->GetLclNum();
16007 LclVarDsc* lclVarDsc = &lvaTable[lclNum];
16008 lclVarDsc->lvUsedInSIMDIntrinsic = true;
16011 if (op2 != nullptr && op2->OperIsLocal())
16013 unsigned lclNum = op2->AsLclVarCommon()->GetLclNum();
16014 LclVarDsc* lclVarDsc = &lvaTable[lclNum];
16015 lclVarDsc->lvUsedInSIMDIntrinsic = true;
16018 return new (this, GT_SIMD) GenTreeSIMD(type, op1, op2, simdIntrinsicID, baseType, size);
16021 bool GenTree::isCommutativeSIMDIntrinsic()
16023 assert(gtOper == GT_SIMD);
16024 switch (AsSIMD()->gtSIMDIntrinsicID)
16026 case SIMDIntrinsicAdd:
16027 case SIMDIntrinsicBitwiseAnd:
16028 case SIMDIntrinsicBitwiseOr:
16029 case SIMDIntrinsicBitwiseXor:
16030 case SIMDIntrinsicEqual:
16031 case SIMDIntrinsicMax:
16032 case SIMDIntrinsicMin:
16033 case SIMDIntrinsicMul:
16034 case SIMDIntrinsicOpEquality:
16035 case SIMDIntrinsicOpInEquality:
16041 #endif // FEATURE_SIMD
16043 //---------------------------------------------------------------------------------------
16044 // GenTreeArgList::Prepend:
16045 // Prepends an element to a GT_LIST.
16048 // compiler - The compiler context.
16049 // element - The element to prepend.
16052 // The new head of the list.
16053 GenTreeArgList* GenTreeArgList::Prepend(Compiler* compiler, GenTree* element)
16055 GenTreeArgList* head = compiler->gtNewListNode(element, this);
16056 head->gtFlags |= (gtFlags & GTF_LIST_AGGREGATE);
16057 gtFlags &= ~GTF_LIST_AGGREGATE;
16061 //---------------------------------------------------------------------------------------
16062 // InitializeStructReturnType:
16063 // Initialize the Return Type Descriptor for a method that returns a struct type
16066 // comp - Compiler Instance
16067 // retClsHnd - VM handle to the struct type returned by the method
16072 void ReturnTypeDesc::InitializeStructReturnType(Compiler* comp, CORINFO_CLASS_HANDLE retClsHnd)
16076 #if FEATURE_MULTIREG_RET
16078 assert(retClsHnd != NO_CLASS_HANDLE);
16079 unsigned structSize = comp->info.compCompHnd->getClassSize(retClsHnd);
16081 Compiler::structPassingKind howToReturnStruct;
16082 var_types returnType = comp->getReturnTypeForStruct(retClsHnd, &howToReturnStruct, structSize);
16084 switch (howToReturnStruct)
16086 case Compiler::SPK_PrimitiveType:
16088 assert(returnType != TYP_UNKNOWN);
16089 assert(returnType != TYP_STRUCT);
16090 m_regType[0] = returnType;
16094 case Compiler::SPK_ByValueAsHfa:
16096 assert(returnType == TYP_STRUCT);
16097 var_types hfaType = comp->GetHfaType(retClsHnd);
16099 // We should have an hfa struct type
16100 assert(varTypeIsFloating(hfaType));
16102 // Note that the retail build issues a warning about a potential divsion by zero without this Max function
16103 unsigned elemSize = Max((unsigned)1, EA_SIZE_IN_BYTES(emitActualTypeSize(hfaType)));
16105 // The size of this struct should be evenly divisible by elemSize
16106 assert((structSize % elemSize) == 0);
16108 unsigned hfaCount = (structSize / elemSize);
16109 for (unsigned i = 0; i < hfaCount; ++i)
16111 m_regType[i] = hfaType;
16114 if (comp->compFloatingPointUsed == false)
16116 comp->compFloatingPointUsed = true;
16121 case Compiler::SPK_ByValue:
16123 assert(returnType == TYP_STRUCT);
16125 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
16127 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
16128 comp->eeGetSystemVAmd64PassStructInRegisterDescriptor(retClsHnd, &structDesc);
16130 assert(structDesc.passedInRegisters);
16131 for (int i = 0; i < structDesc.eightByteCount; i++)
16133 assert(i < MAX_RET_REG_COUNT);
16134 m_regType[i] = comp->GetEightByteType(structDesc, i);
16137 #elif defined(_TARGET_ARM64_)
16139 // a non-HFA struct returned using two registers
16141 assert((structSize > TARGET_POINTER_SIZE) && (structSize <= (2 * TARGET_POINTER_SIZE)));
16143 BYTE gcPtrs[2] = {TYPE_GC_NONE, TYPE_GC_NONE};
16144 comp->info.compCompHnd->getClassGClayout(retClsHnd, &gcPtrs[0]);
16145 for (unsigned i = 0; i < 2; ++i)
16147 m_regType[i] = comp->getJitGCType(gcPtrs[i]);
16150 #else // _TARGET_XXX_
16152 // This target needs support here!
16154 NYI("Unsupported TARGET returning a TYP_STRUCT in InitializeStructReturnType");
16156 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
16158 break; // for case SPK_ByValue
16161 case Compiler::SPK_ByReference:
16163 // We are returning using the return buffer argument
16164 // There are no return registers
16169 unreached(); // By the contract of getReturnTypeForStruct we should never get here.
16171 } // end of switch (howToReturnStruct)
16173 #endif // FEATURE_MULTIREG_RET
16180 //---------------------------------------------------------------------------------------
16181 // InitializeLongReturnType:
16182 // Initialize the Return Type Descriptor for a method that returns a TYP_LONG
16185 // comp - Compiler Instance
16190 void ReturnTypeDesc::InitializeLongReturnType(Compiler* comp)
16192 #if defined(_TARGET_X86_)
16194 // Setups up a ReturnTypeDesc for returning a long using two registers
16196 assert(MAX_RET_REG_COUNT >= 2);
16197 m_regType[0] = TYP_INT;
16198 m_regType[1] = TYP_INT;
16200 #else // not _TARGET_X86_
16202 m_regType[0] = TYP_LONG;
16204 #endif // _TARGET_X86_
16211 //-------------------------------------------------------------------
16212 // GetABIReturnReg: Return ith return register as per target ABI
16215 // idx - Index of the return register.
16216 // The first return register has an index of 0 and so on.
16219 // Returns ith return register as per target ABI.
16222 // Right now this is implemented only for x64 Unix
16223 // and yet to be implemented for other multi-reg return
16224 // targets (Arm64/Arm32/x86).
16226 // TODO-ARM: Implement this routine to support HFA returns.
16227 // TODO-X86: Implement this routine to support long returns.
16228 regNumber ReturnTypeDesc::GetABIReturnReg(unsigned idx)
16230 unsigned count = GetReturnRegCount();
16231 assert(idx < count);
16233 regNumber resultReg = REG_NA;
16235 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
16236 var_types regType0 = GetReturnRegType(0);
16240 if (varTypeIsIntegralOrI(regType0))
16242 resultReg = REG_INTRET;
16246 noway_assert(varTypeIsFloating(regType0));
16247 resultReg = REG_FLOATRET;
16252 var_types regType1 = GetReturnRegType(1);
16254 if (varTypeIsIntegralOrI(regType1))
16256 if (varTypeIsIntegralOrI(regType0))
16258 resultReg = REG_INTRET_1;
16262 resultReg = REG_INTRET;
16267 noway_assert(varTypeIsFloating(regType1));
16269 if (varTypeIsFloating(regType0))
16271 resultReg = REG_FLOATRET_1;
16275 resultReg = REG_FLOATRET;
16280 #elif defined(_TARGET_X86_)
16284 resultReg = REG_LNGRET_LO;
16288 resultReg = REG_LNGRET_HI;
16291 #elif defined(_TARGET_ARM64_)
16293 var_types regType = GetReturnRegType(idx);
16294 if (varTypeIsIntegralOrI(regType))
16296 noway_assert(idx < 2); // Up to 2 return registers for 16-byte structs
16297 resultReg = (idx == 0) ? REG_INTRET : REG_INTRET_1; // X0 or X1
16301 noway_assert(idx < 4); // Up to 4 return registers for HFA's
16302 resultReg = (regNumber)((unsigned)(REG_FLOATRET) + idx); // V0, V1, V2 or V3
16305 #endif // TARGET_XXX
16307 assert(resultReg != REG_NA);
16311 //--------------------------------------------------------------------------------
16312 // GetABIReturnRegs: get the mask of return registers as per target arch ABI.
16318 // reg mask of return registers in which the return type is returned.
16321 // For now this is implemented only for x64 Unix and yet to be implemented
16322 // for other multi-reg return targets (Arm64/Arm32x86).
16324 // This routine can be used when the caller is not particular about the order
16325 // of return registers and wants to know the set of return registers.
16327 // TODO-ARM: Implement this routine to support HFA returns.
16328 // TODO-ARM64: Implement this routine to support HFA returns.
16329 // TODO-X86: Implement this routine to support long returns.
16332 regMaskTP ReturnTypeDesc::GetABIReturnRegs()
16334 regMaskTP resultMask = RBM_NONE;
16336 unsigned count = GetReturnRegCount();
16337 for (unsigned i = 0; i < count; ++i)
16339 resultMask |= genRegMask(GetABIReturnReg(i));