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 /*****************************************************************************/
24 unsigned short GenTree::gtOperKindTable[] =
26 #define GTNODE(en,sn,cm,ok) ok + GTK_COMMUTE*cm,
30 /*****************************************************************************/
32 genTreeOps GenTree::OpAsgToOper(genTreeOps op)
35 assert(OperIsAssignment(op) && op != GT_ASG);
38 case GT_ASG_ADD: return GT_ADD;
39 case GT_ASG_SUB: return GT_SUB;
40 case GT_ASG_MUL: return GT_MUL;
41 case GT_ASG_DIV: return GT_DIV;
42 case GT_ASG_MOD: return GT_MOD;
44 case GT_ASG_UDIV: return GT_UDIV;
45 case GT_ASG_UMOD: return GT_UMOD;
47 case GT_ASG_OR: return GT_OR;
48 case GT_ASG_XOR: return GT_XOR;
49 case GT_ASG_AND: return GT_AND;
50 case GT_ASG_LSH: return GT_LSH;
51 case GT_ASG_RSH: return GT_RSH;
52 case GT_ASG_RSZ: return GT_RSZ;
54 case GT_CHS: return GT_NEG;
57 unreached(); // Precondition implies we don't get here.
61 /*****************************************************************************
63 * The types of different GenTree nodes
70 //--------------------------------------------
72 // IndentStack: This struct is used, along with its related enums and strings,
73 // to control both the indendtation and the printing of arcs.
76 // The mode of printing is set in the Constructor, using its 'compiler' argument.
77 // Currently it only prints arcs when fgOrder == fgOrderLinear.
78 // The type of arc to print is specified by the IndentInfo enum, and is controlled
79 // by the caller of the Push() method.
81 enum IndentChars {ICVertical, ICBottom, ICTop, ICMiddle, ICDash, ICEmbedded, ICTerminal, ICError, IndentCharCount };
82 // Sets of strings for different dumping options vert bot top mid dash embedded terminal error
83 static const char* emptyIndents[IndentCharCount] = { " ", " ", " ", " ", " ", "{", "", "?" };
84 static const char* asciiIndents[IndentCharCount] = { "|", "\\", "/", "+", "-", "{", "*", "?" };
85 static const char* unicodeIndents[IndentCharCount] = { "\xe2\x94\x82", "\xe2\x94\x94", "\xe2\x94\x8c", "\xe2\x94\x9c", "\xe2\x94\x80", "{", "\xe2\x96\x8c", "?" };
86 typedef ArrayStack<Compiler::IndentInfo> IndentInfoStack;
89 IndentInfoStack stack;
92 // Constructor for IndentStack. Uses 'compiler' to determine the mode of printing.
93 IndentStack(Compiler* compiler) :
96 if (compiler->asciiTrees)
98 indents = asciiIndents;
102 indents = unicodeIndents;
106 // Return the depth of the current indentation.
109 return stack.Height();
112 // Push a new indentation onto the stack, of the given type.
113 void Push(Compiler::IndentInfo info)
118 // Pop the most recent indentation type off the stack.
119 Compiler::IndentInfo Pop()
124 // Print the current indentation and arcs.
127 unsigned indentCount = Depth();
128 for (unsigned i = 0; i < indentCount; i++)
130 unsigned index = indentCount-1-i;
131 switch (stack.Index(index))
133 case Compiler::IndentInfo::IINone:
136 case Compiler::IndentInfo::IIEmbedded:
137 printf("%s ", indents[ICEmbedded]);
139 case Compiler::IndentInfo::IIArc:
142 printf("%s%s%s", indents[ICMiddle], indents[ICDash], indents[ICDash]);
146 printf("%s ", indents[ICVertical]);
149 case Compiler::IndentInfo::IIArcBottom:
150 printf("%s%s%s", indents[ICBottom], indents[ICDash], indents[ICDash]);
152 case Compiler::IndentInfo::IIArcTop:
153 printf("%s%s%s", indents[ICTop], indents[ICDash], indents[ICDash]);
155 case Compiler::IndentInfo::IIError:
156 printf("%s%s%s", indents[ICError], indents[ICDash], indents[ICDash]);
162 printf("%s", indents[ICTerminal]);
166 //------------------------------------------------------------------------
167 // printIndent: This is a static method which simply invokes the 'print'
168 // method on its 'indentStack' argument.
171 // indentStack - specifies the information for the indentation & arcs to be printed
174 // This method exists to localize the checking for the case where indentStack is null.
176 static void printIndent(IndentStack* indentStack)
178 if (indentStack == nullptr)
180 indentStack->print();
183 static const char * nodeNames[] =
185 #define GTNODE(en,sn,cm,ok) sn,
189 const char * GenTree::NodeName(genTreeOps op)
191 assert((unsigned)op < sizeof(nodeNames)/sizeof(nodeNames[0]));
193 return nodeNames[op];
196 static const char * opNames[] =
198 #define GTNODE(en,sn,cm,ok) #en,
202 const char * GenTree::OpName(genTreeOps op)
204 assert((unsigned)op < sizeof(opNames)/sizeof(opNames[0]));
211 /*****************************************************************************
213 * When 'SMALL_TREE_NODES' is enabled, we allocate tree nodes in 2 different
214 * sizes: 'GTF_DEBUG_NODE_SMALL' for most nodes and 'GTF_DEBUG_NODE_LARGE' for
215 * the few nodes (such as calls and statement list nodes) that have more fields
216 * and take up a lot more space.
221 /* GT_COUNT'th oper is overloaded as 'undefined oper', so allocate storage for GT_COUNT'th oper also */
223 unsigned char GenTree::s_gtNodeSizes[GT_COUNT+1];
226 void GenTree::InitNodeSize()
228 /* 'GT_LCL_VAR' often gets changed to 'GT_REG_VAR' */
230 assert(GenTree::s_gtNodeSizes[GT_LCL_VAR] >= GenTree::s_gtNodeSizes[GT_REG_VAR]);
232 /* Set all sizes to 'small' first */
234 for (unsigned op = 0; op <= GT_COUNT; op++)
236 GenTree::s_gtNodeSizes[op] = TREE_NODE_SZ_SMALL;
239 // Now set all of the appropriate entries to 'large'
241 // On ARM32, ARM64 and System V for struct returning
242 // there is code that does GT_ASG-tree.CopyObj call.
243 // CopyObj is a large node and the GT_ASG is small, which triggers an exception.
244 #if defined(FEATURE_HFA) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
245 GenTree::s_gtNodeSizes[GT_ASG ] = TREE_NODE_SZ_LARGE;
246 GenTree::s_gtNodeSizes[GT_RETURN ] = TREE_NODE_SZ_LARGE;
247 #endif // defined(FEATURE_HFA) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
249 GenTree::s_gtNodeSizes[GT_CALL ] = TREE_NODE_SZ_LARGE;
250 GenTree::s_gtNodeSizes[GT_CAST ] = TREE_NODE_SZ_LARGE;
251 GenTree::s_gtNodeSizes[GT_FTN_ADDR ] = TREE_NODE_SZ_LARGE;
252 GenTree::s_gtNodeSizes[GT_BOX ] = TREE_NODE_SZ_LARGE;
253 GenTree::s_gtNodeSizes[GT_INDEX ] = TREE_NODE_SZ_LARGE;
254 GenTree::s_gtNodeSizes[GT_ARR_BOUNDS_CHECK] = TREE_NODE_SZ_LARGE;
256 GenTree::s_gtNodeSizes[GT_SIMD_CHK ] = TREE_NODE_SZ_LARGE;
257 #endif // FEATURE_SIMD
258 GenTree::s_gtNodeSizes[GT_ARR_ELEM ] = TREE_NODE_SZ_LARGE;
259 GenTree::s_gtNodeSizes[GT_ARR_INDEX ] = TREE_NODE_SZ_LARGE;
260 GenTree::s_gtNodeSizes[GT_ARR_OFFSET ] = TREE_NODE_SZ_LARGE;
261 GenTree::s_gtNodeSizes[GT_RET_EXPR ] = TREE_NODE_SZ_LARGE;
262 GenTree::s_gtNodeSizes[GT_OBJ ] = TREE_NODE_SZ_LARGE;
263 GenTree::s_gtNodeSizes[GT_FIELD ] = TREE_NODE_SZ_LARGE;
264 GenTree::s_gtNodeSizes[GT_STMT ] = TREE_NODE_SZ_LARGE;
265 GenTree::s_gtNodeSizes[GT_CMPXCHG ] = TREE_NODE_SZ_LARGE;
266 GenTree::s_gtNodeSizes[GT_QMARK ] = TREE_NODE_SZ_LARGE;
267 GenTree::s_gtNodeSizes[GT_LEA ] = TREE_NODE_SZ_LARGE;
268 GenTree::s_gtNodeSizes[GT_COPYOBJ ] = TREE_NODE_SZ_LARGE;
269 GenTree::s_gtNodeSizes[GT_INTRINSIC ] = TREE_NODE_SZ_LARGE;
270 #if USE_HELPERS_FOR_INT_DIV
271 GenTree::s_gtNodeSizes[GT_DIV ] = TREE_NODE_SZ_LARGE;
272 GenTree::s_gtNodeSizes[GT_UDIV ] = TREE_NODE_SZ_LARGE;
273 GenTree::s_gtNodeSizes[GT_MOD ] = TREE_NODE_SZ_LARGE;
274 GenTree::s_gtNodeSizes[GT_UMOD ] = TREE_NODE_SZ_LARGE;
276 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
277 GenTree::s_gtNodeSizes[GT_PUTARG_STK ] = TREE_NODE_SZ_LARGE;
278 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
279 #if defined(FEATURE_HFA) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
280 // In importer for Hfa and register returned structs we rewrite GT_ASG to GT_COPYOBJ/GT_CPYBLK
281 // Make sure the sizes agree.
282 assert(GenTree::s_gtNodeSizes[GT_COPYOBJ] <= GenTree::s_gtNodeSizes[GT_ASG]);
283 assert(GenTree::s_gtNodeSizes[GT_COPYBLK] <= GenTree::s_gtNodeSizes[GT_ASG]);
284 #endif // !(defined(FEATURE_HFA) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING))
286 assert(GenTree::s_gtNodeSizes[GT_RETURN] == GenTree::s_gtNodeSizes[GT_ASG]);
288 // This list of assertions should come to contain all GenTree subtypes that are declared
290 assert(sizeof(GenTreeLclFld) <= GenTree::s_gtNodeSizes[GT_LCL_FLD]);
291 assert(sizeof(GenTreeLclVar) <= GenTree::s_gtNodeSizes[GT_LCL_VAR]);
293 static_assert_no_msg(sizeof(GenTree) <= TREE_NODE_SZ_SMALL);
294 static_assert_no_msg(sizeof(GenTreeUnOp) <= TREE_NODE_SZ_SMALL);
295 static_assert_no_msg(sizeof(GenTreeOp) <= TREE_NODE_SZ_SMALL);
296 static_assert_no_msg(sizeof(GenTreeVal) <= TREE_NODE_SZ_SMALL);
297 static_assert_no_msg(sizeof(GenTreeIntConCommon) <= TREE_NODE_SZ_SMALL);
298 static_assert_no_msg(sizeof(GenTreePhysReg) <= TREE_NODE_SZ_SMALL);
299 #ifndef LEGACY_BACKEND
300 static_assert_no_msg(sizeof(GenTreeJumpTable) <= TREE_NODE_SZ_SMALL);
301 #endif // !LEGACY_BACKEND
302 static_assert_no_msg(sizeof(GenTreeIntCon) <= TREE_NODE_SZ_SMALL);
303 static_assert_no_msg(sizeof(GenTreeLngCon) <= TREE_NODE_SZ_SMALL);
304 static_assert_no_msg(sizeof(GenTreeDblCon) <= TREE_NODE_SZ_SMALL);
305 static_assert_no_msg(sizeof(GenTreeStrCon) <= TREE_NODE_SZ_SMALL);
306 static_assert_no_msg(sizeof(GenTreeLclVarCommon) <= TREE_NODE_SZ_SMALL);
307 static_assert_no_msg(sizeof(GenTreeLclVar) <= TREE_NODE_SZ_SMALL);
308 static_assert_no_msg(sizeof(GenTreeLclFld) <= TREE_NODE_SZ_SMALL);
309 static_assert_no_msg(sizeof(GenTreeRegVar) <= TREE_NODE_SZ_SMALL);
310 static_assert_no_msg(sizeof(GenTreeCast) <= TREE_NODE_SZ_LARGE); // *** large node
311 static_assert_no_msg(sizeof(GenTreeBox) <= TREE_NODE_SZ_LARGE); // *** large node
312 static_assert_no_msg(sizeof(GenTreeField) <= TREE_NODE_SZ_LARGE); // *** large node
313 static_assert_no_msg(sizeof(GenTreeArgList) <= TREE_NODE_SZ_SMALL);
314 static_assert_no_msg(sizeof(GenTreeColon) <= TREE_NODE_SZ_SMALL);
315 static_assert_no_msg(sizeof(GenTreeCall) <= TREE_NODE_SZ_LARGE); // *** large node
316 static_assert_no_msg(sizeof(GenTreeCmpXchg) <= TREE_NODE_SZ_LARGE); // *** large node
317 static_assert_no_msg(sizeof(GenTreeFptrVal) <= TREE_NODE_SZ_LARGE); // *** large node
318 static_assert_no_msg(sizeof(GenTreeQmark) <= TREE_NODE_SZ_LARGE); // *** large node
319 static_assert_no_msg(sizeof(GenTreeIntrinsic) <= TREE_NODE_SZ_LARGE); // *** large node
320 static_assert_no_msg(sizeof(GenTreeIndex) <= TREE_NODE_SZ_LARGE); // *** large node
321 static_assert_no_msg(sizeof(GenTreeArrLen) <= TREE_NODE_SZ_LARGE); // *** large node
322 static_assert_no_msg(sizeof(GenTreeBoundsChk) <= TREE_NODE_SZ_LARGE); // *** large node
323 static_assert_no_msg(sizeof(GenTreeArrElem) <= TREE_NODE_SZ_LARGE); // *** large node
324 static_assert_no_msg(sizeof(GenTreeArrIndex) <= TREE_NODE_SZ_LARGE); // *** large node
325 static_assert_no_msg(sizeof(GenTreeArrOffs) <= TREE_NODE_SZ_LARGE); // *** large node
326 static_assert_no_msg(sizeof(GenTreeIndir) <= TREE_NODE_SZ_SMALL);
327 static_assert_no_msg(sizeof(GenTreeStoreInd) <= TREE_NODE_SZ_SMALL);
328 static_assert_no_msg(sizeof(GenTreeBlkOp) <= TREE_NODE_SZ_SMALL);
329 static_assert_no_msg(sizeof(GenTreeCpBlk) <= TREE_NODE_SZ_SMALL);
330 static_assert_no_msg(sizeof(GenTreeInitBlk) <= TREE_NODE_SZ_SMALL);
331 static_assert_no_msg(sizeof(GenTreeCpObj) <= TREE_NODE_SZ_LARGE); // *** large node
332 static_assert_no_msg(sizeof(GenTreeRetExpr) <= TREE_NODE_SZ_LARGE); // *** large node
333 static_assert_no_msg(sizeof(GenTreeStmt) <= TREE_NODE_SZ_LARGE); // *** large node
334 static_assert_no_msg(sizeof(GenTreeObj) <= TREE_NODE_SZ_LARGE); // *** large node
335 static_assert_no_msg(sizeof(GenTreeClsVar) <= TREE_NODE_SZ_SMALL);
336 static_assert_no_msg(sizeof(GenTreeArgPlace) <= TREE_NODE_SZ_SMALL);
337 static_assert_no_msg(sizeof(GenTreeLabel) <= TREE_NODE_SZ_SMALL);
338 static_assert_no_msg(sizeof(GenTreePhiArg) <= TREE_NODE_SZ_SMALL);
339 #ifndef FEATURE_UNIX_AMD64_STRUCT_PASSING
340 static_assert_no_msg(sizeof(GenTreePutArgStk) <= TREE_NODE_SZ_SMALL);
341 #else // FEATURE_UNIX_AMD64_STRUCT_PASSING
342 static_assert_no_msg(sizeof(GenTreePutArgStk) <= TREE_NODE_SZ_LARGE);
343 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
346 static_assert_no_msg(sizeof(GenTreeSIMD) <= TREE_NODE_SZ_SMALL);
347 #endif // FEATURE_SIMD
350 size_t GenTree::GetNodeSize() const
352 return GenTree::s_gtNodeSizes[gtOper];
356 bool GenTree::IsNodeProperlySized() const
360 if (gtDebugFlags & GTF_DEBUG_NODE_SMALL)
362 size = TREE_NODE_SZ_SMALL;
366 assert(gtDebugFlags & GTF_DEBUG_NODE_LARGE);
367 size = TREE_NODE_SZ_LARGE;
370 return GenTree::s_gtNodeSizes[gtOper] <= size;
374 #else // SMALL_TREE_NODES
377 bool GenTree::IsNodeProperlySized() const
383 #endif // SMALL_TREE_NODES
385 /*****************************************************************************/
387 // make sure these get instantiated, because it's not in a header file
388 // (emulating the c++ 'export' keyword here)
389 // VC appears to be somewhat unpredictable about whether they end up in the .obj file without this
390 template Compiler::fgWalkResult Compiler::fgWalkTreePostRec<true> (GenTreePtr *pTree, fgWalkData *fgWalkData);
391 template Compiler::fgWalkResult Compiler::fgWalkTreePostRec<false> (GenTreePtr *pTree, fgWalkData *fgWalkData);
392 template Compiler::fgWalkResult Compiler::fgWalkTreePreRec<true> (GenTreePtr *pTree, fgWalkData *fgWalkData);
393 template Compiler::fgWalkResult Compiler::fgWalkTreePreRec<false> (GenTreePtr *pTree, fgWalkData *fgWalkData);
394 template Compiler::fgWalkResult Compiler::fgWalkTreeRec<true,true> (GenTreePtr *pTree, fgWalkData *fgWalkData);
395 template Compiler::fgWalkResult Compiler::fgWalkTreeRec<false,false>(GenTreePtr *pTree, fgWalkData *fgWalkData);
396 template Compiler::fgWalkResult Compiler::fgWalkTreeRec<true,false> (GenTreePtr *pTree, fgWalkData *fgWalkData);
397 template Compiler::fgWalkResult Compiler::fgWalkTreeRec<false,true> (GenTreePtr *pTree, fgWalkData *fgWalkData);
399 //******************************************************************************
400 // fgWalkTreePreRec - Helper function for fgWalkTreePre.
401 // walk tree in pre order, executing callback on every node.
402 // Template parameter 'computeStack' specifies whether to maintain
403 // a stack of ancestor nodes which can be viewed in the callback.
405 template<bool computeStack>
407 Compiler::fgWalkResult Compiler::fgWalkTreePreRec(GenTreePtr *pTree, fgWalkData *fgWalkData)
409 fgWalkResult result = WALK_CONTINUE;
410 GenTreePtr currentParent = fgWalkData->parent;
417 GenTreePtr tree = *pTree;
419 assert(tree->gtOper != GT_STMT);
420 GenTreeArgList* args; // For call node arg lists.
423 fgWalkData->parentStack->Push(tree);
425 /* Visit this node */
427 // if we are not in the mode where we only do the callback for local var nodes,
428 // visit the node unconditionally. Otherwise we will visit it under leaf handling.
429 if (!fgWalkData->wtprLclsOnly)
431 assert(tree == *pTree);
432 result = fgWalkData->wtprVisitorFn(pTree, fgWalkData);
433 if (result != WALK_CONTINUE)
437 /* Figure out what kind of a node we have */
439 oper = tree->OperGet();
440 kind = tree->OperKind();
442 /* Is this a constant or leaf node? */
444 if (kind & (GTK_CONST|GTK_LEAF))
446 if (fgWalkData->wtprLclsOnly && (oper == GT_LCL_VAR || oper == GT_LCL_FLD))
447 result = fgWalkData->wtprVisitorFn(pTree, fgWalkData);
450 else if (fgWalkData->wtprLclsOnly && GenTree::OperIsLocalStore(oper))
452 result = fgWalkData->wtprVisitorFn(pTree, fgWalkData);
453 if (result != WALK_CONTINUE)
457 fgWalkData->parent = tree;
459 /* Is it a 'simple' unary/binary operator? */
461 if (kind & GTK_SMPOP)
463 if (tree->gtGetOp2())
465 if (tree->gtOp.gtOp1 != NULL)
467 result = fgWalkTreePreRec<computeStack>(&tree->gtOp.gtOp1, fgWalkData);
468 if (result == WALK_ABORT)
473 assert(tree->NullOp1Legal());
476 pTree = &tree->gtOp.gtOp2;
481 pTree = &tree->gtOp.gtOp1;
490 /* See what kind of a special operator we have here */
495 pTree = &tree->gtField.gtFldObj;
500 assert(tree->gtFlags & GTF_CALL);
502 /* Is this a call to unmanaged code ? */
503 if (fgWalkData->wtprLclsOnly && (tree->gtFlags & GTF_CALL_UNMANAGED))
505 result = fgWalkData->wtprVisitorFn(pTree, fgWalkData);
506 if (result == WALK_ABORT)
510 if (tree->gtCall.gtCallObjp)
512 result = fgWalkTreePreRec<computeStack>(&tree->gtCall.gtCallObjp, fgWalkData);
513 if (result == WALK_ABORT)
517 for (args = tree->gtCall.gtCallArgs; args; args = args->Rest())
519 result = fgWalkTreePreRec<computeStack>(args->pCurrent(), fgWalkData);
520 if (result == WALK_ABORT)
524 for (args = tree->gtCall.gtCallLateArgs; args; args = args->Rest())
526 result = fgWalkTreePreRec<computeStack>(args->pCurrent(), fgWalkData);
527 if (result == WALK_ABORT)
531 if (tree->gtCall.gtControlExpr)
533 result = fgWalkTreePreRec<computeStack>(&tree->gtCall.gtControlExpr, fgWalkData);
534 if (result == WALK_ABORT)
538 if (tree->gtCall.gtCallType == CT_INDIRECT)
540 if (tree->gtCall.gtCallCookie)
542 result = fgWalkTreePreRec<computeStack>(&tree->gtCall.gtCallCookie, fgWalkData);
543 if (result == WALK_ABORT)
546 pTree = &tree->gtCall.gtCallAddr;
555 result = fgWalkTreePreRec<computeStack>(&tree->gtArrElem.gtArrObj, fgWalkData);
556 if (result == WALK_ABORT)
560 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
562 result = fgWalkTreePreRec<computeStack>(&tree->gtArrElem.gtArrInds[dim], fgWalkData);
563 if (result == WALK_ABORT)
570 result = fgWalkTreePreRec<computeStack>(&tree->gtArrOffs.gtOffset, fgWalkData);
571 if (result == WALK_ABORT)
573 result = fgWalkTreePreRec<computeStack>(&tree->gtArrOffs.gtIndex, fgWalkData);
574 if (result == WALK_ABORT)
576 result = fgWalkTreePreRec<computeStack>(&tree->gtArrOffs.gtArrObj, fgWalkData);
577 if (result == WALK_ABORT)
583 result = fgWalkTreePreRec<computeStack>(&tree->gtCmpXchg.gtOpLocation, fgWalkData);
584 if (result == WALK_ABORT)
586 result = fgWalkTreePreRec<computeStack>(&tree->gtCmpXchg.gtOpValue, fgWalkData);
587 if (result == WALK_ABORT)
589 result = fgWalkTreePreRec<computeStack>(&tree->gtCmpXchg.gtOpComparand, fgWalkData);
590 if (result == WALK_ABORT)
595 case GT_ARR_BOUNDS_CHECK:
598 #endif // FEATURE_SIMD
599 result = fgWalkTreePreRec<computeStack>(&tree->gtBoundsChk.gtArrLen, fgWalkData);
600 if (result == WALK_ABORT)
602 result = fgWalkTreePreRec<computeStack>(&tree->gtBoundsChk.gtIndex, fgWalkData);
603 if (result == WALK_ABORT)
610 fgWalkData->compiler->gtDispTree(tree);
612 assert(!"unexpected operator");
615 while (pTree != NULL && *pTree != NULL);
618 fgWalkData->parentStack->Pop();
620 if (result != WALK_ABORT)
623 // Restore fgWalkData->parent
625 fgWalkData->parent = currentParent;
630 /*****************************************************************************
632 * Walk all basic blocks and call the given function pointer for all tree
633 * nodes contained therein.
636 void Compiler::fgWalkAllTreesPre(fgWalkPreFn * visitor,
637 void * pCallBackData)
641 for (block = fgFirstBB; block; block = block->bbNext)
645 for (tree = block->bbTreeList; tree; tree = tree->gtNext)
647 assert(tree->gtOper == GT_STMT);
649 fgWalkTreePre(&tree->gtStmt.gtStmtExpr, visitor, pCallBackData);
655 //******************************************************************************
656 // fgWalkTreePostRec - Helper function for fgWalkTreePost.
657 // Walk tree in post order, executing callback on every node
658 // template parameter 'computeStack' specifies whether to maintain
659 // a stack of ancestor nodes which can be viewed in the callback.
661 template<bool computeStack>
663 Compiler::fgWalkResult Compiler::fgWalkTreePostRec(GenTreePtr *pTree, fgWalkData *fgWalkData)
666 GenTreePtr currentParent = fgWalkData->parent;
671 GenTree *tree = *pTree;
673 assert(tree->gtOper != GT_STMT);
674 GenTreeArgList* args;
676 /* Figure out what kind of a node we have */
678 oper = tree->OperGet();
679 kind = tree->OperKind();
682 fgWalkData->parentStack->Push(tree);
684 /* Is this a constant or leaf node? */
686 if (kind & (GTK_CONST|GTK_LEAF))
689 /* Is it a 'simple' unary/binary operator? */
691 fgWalkData->parent = tree;
693 if (kind & GTK_SMPOP)
695 GenTree** op1Slot = &tree->gtOp.gtOp1;
698 if (tree->OperIsBinary())
700 if ((tree->gtFlags & GTF_REVERSE_OPS) == 0)
702 op2Slot = &tree->gtOp.gtOp2;
707 op1Slot = &tree->gtOp.gtOp2;
715 if (*op1Slot != nullptr)
717 result = fgWalkTreePostRec<computeStack>(op1Slot, fgWalkData);
718 if (result == WALK_ABORT)
722 if (op2Slot != nullptr && *op2Slot != nullptr)
724 result = fgWalkTreePostRec<computeStack>(op2Slot, fgWalkData);
725 if (result == WALK_ABORT)
732 /* See what kind of a special operator we have here */
737 if (tree->gtField.gtFldObj)
739 result = fgWalkTreePostRec<computeStack>(&tree->gtField.gtFldObj, fgWalkData);
740 if (result == WALK_ABORT)
748 assert(tree->gtFlags & GTF_CALL);
750 if (tree->gtCall.gtCallObjp)
752 result = fgWalkTreePostRec<computeStack>(&tree->gtCall.gtCallObjp, fgWalkData);
753 if (result == WALK_ABORT)
757 for (args = tree->gtCall.gtCallArgs; args; args = args->Rest())
759 result = fgWalkTreePostRec<computeStack>(args->pCurrent(), fgWalkData);
760 if (result == WALK_ABORT)
764 for (args = tree->gtCall.gtCallLateArgs; args; args = args->Rest())
766 result = fgWalkTreePostRec<computeStack>(args->pCurrent(), fgWalkData);
767 if (result == WALK_ABORT)
770 if (tree->gtCall.gtCallType == CT_INDIRECT)
772 if (tree->gtCall.gtCallCookie)
774 result = fgWalkTreePostRec<computeStack>(&tree->gtCall.gtCallCookie, fgWalkData);
775 if (result == WALK_ABORT)
778 result = fgWalkTreePostRec<computeStack>(&tree->gtCall.gtCallAddr, fgWalkData);
779 if (result == WALK_ABORT)
783 if (tree->gtCall.gtControlExpr != nullptr)
785 result = fgWalkTreePostRec<computeStack>(&tree->gtCall.gtControlExpr, fgWalkData);
786 if (result == WALK_ABORT)
793 result = fgWalkTreePostRec<computeStack>(&tree->gtArrElem.gtArrObj, fgWalkData);
794 if (result == WALK_ABORT)
798 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
800 result = fgWalkTreePostRec<computeStack>(&tree->gtArrElem.gtArrInds[dim], fgWalkData);
801 if (result == WALK_ABORT)
807 result = fgWalkTreePostRec<computeStack>(&tree->gtArrOffs.gtOffset, fgWalkData);
808 if (result == WALK_ABORT)
810 result = fgWalkTreePostRec<computeStack>(&tree->gtArrOffs.gtIndex, fgWalkData);
811 if (result == WALK_ABORT)
813 result = fgWalkTreePostRec<computeStack>(&tree->gtArrOffs.gtArrObj, fgWalkData);
814 if (result == WALK_ABORT)
819 result = fgWalkTreePostRec<computeStack>(&tree->gtCmpXchg.gtOpComparand, fgWalkData);
820 if (result == WALK_ABORT)
822 result = fgWalkTreePostRec<computeStack>(&tree->gtCmpXchg.gtOpValue, fgWalkData);
823 if (result == WALK_ABORT)
825 result = fgWalkTreePostRec<computeStack>(&tree->gtCmpXchg.gtOpLocation, fgWalkData);
826 if (result == WALK_ABORT)
830 case GT_ARR_BOUNDS_CHECK:
833 #endif // FEATURE_SIMD
834 result = fgWalkTreePostRec<computeStack>(&tree->gtBoundsChk.gtArrLen, fgWalkData);
835 if (result == WALK_ABORT)
837 result = fgWalkTreePostRec<computeStack>(&tree->gtBoundsChk.gtIndex, fgWalkData);
838 if (result == WALK_ABORT)
844 fgWalkData->compiler->gtDispTree(tree);
846 assert(!"unexpected operator");
851 fgWalkData->parent = currentParent;
853 /* Finally, visit the current node */
854 result = fgWalkData->wtpoVisitorFn(pTree, fgWalkData);
857 fgWalkData->parentStack->Pop();
862 // ****************************************************************************
863 // walk tree doing callbacks in both pre- and post- order (both optional)
865 template<bool doPreOrder, bool doPostOrder>
867 Compiler::fgWalkResult
868 Compiler::fgWalkTreeRec(GenTreePtr *pTree, fgWalkData *fgWalkData)
870 fgWalkResult result = WALK_CONTINUE;
875 GenTree *tree = *pTree;
877 assert(tree->gtOper != GT_STMT);
878 GenTreeArgList* args;
880 /* Figure out what kind of a node we have */
882 oper = tree->OperGet();
883 kind = tree->OperKind();
885 fgWalkData->parentStack->Push(tree);
889 result = fgWalkData->wtprVisitorFn(pTree, fgWalkData);
890 if (result == WALK_ABORT)
895 oper = tree->OperGet();
896 kind = tree->OperKind();
900 // If we're skipping subtrees, we're done.
901 if (result == WALK_SKIP_SUBTREES)
904 /* Is this a constant or leaf node? */
906 if ((kind & (GTK_CONST|GTK_LEAF)) != 0)
909 /* Is it a 'simple' unary/binary operator? */
911 if (kind & GTK_SMPOP)
913 if (tree->gtOp.gtOp1)
915 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtOp.gtOp1, fgWalkData);
916 if (result == WALK_ABORT)
920 if (tree->gtGetOp2())
922 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtOp.gtOp2, fgWalkData);
923 if (result == WALK_ABORT)
930 /* See what kind of a special operator we have here */
935 if (tree->gtField.gtFldObj)
937 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtField.gtFldObj, fgWalkData);
938 if (result == WALK_ABORT)
946 assert(tree->gtFlags & GTF_CALL);
948 if (tree->gtCall.gtCallObjp)
950 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtCall.gtCallObjp, fgWalkData);
951 if (result == WALK_ABORT)
955 for (args = tree->gtCall.gtCallArgs; args; args = args->Rest())
957 result = fgWalkTreeRec<doPreOrder, doPostOrder>(args->pCurrent(), fgWalkData);
958 if (result == WALK_ABORT)
962 for (args = tree->gtCall.gtCallLateArgs; args; args = args->Rest())
964 result = fgWalkTreeRec<doPreOrder, doPostOrder>(args->pCurrent(), fgWalkData);
965 if (result == WALK_ABORT)
968 if (tree->gtCall.gtCallType == CT_INDIRECT)
970 if (tree->gtCall.gtCallCookie)
972 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtCall.gtCallCookie, fgWalkData);
973 if (result == WALK_ABORT)
976 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtCall.gtCallAddr, fgWalkData);
977 if (result == WALK_ABORT)
981 if (tree->gtCall.gtControlExpr)
983 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtCall.gtControlExpr, fgWalkData);
984 if (result == WALK_ABORT)
992 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtArrElem.gtArrObj, fgWalkData);
993 if (result == WALK_ABORT)
997 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
999 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtArrElem.gtArrInds[dim], fgWalkData);
1000 if (result == WALK_ABORT)
1006 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtArrOffs.gtOffset, fgWalkData);
1007 if (result == WALK_ABORT)
1009 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtArrOffs.gtIndex, fgWalkData);
1010 if (result == WALK_ABORT)
1012 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtArrOffs.gtArrObj, fgWalkData);
1013 if (result == WALK_ABORT)
1018 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtCmpXchg.gtOpComparand, fgWalkData);
1019 if (result == WALK_ABORT)
1021 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtCmpXchg.gtOpValue, fgWalkData);
1022 if (result == WALK_ABORT)
1024 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtCmpXchg.gtOpLocation, fgWalkData);
1025 if (result == WALK_ABORT)
1029 case GT_ARR_BOUNDS_CHECK:
1032 #endif // FEATURE_SIMD
1033 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtBoundsChk.gtArrLen, fgWalkData);
1034 if (result == WALK_ABORT)
1036 result = fgWalkTreeRec<doPreOrder, doPostOrder>(&tree->gtBoundsChk.gtIndex, fgWalkData);
1037 if (result == WALK_ABORT)
1043 fgWalkData->compiler->gtDispTree(tree);
1045 assert(!"unexpected operator");
1050 /* Finally, visit the current node */
1053 result = fgWalkData->wtpoVisitorFn(pTree, fgWalkData);
1056 fgWalkData->parentStack->Pop();
1061 /*****************************************************************************
1063 * Call the given function pointer for all nodes in the tree. The 'visitor'
1064 * fn should return one of the following values:
1066 * WALK_ABORT stop walking and return immediately
1067 * WALK_CONTINUE continue walking
1068 * WALK_SKIP_SUBTREES don't walk any subtrees of the node just visited
1071 Compiler::fgWalkResult Compiler::fgWalkTree(GenTreePtr * pTree,
1072 fgWalkPreFn * preVisitor,
1073 fgWalkPreFn * postVisitor,
1074 void * callBackData)
1077 fgWalkData walkData;
1079 walkData.compiler = this;
1080 walkData.wtprVisitorFn = preVisitor;
1081 walkData.wtpoVisitorFn = postVisitor;
1082 walkData.pCallbackData = callBackData;
1083 walkData.parent = NULL;
1084 walkData.wtprLclsOnly = false;
1086 walkData.printModified = false;
1088 ArrayStack<GenTree *> parentStack(this);
1089 walkData.parentStack = &parentStack;
1091 fgWalkResult result;
1093 assert (preVisitor || postVisitor);
1095 if (preVisitor && postVisitor)
1096 result = fgWalkTreeRec<true,true>(pTree, &walkData);
1097 else if (preVisitor)
1098 result = fgWalkTreeRec<true,false>(pTree, &walkData);
1100 result = fgWalkTreeRec<false,true>(pTree, &walkData);
1104 if (verbose && walkData.printModified)
1113 // ------------------------------------------------------------------------------------------
1114 // gtClearReg: Sets the register to the "no register assignment" value, depending upon
1115 // the type of the node, and whether it fits any of the special cases for register pairs
1116 // or multi-reg call nodes.
1119 // compiler - compiler instance
1124 GenTree::gtClearReg(Compiler* compiler)
1126 #if CPU_LONG_USES_REGPAIR
1127 if (isRegPairType(TypeGet()) ||
1128 // (IsLocal() && isRegPairType(compiler->lvaTable[gtLclVarCommon.gtLclNum].TypeGet())) ||
1129 (OperGet() == GT_MUL && (gtFlags & GTF_MUL_64RSLT)))
1131 gtRegPair = REG_PAIR_NONE;
1134 #endif // CPU_LONG_USES_REGPAIR
1139 // Also clear multi-reg state if this is a call node
1142 this->AsCall()->ClearOtherRegs();
1144 else if (IsCopyOrReload())
1146 this->AsCopyOrReload()->ClearOtherRegs();
1150 //-----------------------------------------------------------
1151 // CopyReg: Copy the _gtRegNum/_gtRegPair/gtRegTag fields.
1154 // from - GenTree node from which to copy
1159 GenTree::CopyReg(GenTreePtr from)
1161 // To do the copy, use _gtRegPair, which must be bigger than _gtRegNum. Note that the values
1162 // might be undefined (so gtRegTag == GT_REGTAG_NONE).
1163 _gtRegPair = from->_gtRegPair;
1164 C_ASSERT(sizeof(_gtRegPair) >= sizeof(_gtRegNum));
1165 INDEBUG(gtRegTag = from->gtRegTag;)
1167 // Also copy multi-reg state if this is a call node
1170 assert(from->IsCall());
1171 this->AsCall()->CopyOtherRegs(from->AsCall());
1173 else if (IsCopyOrReload())
1175 this->AsCopyOrReload()->CopyOtherRegs(from->AsCopyOrReload());
1179 //------------------------------------------------------------------
1180 // gtHasReg: Whether node beeen assigned a register by LSRA
1186 // Returns true if the node was assigned a register.
1188 // In case of multi-reg call nodes, it is considered
1189 // having a reg if regs are allocated for all its
1192 // In case of GT_COPY or GT_RELOAD of a multi-reg call,
1193 // GT_COPY/GT_RELOAD is considered having a reg if it
1194 // has a reg assigned to any of its positions.
1197 // In order for this to work properly, gtClearReg must be called
1198 // prior to setting the register value.
1200 bool GenTree::gtHasReg() const
1204 #if CPU_LONG_USES_REGPAIR
1205 if (isRegPairType(TypeGet()))
1207 assert(_gtRegNum != REG_NA);
1208 INDEBUG(assert(gtRegTag == GT_REGTAG_REGPAIR));
1209 hasReg = (gtRegPair != REG_PAIR_NONE);
1214 assert(_gtRegNum != REG_PAIR_NONE);
1215 INDEBUG(assert(gtRegTag == GT_REGTAG_REG));
1217 if (IsMultiRegCall())
1219 // Has to cast away const-ness because GetReturnTypeDesc() is a non-const method
1220 GenTree* tree = const_cast<GenTree*>(this);
1221 GenTreeCall* call = tree->AsCall();
1222 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
1225 // A Multi-reg call node is said to have regs, if it has
1226 // reg assigned to each of its result registers.
1227 for (unsigned i = 0; i < regCount; ++i)
1229 hasReg = (call->GetRegNumByIdx(i) != REG_NA);
1236 else if (IsCopyOrReloadOfMultiRegCall())
1238 GenTree* tree = const_cast<GenTree*>(this);
1239 GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
1240 GenTreeCall* call = copyOrReload->gtGetOp1()->AsCall();
1241 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
1244 // A Multi-reg copy or reload node is said to have regs,
1245 // if it has valid regs in any of the positions.
1246 for (unsigned i = 0; i < regCount; ++i)
1248 hasReg = (copyOrReload->GetRegNumByIdx(i) != REG_NA);
1257 hasReg = (gtRegNum != REG_NA);
1264 //---------------------------------------------------------------
1265 // gtGetRegMask: Get the reg mask of the node.
1271 // Reg Mask of GenTree node.
1274 GenTree::gtGetRegMask() const
1276 regMaskTP resultMask;
1278 #if CPU_LONG_USES_REGPAIR
1279 if (isRegPairType(TypeGet()))
1281 resultMask = genRegPairMask(gtRegPair);
1286 if (IsMultiRegCall())
1288 // temporarily cast away const-ness as AsCall() method is not declared const
1289 resultMask = genRegMask(gtRegNum);
1290 GenTree* temp = const_cast<GenTree*>(this);
1291 resultMask |= temp->AsCall()->GetOtherRegMask();
1293 else if (IsCopyOrReloadOfMultiRegCall())
1295 // A multi-reg copy or reload, will have valid regs for only those
1296 // positions that need to be copied or reloaded. Hence we need
1297 // to consider only those registers for computing reg mask.
1299 GenTree* tree = const_cast<GenTree*>(this);
1300 GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
1301 GenTreeCall* call = copyOrReload->gtGetOp1()->AsCall();
1302 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
1304 resultMask = RBM_NONE;
1305 for (unsigned i = 0; i < regCount; ++i)
1307 regNumber reg = copyOrReload->GetRegNumByIdx(i);
1310 resultMask |= genRegMask(reg);
1316 resultMask = genRegMask(gtRegNum);
1323 //---------------------------------------------------------------
1324 // GetOtherRegMask: Get the reg mask of gtOtherRegs of call node
1330 // Reg mask of gtOtherRegs of call node.
1333 GenTreeCall::GetOtherRegMask() const
1335 regMaskTP resultMask = RBM_NONE;
1337 #if FEATURE_MULTIREG_RET
1338 for (unsigned i = 0; i < MAX_RET_REG_COUNT - 1; ++i)
1340 if (gtOtherRegs[i] != REG_NA)
1342 resultMask |= genRegMask(gtOtherRegs[i]);
1352 #ifndef LEGACY_BACKEND
1354 //-------------------------------------------------------------------------
1355 // HasNonStandardAddedArgs: Return true if the method has non-standard args added to the call
1356 // argument list during argument morphing (fgMorphArgs), e.g., passed in R10 or R11 on AMD64.
1357 // See also GetNonStandardAddedArgCount().
1360 // compiler - the compiler instance
1363 // true if there are any such args, false otherwise.
1365 bool GenTreeCall::HasNonStandardAddedArgs(Compiler* compiler) const
1367 return GetNonStandardAddedArgCount(compiler) != 0;
1371 //-------------------------------------------------------------------------
1372 // GetNonStandardAddedArgCount: Get the count of non-standard arguments that have been added
1373 // during call argument morphing (fgMorphArgs). Do not count non-standard args that are already
1374 // counted in the argument list prior to morphing.
1376 // This function is used to help map the caller and callee arguments during tail call setup.
1379 // compiler - the compiler instance
1382 // The count of args, as described.
1385 // It would be more general to have fgMorphArgs set a bit on the call node when such
1386 // args are added to a call, and a bit on each such arg, and then have this code loop
1387 // over the call args when the special call bit is set, counting the args with the special
1388 // arg bit. This seems pretty heavyweight, though. Instead, this logic needs to be kept
1389 // in sync with fgMorphArgs.
1391 int GenTreeCall::GetNonStandardAddedArgCount(Compiler* compiler) const
1393 if (IsUnmanaged() && !compiler->opts.ShouldUsePInvokeHelpers())
1395 // R11 = PInvoke cookie param
1398 else if (gtCallType == CT_INDIRECT)
1400 if (IsVirtualStub())
1402 // R11 = Virtual stub param
1405 else if (gtCallCookie != nullptr)
1407 // R10 = PInvoke target param
1408 // R11 = PInvoke cookie param
1415 #endif // !LEGACY_BACKEND
1417 //-------------------------------------------------------------------------
1418 // TreatAsHasRetBufArg:
1421 // compiler, the compiler instance so that we can call eeGetHelperNum
1424 // Returns true if we treat the call as if it has a retBuf argument
1425 // This method may actually have a retBuf argument
1426 // or it could be a JIT helper that we are still transforming during
1427 // the importer phase.
1430 // On ARM64 marking the method with the GTF_CALL_M_RETBUFFARG flag
1431 // will make HasRetBufArg() return true, but will also force the
1432 // use of register x8 to pass the RetBuf argument.
1434 // These two Jit Helpers that we handle here by returning true
1435 // aren't actually defined to return a struct, so they don't expect
1436 // their RetBuf to be passed in x8, instead they expect it in x0.
1438 bool GenTreeCall::TreatAsHasRetBufArg(Compiler* compiler) const
1446 // If we see a Jit helper call that returns a TYP_STRUCT we will
1447 // transform it as if it has a Return Buffer Argument
1449 if (IsHelperCall() && (gtReturnType == TYP_STRUCT))
1451 // There are two possible helper calls that use this path:
1452 // CORINFO_HELP_GETFIELDSTRUCT and CORINFO_HELP_UNBOX_NULLABLE
1454 CorInfoHelpFunc helpFunc = compiler->eeGetHelperNum(gtCallMethHnd);
1456 if (helpFunc == CORINFO_HELP_GETFIELDSTRUCT)
1460 else if (helpFunc == CORINFO_HELP_UNBOX_NULLABLE)
1466 assert(!"Unexpected JIT helper in TreatAsHasRetBufArg");
1474 //-------------------------------------------------------------------------
1475 // IsHelperCall: Determine if this GT_CALL node is a specific helper call.
1478 // compiler - the compiler instance so that we can call eeFindHelper
1481 // Returns true if this GT_CALL node is a call to the specified helper.
1483 bool GenTreeCall::IsHelperCall(Compiler* compiler, unsigned helper) const
1485 return IsHelperCall(compiler->eeFindHelper(helper));
1489 /*****************************************************************************
1491 * Returns non-zero if the two trees are identical.
1494 bool GenTree::Compare(GenTreePtr op1, GenTreePtr op2, bool swapOK)
1499 // printf("tree1:\n"); gtDispTree(op1);
1500 // printf("tree2:\n"); gtDispTree(op2);
1504 if (op1 == NULL) return (op2 == NULL);
1505 if (op2 == NULL) return false;
1506 if (op1 == op2) return true;
1508 assert(op1->gtOper != GT_STMT);
1509 assert(op2->gtOper != GT_STMT);
1511 oper = op1->OperGet();
1513 /* The operators must be equal */
1515 if (oper != op2->gtOper)
1518 /* The types must be equal */
1520 if (op1->gtType != op2->gtType)
1523 /* Overflow must be equal */
1524 if (op1->gtOverflowEx() != op2->gtOverflowEx())
1530 /* Sensible flags must be equal */
1531 if ( (op1->gtFlags & (GTF_UNSIGNED )) !=
1532 (op2->gtFlags & (GTF_UNSIGNED )) )
1538 /* Figure out what kind of nodes we're comparing */
1540 kind = op1->OperKind();
1542 /* Is this a constant node? */
1544 if (kind & GTK_CONST)
1549 if (op1->gtIntCon.gtIconVal == op2->gtIntCon.gtIconVal)
1553 // TODO-CQ: Enable this in the future
1555 if (op1->gtLngCon.gtLconVal == op2->gtLngCon.gtLconVal)
1560 if (op1->gtDblCon.gtDconVal == op2->gtDblCon.gtDconVal)
1571 /* Is this a leaf node? */
1573 if (kind & GTK_LEAF)
1578 if (op1->gtLclVarCommon.gtLclNum != op2->gtLclVarCommon.gtLclNum)
1584 if (op1->gtLclFld.gtLclNum != op2->gtLclFld.gtLclNum ||
1585 op1->gtLclFld.gtLclOffs != op2->gtLclFld.gtLclOffs)
1591 if (op1->gtClsVar.gtClsVarHnd != op2->gtClsVar.gtClsVarHnd)
1600 if ((op1->gtType == TYP_STRUCT) &&
1601 (op1->gtArgPlace.gtArgPlaceClsHnd != op2->gtArgPlace.gtArgPlaceClsHnd))
1614 /* Is it a 'simple' unary/binary operator? */
1616 if (kind & GTK_UNOP)
1620 // ExOp operators extend unary operator with extra, non-GenTreePtr members. In many cases,
1621 // these should be included in the comparison.
1625 if (op1->gtArrLen.ArrLenOffset() != op2->gtArrLen.ArrLenOffset()) return false;
1628 if (op1->gtCast.gtCastType != op2->gtCast.gtCastType) return false;
1631 if (op1->AsObj()->gtClass != op2->AsObj()->gtClass) return false;
1634 // For the ones below no extra argument matters for comparison.
1639 assert(!"unexpected unary ExOp operator");
1642 return Compare(op1->gtOp.gtOp1, op2->gtOp.gtOp1);
1645 if (kind & GTK_BINOP)
1649 // ExOp operators extend unary operator with extra, non-GenTreePtr members. In many cases,
1650 // these should be included in the hash code.
1654 if (op1->gtIntrinsic.gtIntrinsicId != op2->gtIntrinsic.gtIntrinsicId) return false;
1657 if (op1->gtAddrMode.gtScale != op2->gtAddrMode.gtScale) return false;
1658 if (op1->gtAddrMode.gtOffset != op2->gtAddrMode.gtOffset) return false;
1661 if (op1->gtIndex.gtIndElemSize != op2->gtIndex.gtIndElemSize) return false;
1664 // For the ones below no extra argument matters for comparison.
1669 assert(!"unexpected binary ExOp operator");
1673 if (op1->gtOp.gtOp2)
1675 if (!Compare(op1->gtOp.gtOp1, op2->gtOp.gtOp1, swapOK))
1677 if (swapOK && OperIsCommutative(oper) &&
1678 ((op1->gtOp.gtOp1->gtFlags | op1->gtOp.gtOp2->gtFlags | op2->gtOp.gtOp1->gtFlags | op2->gtOp.gtOp2->gtFlags) & GTF_ALL_EFFECT) == 0)
1680 if (Compare(op1->gtOp.gtOp1, op2->gtOp.gtOp2, swapOK))
1682 op1 = op1->gtOp.gtOp2;
1683 op2 = op2->gtOp.gtOp1;
1691 op1 = op1->gtOp.gtOp2;
1692 op2 = op2->gtOp.gtOp2;
1699 op1 = op1->gtOp.gtOp1;
1700 op2 = op2->gtOp.gtOp1;
1702 if (!op1) return (op2 == 0);
1703 if (!op2) return false;
1709 /* See what kind of a special operator we have here */
1714 if (op1->gtField.gtFldHnd != op2->gtField.gtFldHnd)
1717 op1 = op1->gtField.gtFldObj;
1718 op2 = op2->gtField.gtFldObj;
1730 if (op1->gtCall.gtCallType != op2->gtCall.gtCallType)
1733 if (op1->gtCall.gtCallType != CT_INDIRECT)
1735 if (op1->gtCall.gtCallMethHnd != op2->gtCall.gtCallMethHnd)
1738 #ifdef FEATURE_READYTORUN_COMPILER
1739 if (op1->gtCall.gtEntryPoint.addr != op2->gtCall.gtEntryPoint.addr)
1745 if (!Compare(op1->gtCall.gtCallAddr, op2->gtCall.gtCallAddr))
1749 if (Compare(op1->gtCall.gtCallLateArgs, op2->gtCall.gtCallLateArgs) &&
1750 Compare(op1->gtCall.gtCallArgs, op2->gtCall.gtCallArgs) &&
1751 Compare(op1->gtCall.gtControlExpr, op2->gtCall.gtControlExpr) &&
1752 Compare(op1->gtCall.gtCallObjp, op2->gtCall.gtCallObjp))
1758 if (op1->gtArrElem.gtArrRank != op2->gtArrElem.gtArrRank)
1761 // NOTE: gtArrElemSize may need to be handled
1764 for (dim = 0; dim < op1->gtArrElem.gtArrRank; dim++)
1766 if (!Compare(op1->gtArrElem.gtArrInds[dim], op2->gtArrElem.gtArrInds[dim]))
1770 op1 = op1->gtArrElem.gtArrObj;
1771 op2 = op2->gtArrElem.gtArrObj;
1775 if (op1->gtArrOffs.gtCurrDim != op2->gtArrOffs.gtCurrDim ||
1776 op1->gtArrOffs.gtArrRank != op2->gtArrOffs.gtArrRank)
1780 return (Compare(op1->gtArrOffs.gtOffset, op2->gtArrOffs.gtOffset) &&
1781 Compare(op1->gtArrOffs.gtIndex, op2->gtArrOffs.gtIndex) &&
1782 Compare(op1->gtArrOffs.gtArrObj, op2->gtArrOffs.gtArrObj));
1785 return Compare(op1->gtCmpXchg.gtOpLocation, op2->gtCmpXchg.gtOpLocation)
1786 && Compare(op1->gtCmpXchg.gtOpValue, op2->gtCmpXchg.gtOpValue)
1787 && Compare(op1->gtCmpXchg.gtOpComparand, op2->gtCmpXchg.gtOpComparand);
1789 case GT_ARR_BOUNDS_CHECK:
1792 #endif // FEATURE_SIMD
1793 return Compare(op1->gtBoundsChk.gtArrLen, op2->gtBoundsChk.gtArrLen)
1794 && Compare(op1->gtBoundsChk.gtIndex, op2->gtBoundsChk.gtIndex)
1795 && (op1->gtBoundsChk.gtThrowKind == op2->gtBoundsChk.gtThrowKind);
1798 assert(!"unexpected operator");
1804 /*****************************************************************************
1806 * Returns non-zero if the given tree contains a use of a local #lclNum.
1809 bool Compiler::gtHasRef(GenTreePtr tree, ssize_t lclNum, bool defOnly)
1818 oper = tree->OperGet();
1819 kind = tree->OperKind();
1821 assert(oper != GT_STMT);
1823 /* Is this a constant node? */
1825 if (kind & GTK_CONST)
1828 /* Is this a leaf node? */
1830 if (kind & GTK_LEAF)
1832 if (oper == GT_LCL_VAR)
1834 if (tree->gtLclVarCommon.gtLclNum == (unsigned)lclNum)
1840 else if (oper == GT_RET_EXPR)
1842 return gtHasRef(tree->gtRetExpr.gtInlineCandidate, lclNum, defOnly);
1848 /* Is it a 'simple' unary/binary operator? */
1850 if (kind & GTK_SMPOP)
1852 if (tree->gtGetOp2())
1854 if (gtHasRef(tree->gtOp.gtOp1, lclNum, defOnly))
1857 tree = tree->gtOp.gtOp2;
1862 tree = tree->gtOp.gtOp1;
1867 if (kind & GTK_ASGOP)
1869 // 'tree' is the gtOp1 of an assignment node. So we can handle
1870 // the case where defOnly is either true or false.
1872 if (tree->gtOper == GT_LCL_VAR &&
1873 tree->gtLclVarCommon.gtLclNum == (unsigned)lclNum)
1877 else if (tree->gtOper == GT_FIELD &&
1878 lclNum == (ssize_t)tree->gtField.gtFldHnd)
1888 /* See what kind of a special operator we have here */
1893 if (lclNum == (ssize_t)tree->gtField.gtFldHnd)
1899 tree = tree->gtField.gtFldObj;
1906 if (tree->gtCall.gtCallObjp)
1907 if (gtHasRef(tree->gtCall.gtCallObjp, lclNum, defOnly))
1910 if (tree->gtCall.gtCallArgs)
1911 if (gtHasRef(tree->gtCall.gtCallArgs, lclNum, defOnly))
1914 if (tree->gtCall.gtCallLateArgs)
1915 if (gtHasRef(tree->gtCall.gtCallLateArgs, lclNum, defOnly))
1918 if (tree->gtCall.gtCallLateArgs)
1919 if (gtHasRef(tree->gtCall.gtControlExpr, lclNum, defOnly))
1922 if (tree->gtCall.gtCallType == CT_INDIRECT)
1924 // pinvoke-calli cookie is a constant, or constant indirection
1925 assert(tree->gtCall.gtCallCookie == NULL ||
1926 tree->gtCall.gtCallCookie->gtOper == GT_CNS_INT ||
1927 tree->gtCall.gtCallCookie->gtOper == GT_IND);
1929 tree = tree->gtCall.gtCallAddr;
1940 if (gtHasRef(tree->gtArrElem.gtArrObj, lclNum, defOnly))
1944 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
1946 if (gtHasRef(tree->gtArrElem.gtArrInds[dim], lclNum, defOnly))
1953 if (gtHasRef(tree->gtArrOffs.gtOffset, lclNum, defOnly) ||
1954 gtHasRef(tree->gtArrOffs.gtIndex, lclNum, defOnly) ||
1955 gtHasRef(tree->gtArrOffs.gtArrObj, lclNum, defOnly))
1962 if (gtHasRef(tree->gtCmpXchg.gtOpLocation, lclNum, defOnly))
1964 if (gtHasRef(tree->gtCmpXchg.gtOpValue, lclNum, defOnly))
1966 if (gtHasRef(tree->gtCmpXchg.gtOpComparand, lclNum, defOnly))
1970 case GT_ARR_BOUNDS_CHECK:
1973 #endif // FEATURE_SIMD
1974 if (gtHasRef(tree->gtBoundsChk.gtArrLen, lclNum, defOnly))
1976 if (gtHasRef(tree->gtBoundsChk.gtIndex, lclNum, defOnly))
1984 assert(!"unexpected operator");
1993 bool hasAddrTakenLcl;
1997 Compiler::fgWalkResult Compiler::gtHasLocalsWithAddrOpCB(GenTreePtr *pTree,
2000 GenTreePtr tree = *pTree;
2001 Compiler * comp = data->compiler;
2003 if (tree->gtOper == GT_LCL_VAR)
2005 unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
2006 LclVarDsc * varDsc = &comp->lvaTable[lclNum];
2008 if (varDsc->lvHasLdAddrOp || varDsc->lvAddrExposed)
2010 ((AddrTakenDsc *)data->pCallbackData)->hasAddrTakenLcl = true;
2015 return WALK_CONTINUE;
2018 /*****************************************************************************
2020 * Return true if this tree contains locals with lvHasLdAddrOp or lvAddrExposed
2024 bool Compiler::gtHasLocalsWithAddrOp(GenTreePtr tree)
2029 desc.hasAddrTakenLcl = false;
2031 fgWalkTreePre(&tree,
2032 gtHasLocalsWithAddrOpCB,
2035 return desc.hasAddrTakenLcl;
2038 /*****************************************************************************
2040 * Helper used to compute hash values for trees.
2044 unsigned genTreeHashAdd(unsigned old, unsigned add)
2046 return (old + old/2) ^ add;
2050 unsigned genTreeHashAdd(unsigned old, void * add)
2052 return genTreeHashAdd(old, (unsigned) (size_t)add);
2056 unsigned genTreeHashAdd(unsigned old, unsigned add1,
2059 return (old + old/2) ^ add1 ^ add2;
2062 /*****************************************************************************
2064 * Given an arbitrary expression tree, compute a hash value for it.
2067 unsigned Compiler::gtHashValue(GenTree * tree)
2078 assert(tree->gtOper != GT_STMT);
2080 /* Figure out what kind of a node we have */
2082 oper = tree->OperGet();
2083 kind = tree->OperKind();
2085 /* Include the operator value in the hash */
2087 hash = genTreeHashAdd(hash, oper);
2089 /* Is this a constant or leaf node? */
2091 if (kind & (GTK_CONST|GTK_LEAF))
2097 case GT_LCL_VAR: add = tree->gtLclVar.gtLclNum; break;
2098 case GT_LCL_FLD: hash = genTreeHashAdd(hash, tree->gtLclFld.gtLclNum);
2099 add = tree->gtLclFld.gtLclOffs; break;
2101 case GT_CNS_INT: add = (int)tree->gtIntCon.gtIconVal; break;
2102 case GT_CNS_LNG: add = (int)tree->gtLngCon.gtLconVal; break;
2103 case GT_CNS_DBL: add = (int)tree->gtDblCon.gtDconVal; break;
2104 case GT_CNS_STR: add = (int)tree->gtStrCon.gtSconCPX; break;
2106 case GT_JMP: add = tree->gtVal.gtVal1; break;
2108 default: add = 0; break;
2111 //narrowing cast, but for hashing.
2112 hash = genTreeHashAdd(hash, (unsigned)add);
2116 /* Is it a 'simple' unary/binary operator? */
2120 if (kind & GTK_UNOP)
2122 op1 = tree->gtOp.gtOp1;
2123 /* Special case: no sub-operand at all */
2125 if (GenTree::IsExOp(kind))
2127 // ExOp operators extend operators with extra, non-GenTreePtr members. In many cases,
2128 // these should be included in the hash code.
2132 hash += tree->gtArrLen.ArrLenOffset();
2135 hash ^= tree->gtCast.gtCastType;
2138 hash ^= static_cast<unsigned>(reinterpret_cast<uintptr_t>(tree->gtObj.gtClass));
2141 hash += tree->gtIndex.gtIndElemSize;
2145 // For the ones below no extra argument matters for comparison.
2150 assert(!"unexpected unary ExOp operator");
2161 if (kind & GTK_BINOP)
2163 if (GenTree::IsExOp(kind))
2165 // ExOp operators extend operators with extra, non-GenTreePtr members. In many cases,
2166 // these should be included in the hash code.
2170 hash += tree->gtIntrinsic.gtIntrinsicId;
2173 hash += (tree->gtAddrMode.gtOffset << 3) + tree->gtAddrMode.gtScale;
2176 // For the ones below no extra argument matters for comparison.
2184 hash += tree->gtSIMD.gtSIMDIntrinsicID;
2185 hash += tree->gtSIMD.gtSIMDBaseType;
2187 #endif // FEATURE_SIMD
2190 assert(!"unexpected binary ExOp operator");
2194 op1 = tree->gtOp.gtOp1;
2195 GenTreePtr op2 = tree->gtOp.gtOp2;
2197 /* Is there a second sub-operand? */
2201 /* Special case: no sub-operands at all */
2206 /* This is a unary operator */
2212 /* This is a binary operator */
2214 unsigned hsh1 = gtHashValue(op1);
2216 /* Special case: addition of two values */
2218 if (GenTree::OperIsCommutative(oper))
2220 unsigned hsh2 = gtHashValue(op2);
2222 /* Produce a hash that allows swapping the operands */
2224 hash = genTreeHashAdd(hash, hsh1, hsh2);
2228 /* Add op1's hash to the running value and continue with op2 */
2230 hash = genTreeHashAdd(hash, hsh1);
2236 /* See what kind of a special operator we have here */
2237 switch (tree->gtOper)
2240 if (tree->gtField.gtFldObj)
2242 temp = tree->gtField.gtFldObj; assert(temp);
2243 hash = genTreeHashAdd(hash, gtHashValue(temp));
2248 temp = tree->gtStmt.gtStmtExpr; assert(temp);
2249 hash = genTreeHashAdd(hash, gtHashValue(temp));
2254 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrElem.gtArrObj));
2257 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
2258 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrElem.gtArrInds[dim]));
2263 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrOffs.gtOffset));
2264 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrOffs.gtIndex));
2265 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrOffs.gtArrObj));
2270 if (tree->gtCall.gtCallObjp && tree->gtCall.gtCallObjp->gtOper != GT_NOP)
2272 temp = tree->gtCall.gtCallObjp; assert(temp);
2273 hash = genTreeHashAdd(hash, gtHashValue(temp));
2276 if (tree->gtCall.gtCallArgs)
2278 temp = tree->gtCall.gtCallArgs; assert(temp);
2279 hash = genTreeHashAdd(hash, gtHashValue(temp));
2282 if (tree->gtCall.gtCallType == CT_INDIRECT)
2284 temp = tree->gtCall.gtCallAddr; assert(temp);
2285 hash = genTreeHashAdd(hash, gtHashValue(temp));
2289 hash = genTreeHashAdd(hash, tree->gtCall.gtCallMethHnd);
2292 if (tree->gtCall.gtCallLateArgs)
2294 temp = tree->gtCall.gtCallLateArgs; assert(temp);
2295 hash = genTreeHashAdd(hash, gtHashValue(temp));
2300 hash = genTreeHashAdd(hash, gtHashValue(tree->gtCmpXchg.gtOpLocation));
2301 hash = genTreeHashAdd(hash, gtHashValue(tree->gtCmpXchg.gtOpValue));
2302 hash = genTreeHashAdd(hash, gtHashValue(tree->gtCmpXchg.gtOpComparand));
2305 case GT_ARR_BOUNDS_CHECK:
2308 #endif // FEATURE_SIMD
2309 hash = genTreeHashAdd(hash, gtHashValue(tree->gtBoundsChk.gtArrLen));
2310 hash = genTreeHashAdd(hash, gtHashValue(tree->gtBoundsChk.gtIndex));
2311 hash = genTreeHashAdd(hash, tree->gtBoundsChk.gtThrowKind);
2318 assert(!"unexpected operator");
2327 /*****************************************************************************
2329 * Given an arbitrary expression tree, attempts to find the set of all local variables
2330 * referenced by the tree, and return them as "*result".
2331 * If "findPtr" is null, this is a tracked variable set;
2332 * if it is non-null, this is an "all var set."
2333 * The "*result" value is valid only if the call returns "true." It may return "false"
2334 * for several reasons:
2335 * If "findPtr" is NULL, and the expression contains an untracked variable.
2336 * If "findPtr" is non-NULL, and the expression contains a variable that can't be represented
2337 * in an "all var set."
2338 * If the expression accesses address-exposed variables.
2341 * are any indirections or global refs in the expression, the "*refsPtr" argument
2342 * will be assigned the appropriate bit set based on the 'varRefKinds' type.
2343 * It won't be assigned anything when there are no indirections or global
2344 * references, though, so this value should be initialized before the call.
2345 * If we encounter an expression that is equal to *findPtr we set *findPtr
2348 bool Compiler::lvaLclVarRefs(GenTreePtr tree,
2349 GenTreePtr * findPtr,
2350 varRefKinds* refsPtr,
2355 varRefKinds refs = VR_NONE;
2356 ALLVARSET_TP ALLVARSET_INIT_NOCOPY(allVars, AllVarSetOps::UninitVal());
2357 VARSET_TP VARSET_INIT_NOCOPY(trkdVars, VarSetOps::UninitVal());
2359 AllVarSetOps::AssignNoCopy(this, allVars, AllVarSetOps::MakeEmpty(this));
2361 VarSetOps::AssignNoCopy(this, trkdVars, VarSetOps::MakeEmpty(this));
2366 assert(tree->gtOper != GT_STMT);
2368 /* Remember whether we've come across the expression we're looking for */
2370 if (findPtr && *findPtr == tree) *findPtr = NULL;
2372 /* Figure out what kind of a node we have */
2374 oper = tree->OperGet();
2375 kind = tree->OperKind();
2377 /* Is this a constant or leaf node? */
2379 if (kind & (GTK_CONST|GTK_LEAF))
2381 if (oper == GT_LCL_VAR)
2383 unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
2385 /* Should we use the variable table? */
2389 if (lclNum >= lclMAX_ALLSET_TRACKED)
2392 AllVarSetOps::AddElemD(this, allVars, lclNum);
2396 assert(lclNum < lvaCount);
2397 LclVarDsc * varDsc = lvaTable + lclNum;
2399 if (varDsc->lvTracked == false)
2402 // Don't deal with expressions with address-exposed variables.
2403 if (varDsc->lvAddrExposed)
2406 VarSetOps::AddElemD(this, trkdVars, varDsc->lvVarIndex);
2409 else if (oper == GT_LCL_FLD)
2411 /* We can't track every field of every var. Moreover, indirections
2412 may access different parts of the var as different (but
2413 overlapping) fields. So just treat them as indirect accesses */
2415 if (varTypeIsGC(tree->TypeGet()))
2420 else if (oper == GT_CLS_VAR)
2425 if (refs != VR_NONE)
2427 /* Write it back to callers parameter using an 'or' */
2428 *refsPtr = varRefKinds((*refsPtr) | refs);
2430 lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
2434 /* Is it a 'simple' unary/binary operator? */
2436 if (kind & GTK_SMPOP)
2440 assert(tree->gtOp.gtOp2 == NULL);
2442 /* Set the proper indirection bit */
2444 if ((tree->gtFlags & GTF_IND_INVARIANT) == 0)
2446 if (varTypeIsGC(tree->TypeGet()))
2451 // If the flag GTF_IND_TGTANYWHERE is set this indirection
2452 // could also point at a global variable
2454 if (tree->gtFlags & GTF_IND_TGTANYWHERE)
2456 refs = varRefKinds( ((int) refs) | ((int) VR_GLB_VAR) );
2460 /* Write it back to callers parameter using an 'or' */
2461 *refsPtr = varRefKinds((*refsPtr) | refs);
2463 // For IL volatile memory accesses we mark the GT_IND node
2464 // with a GTF_DONT_CSE flag.
2466 // This flag is also set for the left hand side of an assignment.
2468 // If this flag is set then we return false
2470 if (tree->gtFlags & GTF_DONT_CSE)
2476 if (tree->gtGetOp2())
2478 /* It's a binary operator */
2479 if (!lvaLclVarRefsAccum(tree->gtOp.gtOp1, findPtr, refsPtr, &allVars, &trkdVars)) return false;
2481 tree = tree->gtOp.gtOp2; assert(tree);
2486 /* It's a unary (or nilary) operator */
2488 tree = tree->gtOp.gtOp1;
2492 lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
2500 if (!lvaLclVarRefsAccum(tree->gtArrElem.gtArrObj, findPtr, refsPtr, &allVars, &trkdVars)) return false;
2503 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
2505 VARSET_TP VARSET_INIT_NOCOPY(tmpVs, VarSetOps::UninitVal());
2506 if (!lvaLclVarRefsAccum(tree->gtArrElem.gtArrInds[dim], findPtr, refsPtr, &allVars, &trkdVars)) return false;
2508 lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
2512 if (!lvaLclVarRefsAccum(tree->gtArrOffs.gtOffset, findPtr, refsPtr, &allVars, &trkdVars))
2515 if (!lvaLclVarRefsAccum(tree->gtArrOffs.gtIndex, findPtr, refsPtr, &allVars, &trkdVars))
2518 if (!lvaLclVarRefsAccum(tree->gtArrOffs.gtArrObj, findPtr, refsPtr, &allVars, &trkdVars))
2521 lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
2524 case GT_ARR_BOUNDS_CHECK:
2527 #endif // FEATURE_SIMD
2529 if (!lvaLclVarRefsAccum(tree->gtBoundsChk.gtArrLen, findPtr, refsPtr, &allVars, &trkdVars)) return false;
2531 if (!lvaLclVarRefsAccum(tree->gtBoundsChk.gtIndex, findPtr, refsPtr, &allVars, &trkdVars)) return false;
2533 lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
2538 /* Allow calls to the Shared Static helper */
2539 if (IsSharedStaticHelper(tree))
2541 *refsPtr = varRefKinds((*refsPtr) | VR_INVARIANT);
2542 lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
2549 } // end switch (oper)
2554 bool Compiler::lvaLclVarRefsAccum(GenTreePtr tree,
2555 GenTreePtr * findPtr,
2556 varRefKinds * refsPtr,
2557 ALLVARSET_TP* allVars,
2558 VARSET_TP* trkdVars)
2562 ALLVARSET_TP ALLVARSET_INIT_NOCOPY(tmpVs, AllVarSetOps::UninitVal());
2563 if (!lvaLclVarRefs(tree, findPtr, refsPtr, &tmpVs)) return false;
2565 AllVarSetOps::UnionD(this, *allVars, tmpVs);
2569 VARSET_TP VARSET_INIT_NOCOPY(tmpVs, VarSetOps::UninitVal());
2570 if (!lvaLclVarRefs(tree, findPtr, refsPtr, &tmpVs)) return false;
2572 VarSetOps::UnionD(this, *trkdVars, tmpVs);
2577 void Compiler::lvaLclVarRefsAccumIntoRes(GenTreePtr * findPtr,
2579 ALLVARSET_VALARG_TP allVars,
2580 VARSET_VALARG_TP trkdVars)
2584 ALLVARSET_TP* avsPtr = (ALLVARSET_TP*)result;
2585 AllVarSetOps::AssignNoCopy(this, (*avsPtr), allVars);
2589 VARSET_TP* vsPtr = (VARSET_TP*)result;
2590 VarSetOps::AssignNoCopy(this, (*vsPtr), trkdVars);
2594 /*****************************************************************************
2596 * Return a relational operator that is the reverse of the given one.
2600 genTreeOps GenTree::ReverseRelop(genTreeOps relop)
2603 genTreeOps reverseOps[] =
2613 assert(reverseOps[GT_EQ - GT_EQ] == GT_NE);
2614 assert(reverseOps[GT_NE - GT_EQ] == GT_EQ);
2616 assert(reverseOps[GT_LT - GT_EQ] == GT_GE);
2617 assert(reverseOps[GT_LE - GT_EQ] == GT_GT);
2618 assert(reverseOps[GT_GE - GT_EQ] == GT_LT);
2619 assert(reverseOps[GT_GT - GT_EQ] == GT_LE);
2621 assert(OperIsCompare(relop));
2622 assert(relop >= GT_EQ && (unsigned)(relop - GT_EQ) < sizeof(reverseOps));
2624 return reverseOps[relop - GT_EQ];
2627 /*****************************************************************************
2629 * Return a relational operator that will work for swapped operands.
2633 genTreeOps GenTree::SwapRelop(genTreeOps relop)
2636 genTreeOps swapOps[] =
2646 assert(swapOps[GT_EQ - GT_EQ] == GT_EQ);
2647 assert(swapOps[GT_NE - GT_EQ] == GT_NE);
2649 assert(swapOps[GT_LT - GT_EQ] == GT_GT);
2650 assert(swapOps[GT_LE - GT_EQ] == GT_GE);
2651 assert(swapOps[GT_GE - GT_EQ] == GT_LE);
2652 assert(swapOps[GT_GT - GT_EQ] == GT_LT);
2654 assert(OperIsCompare(relop));
2655 assert(relop >= GT_EQ && (unsigned)(relop - GT_EQ) < sizeof(swapOps));
2657 return swapOps[relop - GT_EQ];
2660 /*****************************************************************************
2662 * Reverse the meaning of the given test condition.
2665 GenTreePtr Compiler::gtReverseCond(GenTree * tree)
2667 if (tree->OperIsCompare())
2669 tree->SetOper(GenTree::ReverseRelop(tree->OperGet()));
2671 // Flip the GTF_RELOP_NAN_UN bit
2672 // a ord b === (a != NaN && b != NaN)
2673 // a unord b === (a == NaN || b == NaN)
2674 // => !(a ord b) === (a unord b)
2675 if (varTypeIsFloating(tree->gtOp.gtOp1->TypeGet()))
2676 tree->gtFlags ^= GTF_RELOP_NAN_UN;
2680 tree = gtNewOperNode(GT_NOT, TYP_INT, tree);
2687 /*****************************************************************************/
2692 bool GenTree::gtIsValid64RsltMul()
2694 if ((gtOper != GT_MUL) || !(gtFlags & GTF_MUL_64RSLT))
2697 GenTreePtr op1 = gtOp.gtOp1;
2698 GenTreePtr op2 = gtOp.gtOp2;
2700 if (TypeGet() != TYP_LONG ||
2701 op1->TypeGet() != TYP_LONG ||
2702 op2->TypeGet() != TYP_LONG)
2708 // op1 has to be conv.i8(i4Expr)
2709 if ((op1->gtOper != GT_CAST) ||
2710 (genActualType(op1->CastFromType()) != TYP_INT))
2713 // op2 has to be conv.i8(i4Expr)
2714 if ((op2->gtOper != GT_CAST) ||
2715 (genActualType(op2->CastFromType()) != TYP_INT))
2718 // The signedness of both casts must be the same
2719 if (((op1->gtFlags & GTF_UNSIGNED) != 0) !=
2720 ((op2->gtFlags & GTF_UNSIGNED) != 0))
2723 // Do unsigned mul iff both the casts are unsigned
2724 if (((op1->gtFlags & GTF_UNSIGNED) != 0) != ((gtFlags & GTF_UNSIGNED) != 0))
2732 /*****************************************************************************
2734 * Figure out the evaluation order for a list of values.
2737 unsigned Compiler::gtSetListOrder(GenTree *list, bool regs)
2739 assert(list && list->IsList());
2743 unsigned costSz = 0;
2744 unsigned costEx = 0;
2746 #if FEATURE_STACK_FP_X87
2747 /* Save the current FP stack level since an argument list
2748 * will implicitly pop the FP stack when pushing the argument */
2749 unsigned FPlvlSave = codeGen->genGetFPstkLevel();
2750 #endif // FEATURE_STACK_FP_X87
2752 GenTreePtr next = list->gtOp.gtOp2;
2756 unsigned nxtlvl = gtSetListOrder(next, regs);
2758 ftreg |= next->gtRsvdRegs;
2762 costEx += next->gtCostEx;
2763 costSz += next->gtCostSz;
2766 GenTreePtr op1 = list->gtOp.gtOp1;
2767 unsigned lvl = gtSetEvalOrder(op1);
2769 #if FEATURE_STACK_FP_X87
2770 /* restore the FP level */
2771 codeGen->genResetFPstkLevel(FPlvlSave);
2772 #endif // FEATURE_STACK_FP_X87
2774 list->gtRsvdRegs = (regMaskSmall)(ftreg | op1->gtRsvdRegs);
2779 if (op1->gtCostEx != 0)
2781 costEx += op1->gtCostEx;
2782 costEx += regs ? 0 : IND_COST_EX;
2785 if (op1->gtCostSz != 0)
2787 costSz += op1->gtCostSz;
2788 #ifdef _TARGET_XARCH_
2789 if (regs) // push is smaller than mov to reg
2796 list->SetCosts(costEx, costSz);
2801 /*****************************************************************************
2803 * This routine is a helper routine for gtSetEvalOrder() and is used to
2804 * mark the interior address computation nodes with the GTF_ADDRMODE_NO_CSE flag
2805 * which prevents them from being considered for CSE's.
2807 * Furthermore this routine is a factoring of the logic used to walk down
2808 * the child nodes of a GT_IND tree, similar to optParseArrayRef().
2810 * Previously we had this logic repeated three times inside of gtSetEvalOrder().
2811 * Here we combine those three repeats into this routine and use the
2812 * bool constOnly to modify the behavior of this routine for the first call.
2814 * The object here is to mark all of the interior GT_ADD's and GT_NOP's
2815 * with the GTF_ADDRMODE_NO_CSE flag and to set op1 and op2 to the terminal nodes
2816 * which are later matched against 'adr' and 'idx'.
2818 * *pbHasRangeCheckBelow is set to false if we traverse a range check GT_NOP
2819 * node in our walk. It remains unchanged otherwise.
2821 * TODO-Cleanup: It is essentially impossible to determine
2822 * what it is supposed to do, or to write a reasonable specification comment
2823 * for it that describes what it is supposed to do. There are obviously some
2824 * very specific tree patterns that it expects to see, but those are not documented.
2825 * The fact that it writes back to its op1WB and op2WB arguments, and traverses
2826 * down both op1 and op2 trees, but op2 is only related to op1 in the (!constOnly)
2827 * case (which really seems like a bug) is very confusing.
2830 void Compiler::gtWalkOp(GenTree * * op1WB,
2835 GenTreePtr op1 = *op1WB;
2836 GenTreePtr op2 = *op2WB;
2837 GenTreePtr op1EffectiveVal;
2839 if (op1->gtOper == GT_COMMA)
2841 op1EffectiveVal = op1->gtEffectiveVal();
2842 if ((op1EffectiveVal->gtOper == GT_ADD) &&
2843 (!op1EffectiveVal->gtOverflow()) &&
2844 (!constOnly || (op1EffectiveVal->gtOp.gtOp2->IsCnsIntOrI())))
2846 op1 = op1EffectiveVal;
2850 // Now we look for op1's with non-overflow GT_ADDs [of constants]
2851 while ((op1->gtOper == GT_ADD) &&
2852 (!op1->gtOverflow()) &&
2853 (!constOnly || (op1->gtOp.gtOp2->IsCnsIntOrI())))
2855 // mark it with GTF_ADDRMODE_NO_CSE
2856 op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
2858 if (!constOnly) // TODO-Cleanup: It seems bizarre that this is !constOnly
2859 op2 = op1->gtOp.gtOp2;
2860 op1 = op1->gtOp.gtOp1;
2862 // If op1 is a GT_NOP then swap op1 and op2.
2863 // (Why? Also, presumably op2 is not a GT_NOP in this case?)
2864 if (op1->gtOper == GT_NOP)
2873 if (op1->gtOper == GT_COMMA)
2875 op1EffectiveVal = op1->gtEffectiveVal();
2876 if ((op1EffectiveVal->gtOper == GT_ADD) &&
2877 (!op1EffectiveVal->gtOverflow()) &&
2878 (!constOnly || (op1EffectiveVal->gtOp.gtOp2->IsCnsIntOrI())))
2880 op1 = op1EffectiveVal;
2884 if (!constOnly && ((op2 == adr) || (!op2->IsCnsIntOrI())))
2893 /*****************************************************************************
2894 * This is a workaround. It is to help implement an assert in gtSetEvalOrder() that the values
2895 * gtWalkOp() leaves in op1 and op2 correspond with the values of adr, idx, mul, and cns
2896 * that are returned by genCreateAddrMode(). It's essentially impossible to determine
2897 * what gtWalkOp() *should* return for all possible trees. This simply loosens one assert
2898 * to handle the following case:
2901 const(h) int 4 field
2903 lclVar byref V00 this <-- op2
2904 comma byref <-- adr (base)
2906 lclVar byref V00 this
2908 const int 2 <-- mul == 4
2910 lclVar int V01 arg1 <-- idx
2912 * Here, we are planning to generate the address mode [edx+4*eax], where eax = idx and edx = the GT_COMMA expression.
2913 * To check adr equivalence with op2, we need to walk down the GT_ADD tree just like gtWalkOp() does.
2915 GenTreePtr Compiler::gtWalkOpEffectiveVal(GenTreePtr op)
2919 if (op->gtOper == GT_COMMA)
2921 GenTreePtr opEffectiveVal = op->gtEffectiveVal();
2922 if ((opEffectiveVal->gtOper == GT_ADD) &&
2923 (!opEffectiveVal->gtOverflow()) &&
2924 (opEffectiveVal->gtOp.gtOp2->IsCnsIntOrI()))
2926 op = opEffectiveVal;
2930 if ((op->gtOper != GT_ADD) ||
2932 !op->gtOp.gtOp2->IsCnsIntOrI())
2935 op = op->gtOp.gtOp1;
2942 /*****************************************************************************
2944 * Given a tree, set the gtCostEx and gtCostSz fields which
2945 * are used to measure the relative costs of the codegen of the tree
2949 void Compiler::gtPrepareCost(GenTree * tree)
2951 #if FEATURE_STACK_FP_X87
2952 codeGen->genResetFPstkLevel();
2953 #endif // FEATURE_STACK_FP_X87
2954 gtSetEvalOrder(tree);
2957 bool Compiler::gtIsLikelyRegVar(GenTree * tree)
2959 if (tree->gtOper != GT_LCL_VAR)
2962 assert(tree->gtLclVar.gtLclNum < lvaTableCnt);
2963 LclVarDsc * varDsc = lvaTable + tree->gtLclVar.gtLclNum;
2965 if (varDsc->lvDoNotEnregister)
2968 if (varDsc->lvRefCntWtd < (BB_UNITY_WEIGHT * 3))
2972 if (varTypeIsFloating(tree->TypeGet()))
2974 if (varTypeIsLong(tree->TypeGet()))
2981 //------------------------------------------------------------------------
2982 // gtCanSwapOrder: Returns true iff the secondNode can be swapped with firstNode.
2985 // firstNode - An operand of a tree that can have GTF_REVERSE_OPS set.
2986 // secondNode - The other operand of the tree.
2989 // Returns a boolean indicating whether it is safe to reverse the execution
2990 // order of the two trees, considering any exception, global effects, or
2991 // ordering constraints.
2994 Compiler::gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode)
2996 // Relative of order of global / side effects can't be swapped.
2998 bool canSwap = true;
3000 if (optValnumCSE_phase)
3002 canSwap = optCSE_canSwap(firstNode, secondNode);
3005 // We cannot swap in the presence of special side effects such as GT_CATCH_ARG.
3008 (firstNode->gtFlags & GTF_ORDER_SIDEEFF))
3013 // When strict side effect order is disabled we allow GTF_REVERSE_OPS to be set
3014 // when one or both sides contains a GTF_CALL or GTF_EXCEPT.
3015 // Currently only the C and C++ languages allow non strict side effect order.
3017 unsigned strictEffects = GTF_GLOB_EFFECT;
3020 (firstNode->gtFlags & strictEffects))
3022 // op1 has side efects that can't be reordered.
3023 // Check for some special cases where we still may be able to swap.
3025 if (secondNode->gtFlags & strictEffects)
3027 // op2 has also has non reorderable side effects - can't swap.
3032 // No side effects in op2 - we can swap iff op1 has no way of modifying op2,
3033 // i.e. through byref assignments or calls or op2 is a constant.
3035 if (firstNode->gtFlags & strictEffects & GTF_PERSISTENT_SIDE_EFFECTS)
3037 // We have to be conservative - can swap iff op2 is constant.
3038 if (!secondNode->OperIsConst())
3046 /*****************************************************************************
3048 * Given a tree, figure out the order in which its sub-operands should be
3049 * evaluated. If the second operand of a binary operator is more expensive
3050 * than the first operand, then try to swap the operand trees. Updates the
3051 * GTF_REVERSE_OPS bit if necessary in this case.
3053 * Returns the Sethi 'complexity' estimate for this tree (the higher
3054 * the number, the higher is the tree's resources requirement).
3056 * This function sets:
3057 * 1. gtCostEx to the execution complexity estimate
3058 * 2. gtCostSz to the code size estimate
3059 * 3. gtRsvdRegs to the set of fixed registers trashed by the tree
3060 * 4. gtFPlvl to the "floating point depth" value for node, i.e. the max. number
3061 * of operands the tree will push on the x87 (coprocessor) stack. Also sets
3062 * genFPstkLevel, tmpDoubleSpillMax, and possibly gtFPstLvlRedo.
3063 * 5. Sometimes sets GTF_ADDRMODE_NO_CSE on nodes in the tree.
3064 * 6. DEBUG-only: clears GTF_DEBUG_NODE_MORPHED.
3068 #pragma warning(push)
3069 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
3071 unsigned Compiler::gtSetEvalOrder(GenTree * tree)
3074 assert(tree->gtOper != GT_STMT);
3077 /* Clear the GTF_DEBUG_NODE_MORPHED flag as well */
3078 tree->gtDebugFlags &= ~GTF_DEBUG_NODE_MORPHED;
3081 /* Is this a FP value? */
3083 bool isflt = varTypeIsFloating(tree->TypeGet());
3086 /* Figure out what kind of a node we have */
3088 genTreeOps oper = tree->OperGet();
3089 unsigned kind = tree->OperKind();
3091 /* Assume no fixed registers will be trashed */
3093 regMaskTP ftreg = RBM_NONE; // Set of registers that will be used by the subtree
3105 /* Is this a constant or a leaf node? */
3107 if (kind & (GTK_LEAF|GTK_CONST))
3111 bool iconNeedsReloc;
3127 // If the constant is a handle then it will need to have a relocation
3129 // Any constant that requires a reloc must use the movw/movt sequence
3131 iconNeedsReloc = opts.compReloc && tree->IsIconHandle() && !tree->IsIconHandle(GTF_ICON_FIELD_HDL);
3133 if (iconNeedsReloc || !codeGen->validImmForInstr(INS_mov, tree->gtIntCon.gtIconVal))
3139 else if (((unsigned) tree->gtIntCon.gtIconVal) <= 0x00ff)
3153 #elif defined _TARGET_XARCH_
3167 // If the constant is a handle then it will need to have a relocation
3169 // Any constant that requires a reloc must use the movw/movt sequence
3171 iconNeedsReloc = opts.compReloc && tree->IsIconHandle() && !tree->IsIconHandle(GTF_ICON_FIELD_HDL);
3173 if (!iconNeedsReloc && (((signed char) tree->gtIntCon.gtIconVal) == tree->gtIntCon.gtIconVal))
3178 #if defined(_TARGET_AMD64_)
3179 else if (iconNeedsReloc || ((tree->gtIntCon.gtIconVal & 0xFFFFFFFF00000000LL) != 0))
3184 #endif // _TARGET_AMD64_
3192 #elif defined(_TARGET_ARM64_)
3196 // TODO-ARM64-NYI: Need cost estimates.
3205 #error "Unknown _TARGET_"
3210 Note that some code below depends on constants always getting
3211 moved to be the second operand of a binary operator. This is
3212 easily accomplished by giving constants a level of 0, which
3213 we do on the next line. If you ever decide to change this, be
3214 aware that unless you make other arrangements for integer
3215 constants to be moved, stuff will break.
3223 /* We use fldz and fld1 to load 0.0 and 1.0, but all other */
3224 /* floating point constants are loaded using an indirection */
3225 if ((*((__int64 *)&(tree->gtDblCon.gtDconVal)) == 0) ||
3226 (*((__int64 *)&(tree->gtDblCon.gtDconVal)) == I64(0x3ff0000000000000)))
3233 costEx = IND_COST_EX;
3240 if (gtIsLikelyRegVar(tree))
3244 /* Sign-extend and zero-extend are more expensive to load */
3245 if (lvaTable[tree->gtLclVar.gtLclNum].lvNormalizeOnLoad())
3253 costEx = IND_COST_EX;
3255 /* Sign-extend and zero-extend are more expensive to load */
3256 if (varTypeIsSmall(tree->TypeGet()))
3262 #if defined(_TARGET_AMD64_)
3263 // increase costSz for floating point locals
3267 if (!gtIsLikelyRegVar(tree))
3273 #if CPU_LONG_USES_REGPAIR
3274 if (varTypeIsLong(tree->TypeGet()))
3276 costEx *= 2; // Longs are twice as expensive
3284 // We generate movw/movt/ldr
3286 costEx = 3 + IND_COST_EX; // 6
3287 costSz = 4 + 4 + 2; // 10
3292 costEx = IND_COST_EX;
3294 if (varTypeIsSmall(tree->TypeGet()))
3314 #if FEATURE_STACK_FP_X87
3315 if (isflt && (oper != GT_PHI_ARG))
3317 codeGen->genIncrementFPstkLevel();
3319 #endif // FEATURE_STACK_FP_X87
3323 /* Is it a 'simple' unary/binary operator? */
3325 if (kind & GTK_SMPOP)
3327 int lvlb; // preference for op2
3328 unsigned lvl2; // scratch variable
3330 GenTreePtr op1 = tree->gtOp.gtOp1;
3331 GenTreePtr op2 = tree->gtGetOp2();
3336 if (tree->OperIsAddrMode())
3345 /* Check for a nilary operator */
3349 assert(op2 == nullptr);
3356 /* Is this a unary operator? */
3360 /* Process the operand of the operator */
3362 /* Most Unary ops have costEx of 1 */
3366 level = gtSetEvalOrder(op1);
3367 ftreg |= op1->gtRsvdRegs;
3369 /* Special handling for some operators */
3384 #if defined(_TARGET_ARM_)
3387 if (isflt || varTypeIsFloating(op1->TypeGet()))
3392 #elif defined(_TARGET_ARM64_)
3395 if (isflt || varTypeIsFloating(op1->TypeGet()))
3400 #elif defined(_TARGET_XARCH_)
3404 if (isflt || varTypeIsFloating(op1->TypeGet()))
3406 /* cast involving floats always go through memory */
3407 costEx = IND_COST_EX * 2;
3410 #if FEATURE_STACK_FP_X87
3411 if (isflt != varTypeIsFloating(op1->TypeGet()))
3413 isflt ? codeGen->genIncrementFPstkLevel() // Cast from int to float
3414 : codeGen->genDecrementFPstkLevel(); // Cast from float to int
3416 #endif // FEATURE_STACK_FP_X87
3419 #error "Unknown _TARGET_"
3422 #if CPU_LONG_USES_REGPAIR
3423 if (varTypeIsLong(tree->TypeGet()))
3425 if (varTypeIsUnsigned(tree->TypeGet()))
3427 /* Cast to unsigned long */
3433 /* Cast to signed long is slightly more costly */
3438 #endif // CPU_LONG_USES_REGPAIR
3440 /* Overflow casts are a lot more expensive */
3441 if (tree->gtOverflow())
3457 // GT_INTRINSIC intrinsics Sin, Cos, Sqrt, Abs ... have higher costs.
3458 // TODO: tune these costs target specific as some of these are
3459 // target intrinsics and would cost less to generate code.
3460 switch (tree->gtIntrinsic.gtIntrinsicId)
3463 assert(!"missing case for gtIntrinsicId");
3468 case CORINFO_INTRINSIC_Sin:
3469 case CORINFO_INTRINSIC_Cos:
3470 case CORINFO_INTRINSIC_Sqrt:
3471 case CORINFO_INTRINSIC_Cosh:
3472 case CORINFO_INTRINSIC_Sinh:
3473 case CORINFO_INTRINSIC_Tan:
3474 case CORINFO_INTRINSIC_Tanh:
3475 case CORINFO_INTRINSIC_Asin:
3476 case CORINFO_INTRINSIC_Acos:
3477 case CORINFO_INTRINSIC_Atan:
3478 case CORINFO_INTRINSIC_Atan2:
3479 case CORINFO_INTRINSIC_Log10:
3480 case CORINFO_INTRINSIC_Pow:
3481 case CORINFO_INTRINSIC_Exp:
3482 case CORINFO_INTRINSIC_Ceiling:
3483 case CORINFO_INTRINSIC_Floor:
3484 case CORINFO_INTRINSIC_Object_GetType:
3485 // Giving intrinsics a large fixed exectuion cost is because we'd like to CSE
3486 // them, even if they are implemented by calls. This is different from modeling
3487 // user calls since we never CSE user calls.
3492 case CORINFO_INTRINSIC_Abs:
3497 case CORINFO_INTRINSIC_Round:
3500 #if FEATURE_STACK_FP_X87
3501 if (tree->TypeGet() == TYP_INT)
3503 // This is a special case to handle the following
3504 // optimization: conv.i4(round.d(d)) -> round.i(d)
3505 codeGen->genDecrementFPstkLevel();
3507 #endif // FEATURE_STACK_FP_X87
3515 // We need to ensure that -x is evaluated before x or else
3516 // we get burned while adjusting genFPstkLevel in x*-x where
3517 // the rhs x is the last use of the enregsitered x.
3519 // Even in the integer case we want to prefer to
3520 // evaluate the side without the GT_NEG node, all other things
3521 // being equal. Also a GT_NOT requires a scratch register
3528 /* If the operand was floating point, pop the value from the stack */
3530 #if FEATURE_STACK_FP_X87
3531 if (varTypeIsFloating(op1->TypeGet()))
3533 codeGen->genDecrementFPstkLevel();
3535 #endif // FEATURE_STACK_FP_X87
3539 // If we have a GT_ADDR of an GT_IND we can just copy the costs from indOp1
3540 if (op1->OperGet() == GT_IND)
3542 GenTreePtr indOp1 = op1->gtOp.gtOp1;
3543 costEx = indOp1->gtCostEx;
3544 costSz = indOp1->gtCostSz;
3551 /* Array Len should be the same as an indirections, which have a costEx of IND_COST_EX */
3552 costEx = IND_COST_EX - 1;
3558 // We estimate the cost of a GT_OBJ or GT_MKREFANY to be two loads (GT_INDs)
3559 costEx = 2*IND_COST_EX;
3564 // We estimate the cost of a GT_BOX to be two stores (GT_INDs)
3565 costEx = 2*IND_COST_EX;
3571 /* An indirection should always have a non-zero level.
3572 * Only constant leaf nodes have level 0.
3578 /* Indirections have a costEx of IND_COST_EX */
3579 costEx = IND_COST_EX;
3582 /* If we have to sign-extend or zero-extend, bump the cost */
3583 if (varTypeIsSmall(tree->TypeGet()))
3591 #if FEATURE_STACK_FP_X87
3592 /* Indirect loads of FP values push a new value on the FP stack */
3593 codeGen->genIncrementFPstkLevel();
3594 #endif // FEATURE_STACK_FP_X87
3595 if (tree->TypeGet() == TYP_DOUBLE)
3599 #endif // _TARGET_ARM_
3602 /* Can we form an addressing mode with this indirection? */
3604 if (op1->gtOper == GT_ADD)
3607 #if SCALED_ADDR_MODES
3614 /* See if we can form a complex addressing mode? */
3616 GenTreePtr addr = op1;
3617 if (codeGen->genCreateAddrMode(addr, // address
3620 RBM_NONE, // reg mask
3621 &rev, // reverse ops
3624 #if SCALED_ADDR_MODES
3627 &cns, // displacement
3628 true)) // don't generate code
3630 // We can form a complex addressing mode, so mark each of the interior
3631 // nodes with GTF_ADDRMODE_NO_CSE and calculate a more accurate cost.
3633 addr->gtFlags |= GTF_ADDRMODE_NO_CSE;
3634 #ifdef _TARGET_XARCH_
3635 // addrmodeCount is the count of items that we used to form
3636 // an addressing mode. The maximum value is 4 when we have
3637 // all of these: { base, idx, cns, mul }
3639 unsigned addrmodeCount = 0;
3642 costEx += base->gtCostEx;
3643 costSz += base->gtCostSz;
3649 costEx += idx->gtCostEx;
3650 costSz += idx->gtCostSz;
3656 if (((signed char)cns) == ((int)cns))
3666 // When we form a complex addressing mode we can reduced the costs
3667 // associated with the interior GT_ADD and GT_LSH nodes:
3669 // GT_ADD -- reduce this interior GT_ADD by (-3,-3)
3671 // GT_ADD 'cns' -- reduce this interior GT_ADD by (-2,-2)
3673 // 'base' GT_LSL -- reduce this interior GT_LSL by (-1,-1)
3677 if (addrmodeCount > 1)
3679 // The number of interior GT_ADD and GT_LSL will always be one less than addrmodeCount
3683 GenTreePtr tmp = addr;
3684 while (addrmodeCount > 0)
3686 // decrement the gtCosts for the interior GT_ADD or GT_LSH node by the remaining addrmodeCount
3687 tmp->SetCosts(tmp->gtCostEx - addrmodeCount, tmp->gtCostSz - addrmodeCount);
3690 if (addrmodeCount > 0)
3692 GenTreePtr tmpOp1 = tmp->gtOp.gtOp1;
3693 GenTreePtr tmpOp2 = tmp->gtGetOp2();
3694 assert(tmpOp2 != nullptr);
3696 if ((tmpOp1 != base) && (tmpOp1->OperGet() == GT_ADD))
3700 else if (tmpOp2->OperGet() == GT_LSH)
3704 else if (tmpOp1->OperGet() == GT_LSH)
3708 else if (tmpOp2->OperGet() == GT_ADD)
3714 // We can very rarely encounter a tree that has a GT_COMMA node
3715 // that is difficult to walk, so we just early out without decrementing.
3721 #elif defined _TARGET_ARM_
3724 costEx += base->gtCostEx;
3725 costSz += base->gtCostSz;
3726 if ((base->gtOper == GT_LCL_VAR) &&
3727 ((idx==NULL) || (cns==0)))
3735 costEx += idx->gtCostEx;
3736 costSz += idx->gtCostSz;
3745 if (cns >= 128) // small offsets fits into a 16-bit instruction
3747 if (cns < 4096) // medium offsets require a 32-bit instruction
3754 costEx += 2; // Very large offsets require movw/movt instructions
3759 #elif defined _TARGET_ARM64_
3762 costEx += base->gtCostEx;
3763 costSz += base->gtCostSz;
3768 costEx += idx->gtCostEx;
3769 costSz += idx->gtCostSz;
3774 if (cns >= (4096 * genTypeSize(tree->TypeGet())))
3781 #error "Unknown _TARGET_"
3784 assert(addr->gtOper == GT_ADD);
3785 assert(!addr->gtOverflow());
3786 assert(op2 == NULL);
3789 // If we have an addressing mode, we have one of:
3791 // [ idx * mul ] // mul >= 2, else we would use base instead of idx
3792 // [ idx * mul + cns] // mul >= 2, else we would use base instead of idx
3793 // [base + idx * mul ] // mul can be 0, 2, 4, or 8
3794 // [base + idx * mul + cns] // mul can be 0, 2, 4, or 8
3795 // Note that mul == 0 is semantically equivalent to mul == 1.
3796 // Note that cns can be zero.
3797 #if SCALED_ADDR_MODES
3798 assert((base != NULL) || (idx != NULL && mul >= 2));
3800 assert(base != NULL);
3803 INDEBUG(GenTreePtr op1Save = addr);
3805 /* Walk addr looking for non-overflow GT_ADDs */
3806 gtWalkOp(&addr, &op2, base, false);
3808 // addr and op2 are now children of the root GT_ADD of the addressing mode
3809 assert(addr != op1Save);
3810 assert(op2 != NULL);
3812 /* Walk addr looking for non-overflow GT_ADDs of constants */
3813 gtWalkOp(&addr, &op2, NULL, true);
3815 // TODO-Cleanup: It seems very strange that we might walk down op2 now, even though the prior
3816 // call to gtWalkOp() may have altered op2.
3818 /* Walk op2 looking for non-overflow GT_ADDs of constants */
3819 gtWalkOp(&op2, &addr, NULL, true);
3821 // OK we are done walking the tree
3822 // Now assert that addr and op2 correspond with base and idx
3823 // in one of the several acceptable ways.
3825 // Note that sometimes addr/op2 is equal to idx/base
3826 // and other times addr/op2 is a GT_COMMA node with
3827 // an effective value that is idx/base
3831 if ((addr != base) && (addr->gtOper == GT_LSH))
3833 addr->gtFlags |= GTF_ADDRMODE_NO_CSE;
3834 if (addr->gtOp.gtOp1->gtOper == GT_MUL)
3836 addr->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3838 assert((base == NULL) || (op2 == base) || (op2->gtEffectiveVal() == base->gtEffectiveVal()) ||
3839 (gtWalkOpEffectiveVal(op2) == gtWalkOpEffectiveVal(base)));
3844 assert(op2->gtOper == GT_LSH || op2->gtOper == GT_MUL);
3845 op2->gtFlags |= GTF_ADDRMODE_NO_CSE;
3846 // We may have eliminated multiple shifts and multiplies in the addressing mode,
3847 // so navigate down through them to get to "idx".
3848 GenTreePtr op2op1 = op2->gtOp.gtOp1;
3849 while ((op2op1->gtOper == GT_LSH || op2op1->gtOper == GT_MUL) && op2op1 != idx)
3851 op2op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3852 op2op1 = op2op1->gtOp.gtOp1;
3854 assert(addr->gtEffectiveVal() == base);
3855 assert(op2op1 == idx);
3862 if ((addr == idx) || (addr->gtEffectiveVal() == idx))
3866 if ((addr->gtOper == GT_MUL) || (addr->gtOper == GT_LSH))
3868 if ((addr->gtOp.gtOp1->gtOper == GT_NOP) ||
3869 (addr->gtOp.gtOp1->gtOper == GT_MUL && addr->gtOp.gtOp1->gtOp.gtOp1->gtOper == GT_NOP))
3871 addr->gtFlags |= GTF_ADDRMODE_NO_CSE;
3872 if (addr->gtOp.gtOp1->gtOper == GT_MUL)
3873 addr->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3877 assert((op2 == base) || (op2->gtEffectiveVal() == base));
3879 else if ((addr == base) || (addr->gtEffectiveVal() == base))
3884 if ((op2->gtOper == GT_MUL) || (op2->gtOper == GT_LSH))
3886 if ((op2->gtOp.gtOp1->gtOper == GT_NOP) ||
3887 (op2->gtOp.gtOp1->gtOper == GT_MUL && op2->gtOp.gtOp1->gtOp.gtOp1->gtOper == GT_NOP))
3890 op2->gtFlags |= GTF_ADDRMODE_NO_CSE;
3891 if (op2->gtOp.gtOp1->gtOper == GT_MUL)
3892 op2->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3895 assert((op2 == idx) || (op2->gtEffectiveVal() == idx));
3900 // addr isn't base or idx. Is this possible? Or should there be an assert?
3905 } // end if (genCreateAddrMode(...))
3907 } // end if (op1->gtOper == GT_ADD)
3908 else if (gtIsLikelyRegVar(op1))
3910 /* Indirection of an enregister LCL_VAR, don't increase costEx/costSz */
3913 #ifdef _TARGET_XARCH_
3914 else if (op1->IsCnsIntOrI())
3916 // Indirection of a CNS_INT, subtract 1 from costEx
3917 // makes costEx 3 for x86 and 4 for amd64
3919 costEx += (op1->gtCostEx - 1);
3920 costSz += op1->gtCostSz;
3929 costEx += op1->gtCostEx;
3930 costSz += op1->gtCostSz;
3934 /* Binary operator - check for certain special cases */
3938 /* Default Binary ops have a cost of 1,1 */
3948 #ifndef _TARGET_64BIT_
3949 if (varTypeIsLong(op1->TypeGet()))
3951 /* Operations on longs are more expensive */
3961 /* Modulo by a power of 2 is easy */
3963 if (op2->IsCnsIntOrI())
3965 size_t ival = op2->gtIntConCommon.IconValue();
3967 if (ival > 0 && ival == genFindLowestBit(ival))
3978 /* fp division is very expensive to execute */
3979 costEx = 36; // TYP_DOUBLE
3984 /* integer division is also very expensive */
3988 // Encourage the first operand to be evaluated (into EAX/EDX) first */
3991 #ifdef _TARGET_XARCH_
3992 // the idiv and div instruction requires EAX/EDX
3993 ftreg |= RBM_EAX|RBM_EDX;
4002 /* FP multiplication instructions are more expensive */
4008 /* Integer multiplication instructions are more expensive */
4012 if (tree->gtOverflow())
4014 /* Overflow check are more expensive */
4020 if ((tree->gtType == TYP_LONG) || tree->gtOverflow())
4022 /* We use imulEAX for TYP_LONG and overflow multiplications */
4023 // Encourage the first operand to be evaluated (into EAX/EDX) first */
4026 // the imulEAX instruction ob x86 requires EDX:EAX
4027 ftreg |= (RBM_EAX|RBM_EDX);
4029 /* The 64-bit imul instruction costs more */
4032 #endif // _TARGET_X86_
4043 /* FP instructions are a bit more expensive */
4049 /* Overflow check are more expensive */
4050 if (tree->gtOverflow())
4060 /* Comma tosses the result of the left operand */
4061 gtSetEvalOrderAndRestoreFPstkLevel(op1);
4062 level = gtSetEvalOrder(op2);
4064 ftreg |= op1->gtRsvdRegs|op2->gtRsvdRegs;
4066 /* GT_COMMA cost is the sum of op1 and op2 costs */
4067 costEx = (op1->gtCostEx + op2->gtCostEx);
4068 costSz = (op1->gtCostSz + op2->gtCostSz);
4074 level = gtSetEvalOrderAndRestoreFPstkLevel(op1);
4075 lvl2 = gtSetEvalOrder(op2);
4079 else if (level == lvl2)
4082 ftreg |= op1->gtRsvdRegs|op2->gtRsvdRegs;
4083 costEx = op1->gtCostEx + op2->gtCostEx;
4084 costSz = op1->gtCostSz + op2->gtCostSz;
4092 /* Assignments need a bit of special handling */
4094 if (kind & GTK_ASGOP)
4096 /* Process the target */
4098 level = gtSetEvalOrder(op1);
4100 #if FEATURE_STACK_FP_X87
4102 /* If assigning an FP value, the target won't get pushed */
4104 if (isflt && !tree->IsPhiDefn())
4107 codeGen->genDecrementFPstkLevel();
4110 #endif // FEATURE_STACK_FP_X87
4112 if (gtIsLikelyRegVar(op1))
4115 lvl2 = gtSetEvalOrder(op2);
4117 ftreg |= op2->gtRsvdRegs;
4119 /* Assignment to an enregistered LCL_VAR */
4120 costEx = op2->gtCostEx;
4121 costSz = max(3, op2->gtCostSz); // 3 is an estimate for a reg-reg assignment
4122 goto DONE_OP1_AFTER_COST;
4124 else if (oper != GT_ASG)
4126 // Assign-Op instructions read and write op1
4128 costEx += op1->gtCostEx;
4130 costSz += op1->gtCostSz;
4137 /* Process the sub-operands */
4139 level = gtSetEvalOrder(op1);
4142 level -= lvlb; // lvlb is negative, so this increases level
4148 lvl2 = gtSetEvalOrder(op2) + lvlb;
4149 ftreg |= op1->gtRsvdRegs;
4151 ftreg |= op2->gtRsvdRegs;
4153 costEx += (op1->gtCostEx + op2->gtCostEx);
4154 costSz += (op1->gtCostSz + op2->gtCostSz);
4156 DONE_OP1_AFTER_COST:
4158 Binary FP operators pop 2 operands and produce 1 result;
4159 FP comparisons pop 2 operands and produces 0 results.
4160 assignments consume 1 value and don't produce anything.
4163 #if FEATURE_STACK_FP_X87
4164 if (isflt && !tree->IsPhiDefn())
4166 assert(oper != GT_COMMA);
4167 codeGen->genDecrementFPstkLevel();
4169 #endif // FEATURE_STACK_FP_X87
4171 bool bReverseInAssignment = false;
4172 if (kind & GTK_ASGOP)
4174 GenTreePtr op1Val = op1;
4176 if (tree->gtOper == GT_ASG)
4178 // Skip over the GT_IND/GT_ADDR tree (if one exists)
4180 if ((op1->gtOper == GT_IND) && (op1->gtOp.gtOp1->gtOper == GT_ADDR))
4182 op1Val = op1->gtOp.gtOp1->gtOp.gtOp1;
4186 switch (op1Val->gtOper)
4190 // If we have any side effects on the GT_IND child node
4191 // we have to evaluate op1 first
4192 if (op1Val->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT)
4195 // In case op2 assigns to a local var that is used in op1Val, we have to evaluate op1Val first.
4196 if (op2->gtFlags & GTF_ASG)
4199 // If op2 is simple then evaluate op1 first
4201 if (op2->OperKind() & GTK_LEAF)
4204 // fall through and set GTF_REVERSE_OPS
4209 // We evaluate op2 before op1
4210 bReverseInAssignment = true;
4211 tree->gtFlags |= GTF_REVERSE_OPS;
4218 else if (kind & GTK_RELOP)
4220 /* Float compares remove both operands from the FP stack */
4221 /* Also FP comparison uses EAX for flags */
4223 if (varTypeIsFloating(op1->TypeGet()))
4225 #if FEATURE_STACK_FP_X87
4226 codeGen->genDecrementFPstkLevel(2);
4227 #endif // FEATURE_STACK_FP_X87
4228 #ifdef _TARGET_XARCH_
4233 #if CPU_LONG_USES_REGPAIR
4234 if (varTypeIsLong(op1->TypeGet()))
4236 costEx *= 2; // Longs are twice as expensive
4240 if ((tree->gtFlags & GTF_RELOP_JMP_USED) == 0)
4242 /* Using a setcc instruction is more expensive */
4247 /* Check for other interesting cases */
4260 /* Variable sized shifts are more expensive and use REG_SHIFT */
4262 if (!op2->IsCnsIntOrI())
4265 if (REG_SHIFT != REG_NA)
4270 #ifndef _TARGET_64BIT_
4271 // Variable sized LONG shifts require the use of a helper call
4273 if (tree->gtType == TYP_LONG)
4277 costEx += 3 * IND_COST_EX;
4279 ftreg |= RBM_CALLEE_TRASH;
4281 #endif // !_TARGET_64BIT_
4288 switch (tree->gtIntrinsic.gtIntrinsicId)
4290 case CORINFO_INTRINSIC_Atan2:
4291 case CORINFO_INTRINSIC_Pow:
4292 // These math intrinsics are actually implemented by user calls.
4293 // Increase the Sethi 'complexity' by two to reflect the argument
4294 // register requirement.
4298 assert(!"Unknown binary GT_INTRINSIC operator");
4308 /* We need to evalutate constants later as many places in codegen
4309 can't handle op1 being a constant. This is normally naturally
4310 enforced as constants have the least level of 0. However,
4311 sometimes we end up with a tree like "cns1 < nop(cns2)". In
4312 such cases, both sides have a level of 0. So encourage constants
4313 to be evaluated last in such cases */
4315 if ((level == 0) && (level == lvl2) &&
4316 (op1->OperKind() & GTK_CONST) &&
4317 (tree->OperIsCommutative() || tree->OperIsCompare()))
4322 /* We try to swap operands if the second one is more expensive */
4326 if (tree->gtFlags & GTF_REVERSE_OPS)
4337 if (fgOrder == FGOrderLinear)
4339 // Don't swap anything if we're in linear order; we're really just interested in the costs.
4342 else if (bReverseInAssignment)
4344 // Assignments are special, we want the reverseops flags
4345 // so if possible it was set above.
4350 if (tree->gtFlags & GTF_REVERSE_OPS)
4352 tryToSwap = (level > lvl2);
4356 tryToSwap = (level < lvl2);
4359 // Try to force extra swapping when in the stress mode:
4360 if (compStressCompile(STRESS_REVERSE_FLAG, 60) &&
4361 ((tree->gtFlags & GTF_REVERSE_OPS) == 0) &&
4362 ((op2->OperKind() & GTK_CONST) == 0) )
4371 bool canSwap = gtCanSwapOrder(opA, opB);
4375 /* Can we swap the order by commuting the operands? */
4385 if (GenTree::SwapRelop(oper) != oper)
4387 // SetOper will obliterate the VN for the underlying expression.
4388 // If we're in VN CSE phase, we don't want to lose that information,
4389 // so save the value numbers and put them back after the SetOper.
4390 ValueNumPair vnp = tree->gtVNPair;
4391 tree->SetOper(GenTree::SwapRelop(oper));
4392 if (optValnumCSE_phase)
4394 tree->gtVNPair = vnp;
4407 /* Swap the operands */
4409 tree->gtOp.gtOp1 = op2;
4410 tree->gtOp.gtOp2 = op1;
4412 #if FEATURE_STACK_FP_X87
4413 /* We may have to recompute FP levels */
4414 if (op1->gtFPlvl || op2->gtFPlvl)
4415 gtFPstLvlRedo = true;
4416 #endif // FEATURE_STACK_FP_X87
4428 #ifdef LEGACY_BACKEND
4429 // For LSRA we require that LclVars be "evaluated" just prior to their use,
4430 // so that if they must be reloaded, it is done at the right place.
4431 // This means that we allow reverse evaluation for all BINOPs.
4432 // (Note that this doesn't affect the order of the operands in the instruction).
4435 #endif // LEGACY_BACKEND
4441 /* Mark the operand's evaluation order to be swapped */
4442 if (tree->gtFlags & GTF_REVERSE_OPS)
4444 tree->gtFlags &= ~GTF_REVERSE_OPS;
4448 tree->gtFlags |= GTF_REVERSE_OPS;
4451 #if FEATURE_STACK_FP_X87
4452 /* We may have to recompute FP levels */
4453 if (op1->gtFPlvl || op2->gtFPlvl)
4454 gtFPstLvlRedo = true;
4455 #endif // FEATURE_STACK_FP_X87
4462 /* Swap the level counts */
4463 if (tree->gtFlags & GTF_REVERSE_OPS)
4472 /* Compute the sethi number for this binary operator */
4478 else if (level == lvl2)
4486 /* See what kind of a special operator we have here */
4490 unsigned lvl2; // Scratch variable
4494 assert(tree->gtFlags & GTF_CALL);
4500 /* Evaluate the 'this' argument, if present */
4502 if (tree->gtCall.gtCallObjp)
4504 GenTreePtr thisVal = tree->gtCall.gtCallObjp;
4506 lvl2 = gtSetEvalOrder(thisVal);
4507 if (level < lvl2) level = lvl2;
4508 costEx += thisVal->gtCostEx;
4509 costSz += thisVal->gtCostSz + 1;
4510 ftreg |= thisVal->gtRsvdRegs;
4513 /* Evaluate the arguments, right to left */
4515 if (tree->gtCall.gtCallArgs)
4517 #if FEATURE_STACK_FP_X87
4518 FPlvlSave = codeGen->genGetFPstkLevel();
4519 #endif // FEATURE_STACK_FP_X87
4520 lvl2 = gtSetListOrder(tree->gtCall.gtCallArgs, false);
4521 if (level < lvl2) level = lvl2;
4522 costEx += tree->gtCall.gtCallArgs->gtCostEx;
4523 costSz += tree->gtCall.gtCallArgs->gtCostSz;
4524 ftreg |= tree->gtCall.gtCallArgs->gtRsvdRegs;
4525 #if FEATURE_STACK_FP_X87
4526 codeGen->genResetFPstkLevel(FPlvlSave);
4527 #endif // FEATURE_STACK_FP_X87
4530 /* Evaluate the temp register arguments list
4531 * This is a "hidden" list and its only purpose is to
4532 * extend the life of temps until we make the call */
4534 if (tree->gtCall.gtCallLateArgs)
4536 #if FEATURE_STACK_FP_X87
4537 FPlvlSave = codeGen->genGetFPstkLevel();
4538 #endif // FEATURE_STACK_FP_X87
4539 lvl2 = gtSetListOrder(tree->gtCall.gtCallLateArgs, true);
4540 if (level < lvl2) level = lvl2;
4541 costEx += tree->gtCall.gtCallLateArgs->gtCostEx;
4542 costSz += tree->gtCall.gtCallLateArgs->gtCostSz;
4543 ftreg |= tree->gtCall.gtCallLateArgs->gtRsvdRegs;
4544 #if FEATURE_STACK_FP_X87
4545 codeGen->genResetFPstkLevel(FPlvlSave);
4546 #endif // FEATURE_STACK_FP_X87
4549 if (tree->gtCall.gtCallType == CT_INDIRECT)
4551 // pinvoke-calli cookie is a constant, or constant indirection
4552 assert(tree->gtCall.gtCallCookie == NULL ||
4553 tree->gtCall.gtCallCookie->gtOper == GT_CNS_INT ||
4554 tree->gtCall.gtCallCookie->gtOper == GT_IND);
4556 GenTreePtr indirect = tree->gtCall.gtCallAddr;
4558 lvl2 = gtSetEvalOrder(indirect);
4559 if (level < lvl2) level = lvl2;
4560 costEx += indirect->gtCostEx + IND_COST_EX;
4561 costSz += indirect->gtCostSz;
4562 ftreg |= indirect->gtRsvdRegs;
4567 if ((tree->gtFlags & GTF_CALL_VIRT_KIND_MASK) == GTF_CALL_VIRT_STUB)
4569 // We generate movw/movt/ldr
4570 costEx += (1 + IND_COST_EX);
4572 if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT)
4574 // Must use R12 for the ldr target -- REG_JUMP_THUNK_PARAM
4578 else if ((opts.eeFlags & CORJIT_FLG_PREJIT) == 0)
4585 #ifdef _TARGET_XARCH_
4592 unsigned callKind; callKind = (tree->gtFlags & GTF_CALL_VIRT_KIND_MASK);
4594 /* Virtual calls are a bit more expensive */
4595 if (callKind != GTF_CALL_NONVIRT)
4597 costEx += 2 * IND_COST_EX;
4601 /* Virtual stub calls also must reserve the VIRTUAL_STUB_PARAM reg */
4602 if (callKind == GTF_CALL_VIRT_STUB)
4604 ftreg |= RBM_VIRTUAL_STUB_PARAM;
4607 #ifdef FEATURE_READYTORUN_COMPILER
4608 #ifdef _TARGET_ARM64_
4609 if (tree->gtCall.IsR2RRelativeIndir())
4611 ftreg |= RBM_R2R_INDIRECT_PARAM;
4616 // Normally function calls don't preserve caller save registers
4617 // and thus are much more expensive.
4618 // However a few function calls do preserve these registers
4619 // such as the GC WriteBarrier helper calls.
4621 #if GTF_CALL_REG_SAVE
4622 if (!(tree->gtFlags & GTF_CALL_REG_SAVE))
4626 costEx += 3 * IND_COST_EX;
4627 ftreg |= RBM_CALLEE_TRASH;
4630 #if FEATURE_STACK_FP_X87
4631 if (isflt) codeGen->genIncrementFPstkLevel();
4632 #endif // FEATURE_STACK_FP_X87
4638 level = gtSetEvalOrder(tree->gtArrElem.gtArrObj);
4639 costEx = tree->gtArrElem.gtArrObj->gtCostEx;
4640 costSz = tree->gtArrElem.gtArrObj->gtCostSz;
4643 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
4645 lvl2 = gtSetEvalOrder(tree->gtArrElem.gtArrInds[dim]);
4646 if (level < lvl2) level = lvl2;
4647 costEx += tree->gtArrElem.gtArrInds[dim]->gtCostEx;
4648 costSz += tree->gtArrElem.gtArrInds[dim]->gtCostSz;
4651 #if FEATURE_STACK_FP_X87
4652 if (isflt) codeGen->genIncrementFPstkLevel();
4653 #endif // FEATURE_STACK_FP_X87
4654 level += tree->gtArrElem.gtArrRank;
4655 costEx += 2 + (tree->gtArrElem.gtArrRank * (IND_COST_EX+1));
4656 costSz += 2 + (tree->gtArrElem.gtArrRank * 2);
4660 level = gtSetEvalOrder(tree->gtArrOffs.gtOffset);
4661 costEx = tree->gtArrOffs.gtOffset->gtCostEx;
4662 costSz = tree->gtArrOffs.gtOffset->gtCostSz;
4663 lvl2 = gtSetEvalOrder(tree->gtArrOffs.gtIndex);
4664 level = max(level, lvl2);
4665 costEx += tree->gtArrOffs.gtIndex->gtCostEx;
4666 costSz += tree->gtArrOffs.gtIndex->gtCostSz;
4667 lvl2 = gtSetEvalOrder(tree->gtArrOffs.gtArrObj);
4668 level = max(level, lvl2);
4669 costEx += tree->gtArrOffs.gtArrObj->gtCostEx;
4670 costSz += tree->gtArrOffs.gtArrObj->gtCostSz;
4675 level = gtSetEvalOrder(tree->gtCmpXchg.gtOpLocation);
4676 costSz = tree->gtCmpXchg.gtOpLocation->gtCostSz;
4678 lvl2 = gtSetEvalOrder(tree->gtCmpXchg.gtOpValue);
4679 if (level < lvl2) level = lvl2;
4680 costSz += tree->gtCmpXchg.gtOpValue->gtCostSz;
4682 lvl2 = gtSetEvalOrder(tree->gtCmpXchg.gtOpComparand);
4683 if (level < lvl2) level = lvl2;
4684 costSz += tree->gtCmpXchg.gtOpComparand->gtCostSz;
4686 costEx = MAX_COST; //Seriously, what could be more expensive than lock cmpxchg?
4687 costSz += 5; //size of lock cmpxchg [reg+C], reg
4688 #ifdef _TARGET_XARCH_
4689 ftreg |= RBM_EAX; //cmpxchg must be evaluated into eax.
4693 case GT_ARR_BOUNDS_CHECK:
4696 #endif // FEATURE_SIMD
4697 costEx = 4; // cmp reg,reg and jae throw (not taken)
4698 costSz = 7; // jump to cold section
4700 level = gtSetEvalOrder(tree->gtBoundsChk.gtArrLen);
4701 costEx += tree->gtBoundsChk.gtArrLen->gtCostEx;
4702 costSz += tree->gtBoundsChk.gtArrLen->gtCostSz;
4704 lvl2 = gtSetEvalOrder(tree->gtBoundsChk.gtIndex);
4705 if (level < lvl2) level = lvl2;
4706 costEx += tree->gtBoundsChk.gtIndex->gtCostEx;
4707 costSz += tree->gtBoundsChk.gtIndex->gtCostSz;
4715 printf("unexpected operator in this tree:\n");
4719 NO_WAY("unexpected operator");
4724 #if FEATURE_STACK_FP_X87
4725 // printf("[FPlvl=%2u] ", genGetFPstkLevel()); gtDispTree(tree, 0, true);
4726 noway_assert((unsigned char)codeGen->genFPstkLevel == codeGen->genFPstkLevel);
4727 tree->gtFPlvl = (unsigned char)codeGen->genFPstkLevel;
4729 if (codeGen->genFPstkLevel > tmpDoubleSpillMax)
4730 tmpDoubleSpillMax = codeGen->genFPstkLevel;
4731 #endif // FEATURE_STACK_FP_X87
4733 tree->gtRsvdRegs = (regMaskSmall)ftreg;
4735 // Some path through this function must have set the costs.
4736 assert(costEx != -1);
4737 assert(costSz != -1);
4739 tree->SetCosts(costEx, costSz);
4744 #pragma warning(pop)
4747 #if FEATURE_STACK_FP_X87
4749 /*****************************************************************************/
4750 void Compiler::gtComputeFPlvls(GenTreePtr tree)
4755 unsigned savFPstkLevel;
4758 noway_assert(tree->gtOper != GT_STMT);
4760 /* Figure out what kind of a node we have */
4762 oper = tree->OperGet();
4763 kind = tree->OperKind();
4764 isflt = varTypeIsFloating(tree->TypeGet()) ? 1 : 0;
4766 /* Is this a constant or leaf node? */
4768 if (kind & (GTK_CONST|GTK_LEAF))
4770 codeGen->genFPstkLevel += isflt;
4774 /* Is it a 'simple' unary/binary operator? */
4776 if (kind & GTK_SMPOP)
4778 GenTreePtr op1 = tree->gtOp.gtOp1;
4779 GenTreePtr op2 = tree->gtGetOp2();
4781 /* Check for some special cases */
4787 gtComputeFPlvls(op1);
4789 /* Indirect loads of FP values push a new value on the FP stack */
4791 codeGen->genFPstkLevel += isflt;
4796 gtComputeFPlvls(op1);
4798 /* Casts between non-FP and FP push on / pop from the FP stack */
4800 if (varTypeIsFloating(op1->TypeGet()))
4803 codeGen->genFPstkLevel--;
4808 codeGen->genFPstkLevel++;
4813 case GT_LIST: /* GT_LIST presumably part of an argument list */
4814 case GT_COMMA: /* Comma tosses the result of the left operand */
4816 savFPstkLevel = codeGen->genFPstkLevel;
4817 gtComputeFPlvls(op1);
4818 codeGen->genFPstkLevel = savFPstkLevel;
4821 gtComputeFPlvls(op2);
4834 gtComputeFPlvls(op2);
4840 gtComputeFPlvls(op1);
4841 if (oper == GT_ADDR)
4843 /* If the operand was floating point pop the value from the stack */
4844 if (varTypeIsFloating(op1->TypeGet()))
4846 noway_assert(codeGen->genFPstkLevel);
4847 codeGen->genFPstkLevel--;
4851 // This is a special case to handle the following
4852 // optimization: conv.i4(round.d(d)) -> round.i(d)
4854 if (oper== GT_INTRINSIC && tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Round &&
4855 tree->TypeGet()==TYP_INT)
4857 codeGen->genFPstkLevel--;
4863 /* FP assignments need a bit special handling */
4865 if (isflt && (kind & GTK_ASGOP))
4867 /* The target of the assignment won't get pushed */
4869 if (tree->gtFlags & GTF_REVERSE_OPS)
4871 gtComputeFPlvls(op2);
4872 gtComputeFPlvls(op1);
4874 codeGen->genFPstkLevel--;
4878 gtComputeFPlvls(op1);
4880 codeGen->genFPstkLevel--;
4881 gtComputeFPlvls(op2);
4884 codeGen->genFPstkLevel--;
4888 /* Here we have a binary operator; visit operands in proper order */
4890 if (tree->gtFlags & GTF_REVERSE_OPS)
4892 gtComputeFPlvls(op2);
4893 gtComputeFPlvls(op1);
4897 gtComputeFPlvls(op1);
4898 gtComputeFPlvls(op2);
4902 Binary FP operators pop 2 operands and produce 1 result;
4903 assignments consume 1 value and don't produce any.
4907 codeGen->genFPstkLevel--;
4909 /* Float compares remove both operands from the FP stack */
4911 if (kind & GTK_RELOP)
4913 if (varTypeIsFloating(op1->TypeGet()))
4914 codeGen->genFPstkLevel -= 2;
4920 /* See what kind of a special operator we have here */
4925 gtComputeFPlvls(tree->gtField.gtFldObj);
4926 codeGen->genFPstkLevel += isflt;
4931 if (tree->gtCall.gtCallObjp)
4932 gtComputeFPlvls(tree->gtCall.gtCallObjp);
4934 if (tree->gtCall.gtCallArgs)
4936 savFPstkLevel = codeGen->genFPstkLevel;
4937 gtComputeFPlvls(tree->gtCall.gtCallArgs);
4938 codeGen->genFPstkLevel = savFPstkLevel;
4941 if (tree->gtCall.gtCallLateArgs)
4943 savFPstkLevel = codeGen->genFPstkLevel;
4944 gtComputeFPlvls(tree->gtCall.gtCallLateArgs);
4945 codeGen->genFPstkLevel = savFPstkLevel;
4948 codeGen->genFPstkLevel += isflt;
4953 gtComputeFPlvls(tree->gtArrElem.gtArrObj);
4956 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
4957 gtComputeFPlvls(tree->gtArrElem.gtArrInds[dim]);
4959 /* Loads of FP values push a new value on the FP stack */
4960 codeGen->genFPstkLevel += isflt;
4964 //Evaluate the trees left to right
4965 gtComputeFPlvls(tree->gtCmpXchg.gtOpLocation);
4966 gtComputeFPlvls(tree->gtCmpXchg.gtOpValue);
4967 gtComputeFPlvls(tree->gtCmpXchg.gtOpComparand);
4968 noway_assert(!isflt);
4971 case GT_ARR_BOUNDS_CHECK:
4972 gtComputeFPlvls(tree->gtBoundsChk.gtArrLen);
4973 gtComputeFPlvls(tree->gtBoundsChk.gtIndex);
4974 noway_assert(!isflt);
4979 noway_assert(!"Unhandled special operator in gtComputeFPlvls()");
4986 noway_assert((unsigned char)codeGen->genFPstkLevel == codeGen->genFPstkLevel);
4988 tree->gtFPlvl = (unsigned char)codeGen->genFPstkLevel;
4991 #endif // FEATURE_STACK_FP_X87
4994 /*****************************************************************************
4996 * If the given tree is an integer constant that can be used
4997 * in a scaled index address mode as a multiplier (e.g. "[4*index]"), then return
4998 * the scale factor: 2, 4, or 8. Otherwise, return 0. Note that we never return 1,
4999 * to match the behavior of GetScaleIndexShf().
5002 unsigned GenTree::GetScaleIndexMul()
5004 if (IsCnsIntOrI() && jitIsScaleIndexMul(gtIntConCommon.IconValue()) && gtIntConCommon.IconValue()!=1)
5005 return (unsigned)gtIntConCommon.IconValue();
5010 /*****************************************************************************
5012 * If the given tree is the right-hand side of a left shift (that is,
5013 * 'y' in the tree 'x' << 'y'), and it is an integer constant that can be used
5014 * in a scaled index address mode as a multiplier (e.g. "[4*index]"), then return
5015 * the scale factor: 2, 4, or 8. Otherwise, return 0.
5018 unsigned GenTree::GetScaleIndexShf()
5020 if (IsCnsIntOrI() && jitIsScaleIndexShift(gtIntConCommon.IconValue()))
5021 return (unsigned)(1 << gtIntConCommon.IconValue());
5026 /*****************************************************************************
5028 * If the given tree is a scaled index (i.e. "op * 4" or "op << 2"), returns
5029 * the multiplier: 2, 4, or 8; otherwise returns 0. Note that "1" is never
5033 unsigned GenTree::GetScaledIndex()
5035 // with (!opts.OptEnabled(CLFLG_CONSTANTFOLD) we can have
5036 // CNS_INT * CNS_INT
5038 if (gtOp.gtOp1->IsCnsIntOrI())
5044 return gtOp.gtOp2->GetScaleIndexMul();
5047 return gtOp.gtOp2->GetScaleIndexShf();
5050 assert(!"GenTree::GetScaledIndex() called with illegal gtOper");
5057 /*****************************************************************************
5059 * Returns true if "addr" is a GT_ADD node, at least one of whose arguments is an integer (<= 32 bit)
5060 * constant. If it returns true, it sets "*offset" to (one of the) constant value(s), and
5061 * "*addr" to the other argument.
5064 bool GenTree::IsAddWithI32Const(GenTreePtr* addr, int* offset)
5066 if (OperGet() == GT_ADD)
5068 if (gtOp.gtOp1->IsIntCnsFitsInI32())
5070 *offset = (int)gtOp.gtOp1->gtIntCon.gtIconVal;
5074 else if (gtOp.gtOp2->IsIntCnsFitsInI32())
5076 *offset = (int)gtOp.gtOp2->gtIntCon.gtIconVal;
5085 //------------------------------------------------------------------------
5086 // InsertAfterSelf: Insert 'node' after this node in execution order.
5087 // If 'stmt' is not nullptr, then it is the parent statement of 'this', and we can insert at the
5088 // end of the statement list. If 'stmt' is nullptr, we can't insert at the end of the statement list.
5091 // 'node' - The node to insert. We only insert a node, not a whole tree.
5092 // 'stmt' - Optional. If set, the parent statement of 'this'.
5098 // 'node' is a single node to insert, not a tree to insert.
5101 // Use Compiler::fgInsertTreeInListAfter() to insert a whole tree.
5103 void GenTree::InsertAfterSelf(GenTree* node, GenTreeStmt* stmt /* = nullptr */)
5105 // statements have crazy requirements
5106 assert(this->gtOper != GT_STMT);
5108 node->gtNext = this->gtNext;
5109 node->gtPrev = this;
5111 // Insertion at beginning and end of block are special cases
5112 // and require more context.
5113 if (this->gtNext == nullptr)
5115 assert(stmt != nullptr);
5116 assert(stmt->gtOper == GT_STMT);
5117 assert(stmt->gtStmtExpr == this);
5118 stmt->gtStmtExpr = node;
5122 this->gtNext->gtPrev = node;
5125 this->gtNext = node;
5128 //------------------------------------------------------------------------
5129 // gtGetChildPointer: If 'parent' is the parent of this node, return the pointer
5130 // to the child node so that it can be modified; otherwise, return nullptr.
5133 // parent - The possible parent of this node
5136 // If "child" is a child of "parent", returns a pointer to the child node in the parent
5137 // (i.e. a pointer to a GenTree pointer).
5138 // Otherwise, returns nullptr.
5141 // 'parent' must be non-null
5144 // When FEATURE_MULTIREG_ARGS is defined we can get here with GT_LDOBJ tree.
5145 // This happens when we have a struct that is passed in multiple registers.
5147 // Also note that when FEATURE_UNIX_AMD64_STRUCT_PASSING is defined the GT_LDOBJ
5148 // later gets converted to a GT_LIST with two GT_LCL_FLDs in Lower/LowerXArch.
5151 GenTreePtr* GenTree::gtGetChildPointer(GenTreePtr parent)
5154 switch (parent->OperGet())
5157 if (!parent->OperIsSimple()) return nullptr;
5158 if (this == parent->gtOp.gtOp1) return &(parent->gtOp.gtOp1);
5159 if (this == parent->gtOp.gtOp2) return &(parent->gtOp.gtOp2);
5162 #if !FEATURE_MULTIREG_ARGS
5163 // Note that when FEATURE_MULTIREG_ARGS==1
5164 // a GT_OBJ node is handled above by the default case
5166 // Any GT_OBJ with a field must be lowered before this point.
5167 noway_assert(!"GT_OBJ encountered in GenTree::gtGetChildPointer");
5169 #endif // !FEATURE_MULTIREG_ARGS
5172 if (this == parent->gtCmpXchg.gtOpLocation) return &(parent->gtCmpXchg.gtOpLocation);
5173 if (this == parent->gtCmpXchg.gtOpValue) return &(parent->gtCmpXchg.gtOpValue);
5174 if (this == parent->gtCmpXchg.gtOpComparand) return &(parent->gtCmpXchg.gtOpComparand);
5177 case GT_ARR_BOUNDS_CHECK:
5180 #endif // FEATURE_SIMD
5181 if (this == parent->gtBoundsChk.gtArrLen) return &(parent->gtBoundsChk.gtArrLen);
5182 if (this == parent->gtBoundsChk.gtIndex) return &(parent->gtBoundsChk.gtIndex);
5183 if (this == parent->gtBoundsChk.gtIndRngFailBB) return &(parent->gtBoundsChk.gtIndRngFailBB);
5187 if (this == parent->gtArrElem.gtArrObj) return &(parent->gtArrElem.gtArrObj);
5188 for (int i = 0; i < GT_ARR_MAX_RANK; i++)
5189 if (this == parent->gtArrElem.gtArrInds[i]) return &(parent->gtArrElem.gtArrInds[i]);
5193 if (this == parent->gtArrOffs.gtOffset) return &(parent->gtArrOffs.gtOffset);
5194 if (this == parent->gtArrOffs.gtIndex) return &(parent->gtArrOffs.gtIndex);
5195 if (this == parent->gtArrOffs.gtArrObj) return &(parent->gtArrOffs.gtArrObj);
5199 if (this == parent->AsField()->gtFldObj) return &(parent->AsField()->gtFldObj);
5203 if (this == parent->gtRetExpr.gtInlineCandidate) return &(parent->gtRetExpr.gtInlineCandidate);
5208 GenTreeCall* call = parent->AsCall();
5210 if (this == call->gtCallObjp) return &(call->gtCallObjp);
5211 if (this == call->gtCallArgs) return reinterpret_cast<GenTreePtr*>(&(call->gtCallArgs));
5212 if (this == call->gtCallLateArgs) return reinterpret_cast<GenTreePtr*>(&(call->gtCallLateArgs));
5213 if (this == call->gtControlExpr) return &(call->gtControlExpr);
5214 if (call->gtCallType == CT_INDIRECT)
5216 if (this == call->gtCallCookie) return &(call->gtCallCookie);
5217 if (this == call->gtCallAddr) return &(call->gtCallAddr);
5223 noway_assert(!"Illegal node for gtGetChildPointer()");
5230 //------------------------------------------------------------------------
5231 // gtGetParent: Get the parent of this node, and optionally capture the
5232 // pointer to the child so that it can be modified.
5236 // parentChildPointer - A pointer to a GenTreePtr* (yes, that's three
5237 // levels, i.e. GenTree ***), which if non-null,
5238 // will be set to point to the field in the parent
5239 // that points to this node.
5241 // Return value - The parent of this node.
5245 // This requires that the execution order must be defined (i.e. gtSetEvalOrder() has been called).
5246 // To enable the child to be replaced, it accepts an argument, parentChildPointer that, if non-null,
5247 // will be set to point to the child pointer in the parent that points to this node.
5249 GenTreePtr GenTree::gtGetParent(GenTreePtr** parentChildPtrPtr)
5251 // Find the parent node; it must be after this node in the execution order.
5252 GenTreePtr * parentChildPtr = nullptr;
5254 for (parent = gtNext; parent != nullptr; parent = parent->gtNext)
5256 parentChildPtr = gtGetChildPointer(parent);
5257 if (parentChildPtr != nullptr) break;
5259 if (parentChildPtrPtr != nullptr) *parentChildPtrPtr = parentChildPtr;
5263 /*****************************************************************************
5265 * Returns true if the given operator may cause an exception.
5268 bool GenTree::OperMayThrow()
5279 /* Division with a non-zero, non-minus-one constant does not throw an exception */
5283 if (varTypeIsFloating(op->TypeGet()))
5284 return false; // Floating point division does not throw.
5286 // For integers only division by 0 or by -1 can throw
5287 if (op->IsIntegralConst() && !op->IsIntegralConst(0) && !op->IsIntegralConst(-1))
5294 /* Indirections of handles are known to be safe */
5295 if (op->gtOper == GT_CNS_INT)
5297 if (op->IsIconHandle())
5299 /* No exception is thrown on this indirection */
5303 if (this->gtFlags & GTF_IND_NONFAULTING)
5307 // Non-Null AssertionProp will remove the GTF_EXCEPT flag and mark the GT_IND with GTF_ORDER_SIDEEFF flag
5308 if ((this->gtFlags & GTF_ALL_EFFECT) == GTF_ORDER_SIDEEFF)
5316 // If this is an intrinsic that represents the object.GetType(), it can throw an NullReferenceException.
5317 // Report it as may throw.
5318 // Note: Some of the rest of the existing intrinsics could potentially throw an exception (for example
5319 // the array and string element access ones). They are handled differently than the GetType intrinsic
5320 // and are not marked with GTF_EXCEPT. If these are revisited at some point to be marked as GTF_EXCEPT,
5321 // the code below might need to be specialized to handle them properly.
5322 if ((this->gtFlags & GTF_EXCEPT) != 0)
5329 case GT_ARR_BOUNDS_CHECK:
5340 #endif // FEATURE_SIMD
5346 /* Overflow arithmetic operations also throw exceptions */
5354 #if DEBUGGABLE_GENTREE
5356 GenTree::VtablePtr GenTree::s_vtablesForOpers[] = { NULL };
5357 GenTree::VtablePtr GenTree::s_vtableForOp = NULL;
5359 GenTree::VtablePtr GenTree::GetVtableForOper(genTreeOps oper)
5361 noway_assert (oper < GT_COUNT);
5363 if (s_vtablesForOpers[oper] != NULL) return s_vtablesForOpers[oper];
5365 VtablePtr res = NULL;
5368 #define GTSTRUCT_0(nm, tag) /*handle explicitly*/
5369 #define GTSTRUCT_1(nm, tag) case tag: { GenTree##nm gt; res = *reinterpret_cast<VtablePtr*>(>); } break;
5370 #define GTSTRUCT_2(nm, tag, tag2) /*handle explicitly*/
5371 #define GTSTRUCT_3(nm, tag, tag2, tag3) /*handle explicitly*/
5372 #define GTSTRUCT_4(nm, tag, tag2, tag3, tag4) /*handle explicitly*/
5373 #define GTSTRUCT_N(nm, ...) /*handle explicitly*/
5374 #include "gtstructs.h"
5375 // If FEATURE_EH_FUNCLETS is set, then GT_JMP becomes the only member of Val, and will be handled above.
5376 #if !FEATURE_EH_FUNCLETS
5379 { GenTreeVal gt(GT_JMP, TYP_INT, 0); res = *reinterpret_cast<VtablePtr*>(>); break; }
5383 // Should be unary or binary op.
5384 if (s_vtableForOp == NULL)
5386 unsigned opKind = OperKind(oper);
5387 assert(!IsExOp(opKind));
5388 assert(OperIsSimple(oper) || OperIsLeaf(oper));
5389 // Need to provide non-null operands.
5390 Compiler* comp = (Compiler*)_alloca(sizeof(Compiler));
5391 GenTreeIntCon dummyOp(TYP_INT, 0);
5392 GenTreeOp gt(oper, TYP_INT, &dummyOp, ((opKind & GTK_UNOP) ? NULL : &dummyOp));
5393 s_vtableForOp = *reinterpret_cast<VtablePtr*>(>);
5395 res = s_vtableForOp;
5399 s_vtablesForOpers[oper] = res;
5403 void GenTree::SetVtableForOper(genTreeOps oper)
5405 *reinterpret_cast<VtablePtr*>(this) = GetVtableForOper(oper);
5407 #endif // DEBUGGABLE_GENTREE
5409 GenTreePtr Compiler::gtNewOperNode(genTreeOps oper,
5410 var_types type, GenTreePtr op1,
5413 assert(op1 != NULL);
5414 assert(op2 != NULL);
5416 // We should not be allocating nodes that extend GenTreeOp with this;
5417 // should call the appropriate constructor for the extended type.
5418 assert(!GenTree::IsExOp(GenTree::OperKind(oper)));
5420 GenTreePtr node = new(this, oper) GenTreeOp(oper, type, op1, op2);
5425 GenTreePtr Compiler::gtNewQmarkNode(var_types type, GenTreePtr cond, GenTreePtr colon)
5427 compQmarkUsed = true;
5428 GenTree* result = new(this, GT_QMARK) GenTreeQmark(type, cond, colon, this);
5430 if (compQmarkRationalized)
5432 fgCheckQmarkAllowedForm(result);
5438 GenTreeQmark::GenTreeQmark(var_types type, GenTreePtr cond, GenTreePtr colonOp, Compiler* comp) :
5439 GenTreeOp(GT_QMARK, type, cond, colonOp),
5440 gtThenLiveSet(VarSetOps::UninitVal()),
5441 gtElseLiveSet(VarSetOps::UninitVal())
5443 // These must follow a specific form.
5444 assert(cond != NULL && cond->TypeGet() == TYP_INT);
5445 assert(colonOp != NULL && colonOp->OperGet() == GT_COLON);
5447 comp->impInlineRoot()->compQMarks->Push(this);
5451 GenTreeIntCon* Compiler::gtNewIconNode(ssize_t value, var_types type)
5453 return new(this, GT_CNS_INT) GenTreeIntCon(type, value);
5456 // return a new node representing the value in a physical register
5457 GenTree* Compiler::gtNewPhysRegNode(regNumber reg, var_types type)
5459 assert(genIsValidIntReg(reg) || (reg == REG_SPBASE));
5460 GenTree *result = new(this, GT_PHYSREG) GenTreePhysReg(reg, type);
5464 // Return a new node representing a store of a value to a physical register
5465 // modifies: child's gtRegNum
5466 GenTree* Compiler::gtNewPhysRegNode(regNumber reg, GenTree* src)
5468 assert(genIsValidIntReg(reg));
5469 GenTree *result = new(this, GT_PHYSREGDST) GenTreeOp(GT_PHYSREGDST, TYP_I_IMPL, src, nullptr);
5470 result->gtRegNum = reg;
5471 src->gtRegNum = reg;
5475 #ifndef LEGACY_BACKEND
5476 GenTreePtr Compiler::gtNewJmpTableNode()
5478 GenTreePtr node = new(this, GT_JMPTABLE) GenTreeJumpTable(TYP_INT);
5479 node->gtJumpTable.gtJumpTableAddr = 0;
5482 #endif // !LEGACY_BACKEND
5484 /*****************************************************************************
5486 * Converts an annotated token into an icon flags (so that we will later be
5487 * able to tell the type of the handle that will be embedded in the icon
5491 unsigned Compiler::gtTokenToIconFlags(unsigned token)
5495 switch (TypeFromToken(token))
5500 flags = GTF_ICON_CLASS_HDL;
5504 flags = GTF_ICON_METHOD_HDL;
5508 flags = GTF_ICON_FIELD_HDL;
5512 flags = GTF_ICON_TOKEN_HDL;
5519 /*****************************************************************************
5521 * Allocates a integer constant entry that represents a HANDLE to something.
5522 * It may not be allowed to embed HANDLEs directly into the JITed code (for eg,
5523 * as arguments to JIT helpers). Get a corresponding value that can be embedded.
5524 * If the handle needs to be accessed via an indirection, pValue points to it.
5527 GenTreePtr Compiler::gtNewIconEmbHndNode(void * value,
5532 void * compileTimeHandle)
5536 assert((!value) != (!pValue));
5540 node = gtNewIconHandleNode((size_t)value, flags, /*fieldSeq*/FieldSeqStore::NotAField(), handle1, handle2);
5541 node->gtIntCon.gtCompileTimeHandle = (size_t) compileTimeHandle;
5545 node = gtNewIconHandleNode((size_t)pValue, flags, /*fieldSeq*/FieldSeqStore::NotAField(), handle1, handle2);
5546 node->gtIntCon.gtCompileTimeHandle = (size_t) compileTimeHandle;
5547 node = gtNewOperNode(GT_IND, TYP_I_IMPL, node);
5554 /*****************************************************************************/
5555 GenTreePtr Compiler::gtNewStringLiteralNode(InfoAccessType iat, void * pValue)
5557 GenTreePtr tree = NULL;
5561 case IAT_VALUE: // The info value is directly available
5562 tree = gtNewIconEmbHndNode(pValue, NULL, GTF_ICON_STR_HDL);
5563 tree->gtType = TYP_REF;
5564 tree = gtNewOperNode(GT_NOP, TYP_REF, tree); // prevents constant folding
5567 case IAT_PVALUE: // The value needs to be accessed via an indirection
5568 tree = gtNewIconHandleNode((size_t)pValue, GTF_ICON_STR_HDL);
5569 // An indirection of a string handle can't cause an exception so don't set GTF_EXCEPT
5570 tree = gtNewOperNode(GT_IND, TYP_REF, tree);
5571 tree->gtFlags |= GTF_GLOB_REF;
5574 case IAT_PPVALUE: // The value needs to be accessed via a double indirection
5575 tree = gtNewIconHandleNode((size_t)pValue, GTF_ICON_PSTR_HDL);
5576 tree = gtNewOperNode(GT_IND, TYP_I_IMPL, tree);
5577 tree->gtFlags |= GTF_IND_INVARIANT;
5578 // An indirection of a string handle can't cause an exception so don't set GTF_EXCEPT
5579 tree = gtNewOperNode(GT_IND, TYP_REF, tree);
5580 tree->gtFlags |= GTF_GLOB_REF;
5584 assert(!"Unexpected InfoAccessType");
5590 /*****************************************************************************/
5592 GenTreePtr Compiler::gtNewLconNode(__int64 value)
5594 #ifdef _TARGET_64BIT_
5595 GenTreePtr node = new(this, GT_CNS_INT) GenTreeIntCon(TYP_LONG, value);
5597 GenTreePtr node = new(this, GT_CNS_LNG) GenTreeLngCon(value);
5604 GenTreePtr Compiler::gtNewDconNode(double value)
5606 GenTreePtr node = new(this, GT_CNS_DBL) GenTreeDblCon(value);
5612 GenTreePtr Compiler::gtNewSconNode(int CPX, CORINFO_MODULE_HANDLE scpHandle)
5615 #if SMALL_TREE_NODES
5617 /* 'GT_CNS_STR' nodes later get transformed into 'GT_CALL' */
5619 assert(GenTree::s_gtNodeSizes[GT_CALL] > GenTree::s_gtNodeSizes[GT_CNS_STR]);
5621 GenTreePtr node = new(this, GT_CALL) GenTreeStrCon(CPX, scpHandle
5622 DEBUGARG(/*largeNode*/true));
5624 GenTreePtr node = new(this, GT_CNS_STR) GenTreeStrCon(CPX, scpHandle
5625 DEBUGARG(/*largeNode*/true));
5632 GenTreePtr Compiler::gtNewZeroConNode(var_types type)
5638 zero = gtNewIconNode(0);
5645 zero = gtNewIconNode(0);
5646 zero->gtType = type;
5650 zero = gtNewLconNode(0);
5654 zero = gtNewDconNode(0.0);
5655 zero->gtType = type;
5659 zero = gtNewDconNode(0.0);
5663 assert(!"Bad type");
5670 GenTreePtr Compiler::gtNewOneConNode(var_types type)
5676 return gtNewIconNode(1);
5680 return gtNewLconNode(1);
5684 GenTreePtr one = gtNewDconNode(1.0);
5690 return gtNewDconNode(1.0);
5693 assert(!"Bad type");
5698 GenTreeCall* Compiler::gtNewIndCallNode(GenTreePtr addr,
5700 GenTreeArgList* args,
5701 IL_OFFSETX ilOffset)
5703 return gtNewCallNode(CT_INDIRECT,(CORINFO_METHOD_HANDLE)addr, type, args, ilOffset);
5706 GenTreeCall* Compiler::gtNewCallNode(gtCallTypes callType,
5707 CORINFO_METHOD_HANDLE callHnd,
5709 GenTreeArgList* args,
5710 IL_OFFSETX ilOffset)
5712 GenTreeCall* node = new(this, GT_CALL) GenTreeCall(genActualType(type));
5714 node->gtFlags |= (GTF_CALL|GTF_GLOB_REF);
5716 node->gtFlags |= (args->gtFlags & GTF_ALL_EFFECT);
5717 node->gtCallType = callType;
5718 node->gtCallMethHnd = callHnd;
5719 node->gtCallArgs = args;
5720 node->gtCallObjp = nullptr;
5721 node->fgArgInfo = nullptr;
5722 node->callSig = nullptr;
5723 node->gtRetClsHnd = nullptr;
5724 node->gtControlExpr = nullptr;
5725 node->gtCallMoreFlags = 0;
5727 if (callType == CT_INDIRECT)
5729 node->gtCallCookie = NULL;
5733 node->gtInlineCandidateInfo = NULL;
5735 node->gtCallLateArgs = nullptr;
5736 node->gtReturnType = type;
5738 #ifdef LEGACY_BACKEND
5739 node->gtCallRegUsedMask = RBM_NONE;
5740 #endif // LEGACY_BACKEND
5742 #ifdef FEATURE_READYTORUN_COMPILER
5743 node->gtCall.gtEntryPoint.addr = nullptr;
5746 #if defined(DEBUG) || defined(INLINE_DATA)
5747 // These get updated after call node is built.
5748 node->gtCall.gtInlineObservation = InlineObservation::CALLEE_UNUSED_INITIAL;
5749 node->gtCall.gtRawILOffset = BAD_IL_OFFSET;
5752 #ifdef DEBUGGING_SUPPORT
5753 // Spec: Managed Retval sequence points needs to be generated while generating debug info for debuggable code.
5755 // Implementation note: if not generating MRV info genCallSite2ILOffsetMap will be NULL and
5756 // codegen will pass BAD_IL_OFFSET as IL offset of a call node to emitter, which will cause emitter
5757 // not to emit IP mapping entry.
5758 if (opts.compDbgCode && opts.compDbgInfo)
5760 // Managed Retval - IL offset of the call. This offset is used to emit a
5761 // CALL_INSTRUCTION type sequence point while emitting corresponding native call.
5764 // a) (Opt) We need not store this offset if the method doesn't return a
5765 // value. Rather it can be made BAD_IL_OFFSET to prevent a sequence
5766 // point being emitted.
5768 // b) (Opt) Add new sequence points only if requested by debugger through
5769 // a new boundary type - ICorDebugInfo::BoundaryTypes
5770 if (genCallSite2ILOffsetMap == NULL)
5772 genCallSite2ILOffsetMap = new (getAllocator()) CallSiteILOffsetTable(getAllocator());
5775 // Make sure that there are no duplicate entries for a given call node
5777 assert(!genCallSite2ILOffsetMap->Lookup(node, &value));
5778 genCallSite2ILOffsetMap->Set(node, ilOffset);
5782 // Initialize gtOtherRegs
5783 node->ClearOtherRegs();
5785 // Initialize spill flags of gtOtherRegs
5786 node->ClearOtherRegFlags();
5791 GenTreePtr Compiler::gtNewLclvNode(unsigned lnum,
5795 // We need to ensure that all struct values are normalized.
5796 // It might be nice to assert this in general, but we have assignments of int to long.
5797 if (varTypeIsStruct(type))
5799 assert(type == lvaTable[lnum].lvType);
5801 GenTreePtr node = new(this, GT_LCL_VAR) GenTreeLclVar(type, lnum, ILoffs
5804 /* Cannot have this assert because the inliner uses this function
5805 * to add temporaries */
5807 //assert(lnum < lvaCount);
5812 GenTreePtr Compiler::gtNewLclLNode(unsigned lnum,
5816 // We need to ensure that all struct values are normalized.
5817 // It might be nice to assert this in general, but we have assignments of int to long.
5818 if (varTypeIsStruct(type))
5820 assert(type == lvaTable[lnum].lvType);
5822 #if SMALL_TREE_NODES
5823 /* This local variable node may later get transformed into a large node */
5825 // assert(GenTree::s_gtNodeSizes[GT_CALL] > GenTree::s_gtNodeSizes[GT_LCL_VAR]);
5827 GenTreePtr node = new(this, GT_CALL) GenTreeLclVar(type, lnum, ILoffs
5828 DEBUGARG(/*largeNode*/true));
5830 GenTreePtr node = new(this, GT_LCL_VAR) GenTreeLclVar(type, lnum, ILoffs
5831 DEBUGARG(/*largeNode*/true));
5837 GenTreeLclFld* Compiler::gtNewLclFldNode(unsigned lnum,
5841 GenTreeLclFld* node = new(this, GT_LCL_FLD) GenTreeLclFld(type, lnum, offset);
5843 /* Cannot have this assert because the inliner uses this function
5844 * to add temporaries */
5846 //assert(lnum < lvaCount);
5848 node->gtFieldSeq = FieldSeqStore::NotAField();
5854 GenTreePtr Compiler::gtNewInlineCandidateReturnExpr(GenTreePtr inlineCandidate,
5857 assert(GenTree::s_gtNodeSizes[GT_RET_EXPR] == TREE_NODE_SZ_LARGE);
5859 GenTreePtr node = new(this, GT_RET_EXPR) GenTreeRetExpr(type);
5861 node->gtRetExpr.gtInlineCandidate = inlineCandidate;
5863 if (varTypeIsStruct(inlineCandidate))
5865 node->gtRetExpr.gtRetClsHnd = gtGetStructHandle(inlineCandidate);
5868 // GT_RET_EXPR node eventually might be bashed back to GT_CALL (when inlining is aborted for example).
5869 // Therefore it should carry the GTF_CALL flag so that all the rules about spilling can apply to it as well.
5870 // For example, impImportLeave or CEE_POP need to spill GT_RET_EXPR before empty the evaluation stack.
5871 node->gtFlags |= GTF_CALL;
5876 GenTreeArgList* Compiler::gtNewListNode(GenTreePtr op1, GenTreeArgList* op2)
5878 assert((op1 != NULL) && (op1->OperGet() != GT_LIST));
5880 return new (this, GT_LIST) GenTreeArgList(op1, op2);
5884 /*****************************************************************************
5886 * Create a list out of one value.
5889 GenTreeArgList* Compiler::gtNewArgList(GenTreePtr arg)
5891 return new (this, GT_LIST) GenTreeArgList(arg);
5894 /*****************************************************************************
5896 * Create a list out of the two values.
5899 GenTreeArgList* Compiler::gtNewArgList(GenTreePtr arg1, GenTreePtr arg2)
5901 return new (this, GT_LIST) GenTreeArgList(arg1, gtNewArgList(arg2));
5904 /*****************************************************************************
5906 * Given a GT_CALL node, access the fgArgInfo and find the entry
5907 * that has the matching argNum and return the fgArgTableEntryPtr
5910 fgArgTabEntryPtr Compiler::gtArgEntryByArgNum(GenTreePtr call, unsigned argNum)
5912 noway_assert(call->IsCall());
5913 fgArgInfoPtr argInfo = call->gtCall.fgArgInfo;
5914 noway_assert(argInfo != NULL);
5916 unsigned argCount = argInfo->ArgCount();
5917 fgArgTabEntryPtr * argTable = argInfo->ArgTable();
5918 fgArgTabEntryPtr curArgTabEntry = NULL;
5920 for (unsigned i=0; i < argCount; i++)
5922 curArgTabEntry = argTable[i];
5923 if (curArgTabEntry->argNum == argNum)
5924 return curArgTabEntry;
5926 noway_assert(!"gtArgEntryByArgNum: argNum not found");
5930 /*****************************************************************************
5932 * Given a GT_CALL node, access the fgArgInfo and find the entry
5933 * that has the matching node and return the fgArgTableEntryPtr
5936 fgArgTabEntryPtr Compiler::gtArgEntryByNode(GenTreePtr call, GenTreePtr node)
5938 noway_assert(call->IsCall());
5939 fgArgInfoPtr argInfo = call->gtCall.fgArgInfo;
5940 noway_assert(argInfo != NULL);
5942 unsigned argCount = argInfo->ArgCount();
5943 fgArgTabEntryPtr * argTable = argInfo->ArgTable();
5944 fgArgTabEntryPtr curArgTabEntry = NULL;
5946 for (unsigned i=0; i < argCount; i++)
5948 curArgTabEntry = argTable[i];
5950 if (curArgTabEntry->node == node)
5952 return curArgTabEntry;
5955 else if (node->OperGet() == GT_RELOAD && node->gtOp.gtOp1 == curArgTabEntry->node)
5957 return curArgTabEntry;
5960 else if (curArgTabEntry->parent != NULL)
5962 assert(curArgTabEntry->parent->IsList());
5963 if (curArgTabEntry->parent->Current() == node)
5964 return curArgTabEntry;
5966 else // (curArgTabEntry->parent == NULL)
5968 if (call->gtCall.gtCallObjp == node)
5969 return curArgTabEntry;
5972 noway_assert(!"gtArgEntryByNode: node not found");
5976 /*****************************************************************************
5978 * Find and return the entry with the given "lateArgInx". Requires that one is found
5981 fgArgTabEntryPtr Compiler::gtArgEntryByLateArgIndex(GenTreePtr call, unsigned lateArgInx)
5983 noway_assert(call->IsCall());
5984 fgArgInfoPtr argInfo = call->gtCall.fgArgInfo;
5985 noway_assert(argInfo != NULL);
5987 unsigned argCount = argInfo->ArgCount();
5988 fgArgTabEntryPtr * argTable = argInfo->ArgTable();
5989 fgArgTabEntryPtr curArgTabEntry = NULL;
5991 for (unsigned i=0; i < argCount; i++)
5993 curArgTabEntry = argTable[i];
5994 if (curArgTabEntry->lateArgInx == lateArgInx)
5995 return curArgTabEntry;
5997 noway_assert(!"gtArgEntryByNode: node not found");
6002 /*****************************************************************************
6004 * Given an fgArgTabEntryPtr, return true if it is the 'this' pointer argument.
6006 bool Compiler::gtArgIsThisPtr(fgArgTabEntryPtr argEntry)
6008 return (argEntry->parent == NULL);
6011 /*****************************************************************************
6013 * Create a node that will assign 'src' to 'dst'.
6016 GenTreePtr Compiler::gtNewAssignNode(GenTreePtr dst, GenTreePtr src DEBUGARG(bool isPhiDefn))
6018 var_types type = dst->TypeGet();
6020 // ARM has HFA struct return values, HFA return values are received in registers from GT_CALL,
6021 // using struct assignment.
6023 assert(isPhiDefn || type != TYP_STRUCT || IsHfa(dst) || IsHfa(src));
6024 #elif defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
6025 // You need to use GT_COPYBLK for assigning structs
6026 // See impAssignStruct()
6027 assert(isPhiDefn || type != TYP_STRUCT || IsRegisterPassable(dst) || IsRegisterPassable(src));
6028 #else // !FEATURE_UNIX_AMD64_STRUCT_PASSING
6029 assert(isPhiDefn || type != TYP_STRUCT);
6032 /* Mark the target as being assigned */
6034 if ((dst->gtOper == GT_LCL_VAR) || (dst->OperGet() == GT_LCL_FLD))
6036 dst->gtFlags |= GTF_VAR_DEF;
6037 if (dst->IsPartialLclFld(this))
6039 // We treat these partial writes as combined uses and defs.
6040 dst->gtFlags |= GTF_VAR_USEASG;
6043 dst->gtFlags |= GTF_DONT_CSE;
6045 /* Create the assignment node */
6047 GenTreePtr asg = gtNewOperNode(GT_ASG, type, dst, src);
6049 /* Mark the expression as containing an assignment */
6051 asg->gtFlags |= GTF_ASG;
6056 // Creates a new Obj node.
6057 GenTreeObj* Compiler::gtNewObjNode(CORINFO_CLASS_HANDLE structHnd, GenTree* addr)
6059 var_types nodeType = impNormStructType(structHnd);
6060 assert(varTypeIsStruct(nodeType));
6061 return new (this, GT_OBJ) GenTreeObj(nodeType, addr, structHnd);
6064 // Creates a new CpObj node.
6065 // Parameters (exactly the same as MSIL CpObj):
6067 // dst - The target to copy the struct to
6068 // src - The source to copy the struct from
6069 // structHnd - A class token that represents the type of object being copied. May be null
6070 // if FEATURE_SIMD is enabled and the source has a SIMD type.
6071 // isVolatile - Is this marked as volatile memory?
6072 GenTreeBlkOp* Compiler::gtNewCpObjNode(GenTreePtr dst,
6074 CORINFO_CLASS_HANDLE structHnd,
6079 unsigned gcPtrCount = 0;
6080 BYTE * gcPtrs = nullptr;
6081 var_types type = TYP_STRUCT;
6083 GenTreePtr hndOrSize = nullptr;
6085 GenTreeBlkOp* result = nullptr;
6087 bool useCopyObj = false;
6089 // Intermediate SIMD operations may use SIMD types that are not used by the input IL.
6090 // In this case, the provided type handle will be null and the size of the copy will
6091 // be derived from the node's varType.
6092 if (structHnd == nullptr)
6095 assert(src->OperGet() == GT_ADDR);
6097 GenTree* srcValue = src->gtGetOp1();
6099 type = srcValue->TypeGet();
6100 assert(varTypeIsSIMD(type));
6102 size = genTypeSize(type);
6104 assert(!"structHnd should not be null if FEATURE_SIMD is not enabled!");
6109 // Get the size of the type
6110 size = info.compCompHnd->getClassSize(structHnd);
6112 if (size >= TARGET_POINTER_SIZE)
6114 slots = (unsigned)(roundUp(size, TARGET_POINTER_SIZE) / TARGET_POINTER_SIZE);
6115 gcPtrs = new (this, CMK_ASTNode) BYTE[slots];
6117 type = impNormStructType(structHnd, gcPtrs, &gcPtrCount);
6118 if (varTypeIsEnregisterableStruct(type))
6120 if (dst->OperGet() == GT_ADDR)
6122 GenTree* actualDst = dst->gtGetOp1();
6123 assert((actualDst->TypeGet() == type) || !varTypeIsEnregisterableStruct(actualDst));
6124 actualDst->gtType = type;
6126 if (src->OperGet() == GT_ADDR)
6128 GenTree* actualSrc = src->gtGetOp1();
6129 assert((actualSrc->TypeGet() == type) || !varTypeIsEnregisterableStruct(actualSrc));
6130 actualSrc->gtType = type;
6134 useCopyObj = gcPtrCount > 0;
6138 // If the class being copied contains any GC pointer we store a class handle
6139 // in the icon, otherwise we store the size in bytes to copy
6144 // This will treated as a cpobj as we need to note GC info.
6145 // Store the class handle and mark the node
6147 hndOrSize = gtNewIconHandleNode((size_t)structHnd, GTF_ICON_CLASS_HDL);
6148 result = new (this, GT_COPYOBJ) GenTreeCpObj(gcPtrCount, slots, gcPtrs);
6152 assert(gcPtrCount == 0);
6154 // Doesn't need GC info. Treat operation as a cpblk
6156 hndOrSize = gtNewIconNode(size);
6157 result = new (this, GT_COPYBLK) GenTreeCpBlk();
6158 result->gtBlkOpGcUnsafe = false;
6161 gtBlockOpInit(result, op, dst, src, hndOrSize, isVolatile);
6165 //------------------------------------------------------------------------
6166 // FixupInitBlkValue: Fixup the init value for an initBlk operation
6169 // asgType - The type of assignment that the initBlk is being transformed into
6172 // Modifies the constant value on this node to be the appropriate "fill"
6173 // value for the initblk.
6176 // The initBlk MSIL instruction takes a byte value, which must be
6177 // extended to the size of the assignment when an initBlk is transformed
6178 // to an assignment of a primitive type.
6179 // This performs the appropriate extension.
6182 GenTreeIntCon::FixupInitBlkValue(var_types asgType)
6184 assert(varTypeIsIntegralOrI(asgType));
6185 unsigned size = genTypeSize(asgType);
6188 size_t cns = gtIconVal;
6194 #ifdef _TARGET_64BIT_
6199 #endif // _TARGET_64BIT_
6201 // Make the type used in the GT_IND node match for evaluation types.
6204 // if we are using an GT_INITBLK on a GC type the value being assigned has to be zero (null).
6205 assert(!varTypeIsGC(asgType) || (cns == 0));
6212 // Initializes a BlkOp GenTree
6214 // - Result is a GenTreeBlkOp that is newly constructed by gtNewCpObjNode or gtNewBlkOpNode
6217 // - result is a GenTreeBlkOp node that is the node to be initialized.
6218 // - oper must be either GT_INITBLK or GT_COPYBLK
6219 // - dst is the target (destination) we want to either initialize or copy to
6220 // - src is the init value for IniBlk or the source struct for CpBlk/CpObj
6221 // - size is either the size of the buffer to copy/initialize or a class token
6222 // in the case of CpObj.
6223 // - volatil flag specifies if this node is a volatile memory operation.
6225 // This procedure centralizes all the logic to both enforce proper structure and
6226 // to properly construct any InitBlk/CpBlk node.
6227 void Compiler::gtBlockOpInit(GenTreePtr result,
6230 GenTreePtr srcOrFillVal,
6231 GenTreePtr hndOrSize,
6234 assert(GenTree::OperIsBlkOp(oper));
6236 assert(result->gtType == TYP_VOID);
6237 result->gtOper = oper;
6240 // If this is a CpObj node, the caller must have already set
6241 // the node additional members (gtGcPtrs, gtGcPtrCount, gtSlots).
6242 if(hndOrSize->OperGet() == GT_CNS_INT && hndOrSize->IsIconHandle(GTF_ICON_CLASS_HDL))
6244 GenTreeCpObj* cpObjNode = result->AsCpObj();
6246 assert(cpObjNode->gtGcPtrs != nullptr);
6247 assert(!IsUninitialized(cpObjNode->gtGcPtrs));
6248 assert(!IsUninitialized(cpObjNode->gtGcPtrCount) && cpObjNode->gtGcPtrCount > 0);
6249 assert(!IsUninitialized(cpObjNode->gtSlots) && cpObjNode->gtSlots > 0);
6251 for (unsigned i = 0; i < cpObjNode->gtGcPtrCount; ++i)
6253 CorInfoGCType t = (CorInfoGCType)cpObjNode->gtGcPtrs[i];
6268 /* In the case of CpBlk, we want to avoid generating
6269 * nodes where the source and destination are the same
6270 * because of two reasons, first, is useless, second
6271 * it introduces issues in liveness and also copying
6272 * memory from an overlapping memory location is
6273 * undefined both as per the ECMA standard and also
6274 * the memcpy semantics specify that.
6276 * NOTE: In this case we'll only detect the case for addr of a local
6277 * and a local itself, any other complex expressions won't be
6280 * TODO-Cleanup: though having this logic is goodness (i.e. avoids self-assignment
6281 * of struct vars very early), it was added because fgInterBlockLocalVarLiveness()
6282 * isn't handling self-assignment of struct variables correctly. This issue may not
6283 * surface if struct promotion is ON (which is the case on x86/arm). But still the
6284 * fundamental issue exists that needs to be addressed.
6286 GenTreePtr currSrc = srcOrFillVal;
6287 GenTreePtr currDst = dst;
6288 if (currSrc->OperGet() == GT_ADDR && currDst->OperGet() == GT_ADDR)
6290 currSrc = currSrc->gtOp.gtOp1;
6291 currDst = currDst->gtOp.gtOp1;
6294 if (currSrc->OperGet() == GT_LCL_VAR &&
6295 currDst->OperGet() == GT_LCL_VAR &&
6296 currSrc->gtLclVarCommon.gtLclNum == currDst->gtLclVarCommon.gtLclNum)
6299 result->gtBashToNOP();
6304 /* Note that this use of a GT_LIST is different than all others */
6305 /* in that the the GT_LIST is used as a tuple [dest,src] rather */
6306 /* than a being a NULL terminated list of GT_LIST nodes */
6307 result->gtOp.gtOp1 = gtNewOperNode(GT_LIST, TYP_VOID, /* GT_[oper] */
6308 dst, srcOrFillVal); /* / \ */
6309 result->gtOp.gtOp2 = hndOrSize; /* GT_LIST \ */
6310 /* / \ [hndOrSize] */
6311 /* [dst] [srcOrFillVal] */
6313 // Propagate all effect flags from children
6314 result->gtFlags |= result->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT;
6315 result->gtFlags |= result->gtOp.gtOp2->gtFlags & GTF_ALL_EFFECT;
6317 result->gtFlags |= (GTF_GLOB_REF | GTF_ASG);
6319 // REVERSE_OPS is necessary because the use must occur before the def
6320 result->gtOp.gtOp1->gtFlags |= GTF_REVERSE_OPS;
6322 if (result->gtOper == GT_INITBLK)
6324 result->gtFlags |= (dst->gtFlags & GTF_EXCEPT) |
6325 (hndOrSize->gtFlags & GTF_EXCEPT);
6329 result->gtFlags |= (dst->gtFlags & GTF_EXCEPT) |
6330 (srcOrFillVal->gtFlags & GTF_EXCEPT) |
6331 (hndOrSize->gtFlags & GTF_EXCEPT);
6333 // If the class being copied contains any GC pointer we store a class handle
6334 // and we must set the flag GTF_BLK_HASGCPTR, so that the register predictor
6335 // knows that this GT_COPYBLK will use calls to the ByRef Assign helper
6337 if ((hndOrSize->OperGet() == GT_CNS_INT) && hndOrSize->IsIconHandle(GTF_ICON_CLASS_HDL))
6339 hndOrSize->gtFlags |= GTF_DONT_CSE; // We can't CSE the class handle
6340 result->gtFlags |= GTF_BLK_HASGCPTR;
6346 result->gtFlags |= GTF_BLK_VOLATILE;
6350 if (oper == GT_COPYBLK &&
6351 srcOrFillVal->OperGet() == GT_ADDR &&
6352 dst->OperGet() == GT_ADDR)
6354 // If the source is a GT_SIMD node of SIMD type, then the dst lclvar struct
6355 // should be labeled as simd intrinsic related struct.
6356 // This is done so that the morpher can transform any field accesses into
6357 // intrinsics, thus avoiding conflicting access methods (fields vs. whole-register).
6359 GenTreePtr srcChild = srcOrFillVal->gtGetOp1();
6360 GenTreePtr dstChild = dst->gtGetOp1();
6362 if (dstChild->OperIsLocal() &&
6363 varTypeIsStruct(dstChild) &&
6364 srcChild->OperGet() == GT_SIMD &&
6365 varTypeIsSIMD(srcChild))
6367 unsigned lclNum = dst->gtGetOp1()->AsLclVarCommon()->GetLclNum();
6368 LclVarDsc* lclVarDsc = &lvaTable[lclNum];
6369 lclVarDsc->lvUsedInSIMDIntrinsic = true;
6373 #endif //FEATURE_SIMD
6376 //------------------------------------------------------------------------
6377 // gtNewBlkOpNode: Creates an InitBlk or CpBlk node.
6380 // oper - GT_COPYBLK, GT_INITBLK or GT_COPYOBJ
6381 // dst - Destination or target to copy to / initialize the buffer.
6382 // srcOrFillVall - Either the source to copy from or the byte value to fill the buffer.
6383 // sizeOrClsTok - The size of the buffer or a class token (in the case of CpObj).
6384 // isVolatile - Whether this is a volatile memory operation or not.
6387 // Returns the newly constructed and initialized block operation.
6390 Compiler::gtNewBlkOpNode(genTreeOps oper,
6392 GenTreePtr srcOrFillVal,
6393 GenTreePtr sizeOrClsTok,
6396 GenTreeBlkOp* result = new (this, oper) GenTreeBlkOp(oper);
6397 gtBlockOpInit(result, oper, dst, srcOrFillVal, sizeOrClsTok, isVolatile);
6401 /*****************************************************************************
6403 * Clones the given tree value and returns a copy of the given tree.
6404 * If 'complexOK' is false, the cloning is only done provided the tree
6405 * is not too complex (whatever that may mean);
6406 * If 'complexOK' is true, we try slightly harder to clone the tree.
6407 * In either case, NULL is returned if the tree cannot be cloned
6409 * Note that there is the function gtCloneExpr() which does a more
6410 * complete job if you can't handle this function failing.
6413 GenTreePtr Compiler::gtClone(GenTree * tree, bool complexOK)
6417 switch (tree->gtOper)
6421 #if defined (LATE_DISASM)
6422 if (tree->IsIconHandle())
6424 copy = gtNewIconHandleNode(tree->gtIntCon.gtIconVal,
6426 tree->gtIntCon.gtFieldSeq,
6427 tree->gtIntCon.gtIconHdl.gtIconHdl1,
6428 tree->gtIntCon.gtIconHdl.gtIconHdl2);
6429 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6430 copy->gtType = tree->gtType;
6435 copy = new(this, GT_CNS_INT) GenTreeIntCon(tree->gtType, tree->gtIntCon.gtIconVal, tree->gtIntCon.gtFieldSeq
6437 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6442 // Remember that the LclVar node has been cloned. The flag will be set
6443 // on 'copy' as well.
6444 tree->gtFlags |= GTF_VAR_CLONED;
6445 copy = gtNewLclvNode(tree->gtLclVarCommon.gtLclNum, tree->gtType,
6446 tree->gtLclVar.gtLclILoffs);
6450 case GT_LCL_FLD_ADDR:
6451 // Remember that the LclVar node has been cloned. The flag will be set
6452 // on 'copy' as well.
6453 tree->gtFlags |= GTF_VAR_CLONED;
6454 copy = new (this, tree->gtOper)
6455 GenTreeLclFld(tree->gtOper, tree->TypeGet(), tree->gtLclFld.gtLclNum, tree->gtLclFld.gtLclOffs);
6456 copy->gtLclFld.gtFieldSeq = tree->gtLclFld.gtFieldSeq;
6460 copy = new(this, GT_CLS_VAR) GenTreeClsVar(tree->gtType, tree->gtClsVar.gtClsVarHnd, tree->gtClsVar.gtFieldSeq);
6464 assert(!"clone regvar");
6470 if (tree->gtOper == GT_FIELD)
6474 // copied from line 9850
6477 if (tree->gtField.gtFldObj)
6479 objp = gtClone(tree->gtField.gtFldObj, false);
6484 copy = gtNewFieldRef(tree->TypeGet(),
6485 tree->gtField.gtFldHnd,
6487 tree->gtField.gtFldOffset);
6488 copy->gtField.gtFldMayOverlap = tree->gtField.gtFldMayOverlap;
6490 else if (tree->gtOper == GT_ADD)
6492 GenTreePtr op1 = tree->gtOp.gtOp1;
6493 GenTreePtr op2 = tree->gtOp.gtOp2;
6495 if (op1->OperIsLeaf() &&
6505 copy = gtNewOperNode(GT_ADD, tree->TypeGet(), op1, op2);
6512 else if (tree->gtOper == GT_ADDR)
6514 GenTreePtr op1 = gtClone(tree->gtOp.gtOp1);
6517 copy = gtNewOperNode(GT_ADDR, tree->TypeGet(), op1);
6527 copy->gtFlags |= tree->gtFlags & ~GTF_NODE_MASK;
6529 copy->gtDebugFlags |= tree->gtDebugFlags & ~GTF_DEBUG_NODE_MASK;
6530 #endif // defined(DEBUG)
6535 /*****************************************************************************
6537 * Clones the given tree value and returns a copy of the given tree. Any
6538 * references to local variable varNum will be replaced with the integer
6542 GenTreePtr Compiler::gtCloneExpr(GenTree * tree,
6544 unsigned varNum, // = (unsigned)-1
6550 /* Figure out what kind of a node we have */
6552 genTreeOps oper = tree->OperGet();
6553 unsigned kind = tree->OperKind();
6556 /* Is this a constant or leaf node? */
6558 if (kind & (GTK_CONST|GTK_LEAF))
6564 #if defined (LATE_DISASM)
6565 if (tree->IsIconHandle())
6567 copy = gtNewIconHandleNode(tree->gtIntCon.gtIconVal,
6569 tree->gtIntCon.gtFieldSeq,
6570 tree->gtIntCon.gtIconFld.gtIconCPX,
6571 tree->gtIntCon.gtIconFld.gtIconCls);
6572 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6573 copy->gtType = tree->gtType;
6578 copy = gtNewIconNode (tree->gtIntCon.gtIconVal,
6580 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6581 copy->gtIntCon.gtFieldSeq = tree->gtIntCon.gtFieldSeq;
6586 copy = gtNewLconNode(tree->gtLngCon.gtLconVal);
6590 copy = gtNewDconNode(tree->gtDblCon.gtDconVal);
6591 copy->gtType = tree->gtType; // keep the same type
6595 copy = gtNewSconNode(tree->gtStrCon.gtSconCPX, tree->gtStrCon.gtScpHnd);
6600 if (tree->gtLclVarCommon.gtLclNum == varNum)
6602 copy = gtNewIconNode(varVal, tree->gtType);
6606 // Remember that the LclVar node has been cloned. The flag will
6607 // be set on 'copy' as well.
6608 tree->gtFlags |= GTF_VAR_CLONED;
6609 copy = gtNewLclvNode(tree->gtLclVar.gtLclNum, tree->gtType,
6610 tree->gtLclVar.gtLclILoffs);
6611 copy->AsLclVarCommon()->SetSsaNum(tree->AsLclVarCommon()->GetSsaNum());
6613 copy->gtFlags = tree->gtFlags;
6617 if (tree->gtLclFld.gtLclNum == varNum)
6619 IMPL_LIMITATION("replacing GT_LCL_FLD with a constant");
6623 // Remember that the LclVar node has been cloned. The flag will
6624 // be set on 'copy' as well.
6625 tree->gtFlags |= GTF_VAR_CLONED;
6626 copy = new(this, GT_LCL_FLD) GenTreeLclFld(tree->TypeGet(), tree->gtLclFld.gtLclNum, tree->gtLclFld.gtLclOffs
6628 copy->gtLclFld.gtFieldSeq = tree->gtLclFld.gtFieldSeq;
6629 copy->gtFlags = tree->gtFlags;
6634 copy = new(this, GT_CLS_VAR) GenTreeClsVar(tree->TypeGet(), tree->gtClsVar.gtClsVarHnd, tree->gtClsVar.gtFieldSeq);
6638 copy = gtNewInlineCandidateReturnExpr(tree->gtRetExpr.gtInlineCandidate, tree->gtType);
6641 case GT_MEMORYBARRIER:
6642 copy = new (this, GT_MEMORYBARRIER) GenTree(GT_MEMORYBARRIER, TYP_VOID);
6646 copy = gtNewArgPlaceHolderNode(tree->gtType, tree->gtArgPlace.gtArgPlaceClsHnd);
6650 NO_WAY("Cloning of GT_REG_VAR node not supported");
6654 copy = new (this, oper) GenTreeFptrVal(tree->gtType, tree->gtFptrVal.gtFptrMethod);
6656 #ifdef FEATURE_READYTORUN_COMPILER
6657 copy->gtFptrVal.gtEntryPoint = tree->gtFptrVal.gtEntryPoint;
6658 copy->gtFptrVal.gtLdftnResolvedToken = tree->gtFptrVal.gtLdftnResolvedToken;
6664 copy = new (this, oper) GenTree(oper, tree->gtType);
6667 #if !FEATURE_EH_FUNCLETS
6669 #endif // !FEATURE_EH_FUNCLETS
6671 copy = new (this, oper) GenTreeVal(oper, tree->gtType, tree->gtVal.gtVal1);
6675 copy = new (this, oper) GenTreeLabel(tree->gtLabel.gtLabBB);
6679 NO_WAY("Cloning of node not supported");
6685 /* Is it a 'simple' unary/binary operator? */
6687 if (kind & GTK_SMPOP)
6689 /* If necessary, make sure we allocate a "fat" tree node */
6691 #if SMALL_TREE_NODES
6694 /* These nodes sometimes get bashed to "fat" ones */
6703 // In the implementation of gtNewLargeOperNode you have
6704 // to give an oper that will create a small node,
6705 // otherwise it asserts.
6707 if (GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL)
6709 copy = gtNewLargeOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1,
6710 tree->OperIsBinary() ? tree->gtOp.gtOp2 : NULL);
6712 else // Always a large tree
6714 if (tree->OperIsBinary())
6716 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2);
6720 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1);
6726 copy = new (this, LargeOpOpcode()) GenTreeCast(tree->TypeGet(), tree->gtCast.CastOp(), tree->gtCast.gtCastType
6727 DEBUGARG(/*largeNode*/TRUE));
6730 // The nodes below this are not bashed, so they can be allocated at their individual sizes.
6733 // This is ridiculous, but would go away if we made a stronger distinction between argument lists, whose
6734 // second argument *must* be an arglist*, and the uses of LIST in copyblk and initblk.
6735 if (tree->gtOp.gtOp2 != NULL && tree->gtOp.gtOp2->OperGet() == GT_LIST)
6737 copy = new (this, GT_LIST) GenTreeArgList(tree->gtOp.gtOp1, tree->gtOp.gtOp2->AsArgList());
6741 copy = new (this, GT_LIST) GenTreeOp(GT_LIST, TYP_VOID, tree->gtOp.gtOp1, tree->gtOp.gtOp2);
6747 GenTreeIndex* asInd = tree->AsIndex();
6748 copy = new (this, GT_INDEX) GenTreeIndex(asInd->TypeGet(), asInd->Arr(), asInd->Index(), asInd->gtIndElemSize);
6749 copy->AsIndex()->gtStructElemClass = asInd->gtStructElemClass;
6754 copy = new (this, GT_ARR_LENGTH) GenTreeArrLen(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtArrLen.ArrLenOffset());
6758 copy = new (this, GT_ARR_INDEX)
6759 GenTreeArrIndex(tree->TypeGet(),
6760 gtCloneExpr(tree->gtArrIndex.ArrObj(), addFlags, varNum, varVal),
6761 gtCloneExpr(tree->gtArrIndex.IndexExpr(), addFlags, varNum, varVal),
6762 tree->gtArrIndex.gtCurrDim,
6763 tree->gtArrIndex.gtArrRank,
6764 tree->gtArrIndex.gtArrElemType);
6768 copy = new (this, GT_QMARK) GenTreeQmark(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2, this);
6769 VarSetOps::AssignAllowUninitRhs(this, copy->gtQmark.gtThenLiveSet, tree->gtQmark.gtThenLiveSet);
6770 VarSetOps::AssignAllowUninitRhs(this, copy->gtQmark.gtElseLiveSet, tree->gtQmark.gtElseLiveSet);
6774 copy = new (this, GT_OBJ) GenTreeObj(tree->TypeGet(), tree->gtOp.gtOp1, tree->AsObj()->gtClass);
6778 copy = new (this, GT_BOX) GenTreeBox(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtBox.gtAsgStmtWhenInlinedBoxValue);
6782 copy = new (this, GT_INTRINSIC) GenTreeIntrinsic(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2, tree->gtIntrinsic.gtIntrinsicId,
6783 tree->gtIntrinsic.gtMethodHandle);
6784 #ifdef FEATURE_READYTORUN_COMPILER
6785 copy->gtIntrinsic.gtEntryPoint = tree->gtIntrinsic.gtEntryPoint;
6791 GenTreeCpObj* cpObjOp = tree->AsCpObj();
6792 assert(cpObjOp->gtGcPtrCount > 0);
6793 copy = gtCloneCpObjNode(cpObjOp);
6799 GenTreeInitBlk* initBlkOp = tree->AsInitBlk();
6800 copy = gtNewBlkOpNode(oper,
6802 initBlkOp->InitVal(),
6804 initBlkOp->IsVolatile());
6810 GenTreeCpBlk* cpBlkOp = tree->AsCpBlk();
6811 copy = gtNewBlkOpNode(oper,
6815 cpBlkOp->IsVolatile());
6816 copy->AsCpBlk()->gtBlkOpGcUnsafe = cpBlkOp->gtBlkOpGcUnsafe;
6822 GenTreeAddrMode* addrModeOp = tree->AsAddrMode();
6823 copy = new(this, GT_LEA) GenTreeAddrMode(addrModeOp->TypeGet(),
6825 addrModeOp->Index(),
6826 addrModeOp->gtScale,
6827 addrModeOp->gtOffset);
6834 copy = new(this, oper) GenTreeCopyOrReload(oper, tree->TypeGet(), tree->gtGetOp1());
6841 GenTreeSIMD *simdOp = tree->AsSIMD();
6842 copy = gtNewSIMDNode(simdOp->TypeGet(), simdOp->gtGetOp1(), simdOp->gtGetOp2(),
6843 simdOp->gtSIMDIntrinsicID, simdOp->gtSIMDBaseType, simdOp->gtSIMDSize);
6849 assert(!GenTree::IsExOp(tree->OperKind()) && tree->OperIsSimple());
6850 // We're in the SimpleOp case, so it's always unary or binary.
6851 if (GenTree::OperIsUnary(tree->OperGet()))
6853 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, /*doSimplifications*/false);
6857 assert(GenTree::OperIsBinary(tree->OperGet()));
6858 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2);
6863 // We're in the SimpleOp case, so it's always unary or binary.
6864 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2);
6867 // Some flags are conceptually part of the gtOper, and should be copied immediately.
6868 if (tree->gtOverflowEx())
6870 copy->gtFlags |= GTF_OVERFLOW;
6872 if (copy->OperGet() == GT_CAST)
6874 copy->gtFlags |= (tree->gtFlags & GTF_UNSIGNED);
6877 if (tree->gtOp.gtOp1)
6879 copy->gtOp.gtOp1 = gtCloneExpr(tree->gtOp.gtOp1, addFlags, varNum, varVal);
6882 if (tree->gtGetOp2())
6884 copy->gtOp.gtOp2 = gtCloneExpr(tree->gtOp.gtOp2, addFlags, varNum, varVal);
6889 addFlags |= tree->gtFlags;
6891 // Copy any node annotations, if necessary.
6892 switch (tree->gtOper)
6896 IndirectAssignmentAnnotation* pIndirAnnot = nullptr;
6897 if (m_indirAssignMap != NULL && GetIndirAssignMap()->Lookup(tree, &pIndirAnnot))
6899 IndirectAssignmentAnnotation* pNewIndirAnnot =
6900 new (this, CMK_Unknown) IndirectAssignmentAnnotation(pIndirAnnot->m_lclNum,
6901 pIndirAnnot->m_fieldSeq,
6902 pIndirAnnot->m_isEntire);
6903 GetIndirAssignMap()->Set(copy, pNewIndirAnnot);
6910 if (tree->gtFlags & GTF_IND_ARR_INDEX)
6913 bool b = GetArrayInfoMap()->Lookup(tree, &arrInfo);
6915 GetArrayInfoMap()->Set(copy, arrInfo);
6924 /* GTF_NODE_MASK should not be propagated from 'tree' to 'copy' */
6925 addFlags &= ~GTF_NODE_MASK;
6928 // Effects flags propagate upwards.
6929 if (copy->gtOp.gtOp1 != nullptr)
6930 copy->gtFlags |= (copy->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
6931 if (copy->gtGetOp2() != nullptr)
6932 copy->gtFlags |= (copy->gtGetOp2()->gtFlags & GTF_ALL_EFFECT);
6934 // The early morph for TailCall creates a GT_NOP with GTF_REG_VAL flag set
6935 // Thus we have to copy the gtRegNum/gtRegPair value if we clone it here.
6937 if (addFlags & GTF_REG_VAL)
6939 copy->CopyReg(tree);
6942 // We can call gtCloneExpr() before we have called fgMorph when we expand a GT_INDEX node in fgMorphArrayIndex()
6943 // The method gtFoldExpr() expects to be run after fgMorph so it will set the GTF_DEBUG_NODE_MORPHED
6944 // flag on nodes that it adds/modifies. Then when we call fgMorph we will assert.
6945 // We really only will need to fold when this method is used to replace references to
6946 // local variable with an integer.
6948 if (varNum != (unsigned) -1)
6950 /* Try to do some folding */
6951 copy = gtFoldExpr(copy);
6957 /* See what kind of a special operator we have here */
6962 copy = gtCloneExpr(tree->gtStmt.gtStmtExpr, addFlags, varNum, varVal);
6963 copy = gtNewStmt(copy, tree->gtStmt.gtStmtILoffsx);
6968 copy = new(this, GT_CALL) GenTreeCall(tree->TypeGet());
6970 copy->gtCall.gtCallObjp = tree->gtCall.gtCallObjp ? gtCloneExpr(tree->gtCall.gtCallObjp, addFlags, varNum, varVal) : NULL;
6971 copy->gtCall.gtCallArgs = tree->gtCall.gtCallArgs ? gtCloneExpr(tree->gtCall.gtCallArgs, addFlags, varNum, varVal)->AsArgList() : NULL;
6972 copy->gtCall.gtCallMoreFlags= tree->gtCall.gtCallMoreFlags;
6973 copy->gtCall.gtCallLateArgs = tree->gtCall.gtCallLateArgs ? gtCloneExpr(tree->gtCall.gtCallLateArgs, addFlags, varNum, varVal)->AsArgList() : NULL;
6975 #if !FEATURE_FIXED_OUT_ARGS
6976 copy->gtCall.regArgList = tree->gtCall.regArgList;
6977 copy->gtCall.regArgListCount= tree->gtCall.regArgListCount;
6980 // The call sig comes from the EE and doesn't change throughout the compilation process, meaning
6981 // we only really need one physical copy of it. Therefore a shallow pointer copy will suffice.
6982 // (Note that this still holds even if the tree we are cloning was created by an inlinee compiler,
6983 // because the inlinee still uses the inliner's memory allocator anyway.)
6984 copy->gtCall.callSig = tree->gtCall.callSig;
6986 copy->gtCall.gtCallType = tree->gtCall.gtCallType;
6987 copy->gtCall.gtReturnType = tree->gtCall.gtReturnType;
6988 copy->gtCall.gtControlExpr = tree->gtCall.gtControlExpr;
6990 /* Copy the union */
6991 if (tree->gtCall.gtCallType == CT_INDIRECT)
6993 copy->gtCall.gtCallCookie = tree->gtCall.gtCallCookie ? gtCloneExpr(tree->gtCall.gtCallCookie, addFlags, varNum, varVal) : NULL;
6994 copy->gtCall.gtCallAddr = tree->gtCall.gtCallAddr ? gtCloneExpr(tree->gtCall.gtCallAddr, addFlags, varNum, varVal) : NULL;
6996 else if (tree->gtFlags & GTF_CALL_VIRT_STUB)
6998 copy->gtCall.gtCallMethHnd = tree->gtCall.gtCallMethHnd;
6999 copy->gtCall.gtStubCallStubAddr = tree->gtCall.gtStubCallStubAddr;
7003 copy->gtCall.gtCallMethHnd = tree->gtCall.gtCallMethHnd;
7004 copy->gtCall.gtInlineCandidateInfo = tree->gtCall.gtInlineCandidateInfo;
7007 if (tree->gtCall.fgArgInfo)
7009 // Create and initialize the fgArgInfo for our copy of the call tree
7010 copy->gtCall.fgArgInfo = new (this, CMK_Unknown) fgArgInfo(copy, tree);
7014 copy->gtCall.fgArgInfo = NULL;
7016 copy->gtCall.gtRetClsHnd = tree->gtCall.gtRetClsHnd;
7018 #if FEATURE_MULTIREG_RET
7019 copy->gtCall.gtReturnTypeDesc = tree->gtCall.gtReturnTypeDesc;
7022 #ifdef LEGACY_BACKEND
7023 copy->gtCall.gtCallRegUsedMask = tree->gtCall.gtCallRegUsedMask;
7024 #endif // LEGACY_BACKEND
7026 #ifdef FEATURE_READYTORUN_COMPILER
7027 copy->gtCall.setEntryPoint(tree->gtCall.gtEntryPoint);
7031 copy->gtCall.gtInlineObservation = tree->gtCall.gtInlineObservation;
7034 copy->AsCall()->CopyOtherRegFlags(tree->AsCall());
7039 copy = gtNewFieldRef(tree->TypeGet(),
7040 tree->gtField.gtFldHnd,
7042 tree->gtField.gtFldOffset);
7044 copy->gtField.gtFldObj = tree->gtField.gtFldObj ? gtCloneExpr(tree->gtField.gtFldObj , addFlags, varNum, varVal) : 0;
7045 copy->gtField.gtFldMayOverlap = tree->gtField.gtFldMayOverlap;
7046 #ifdef FEATURE_READYTORUN_COMPILER
7047 copy->gtField.gtFieldLookup = tree->gtField.gtFieldLookup;
7054 GenTreePtr inds[GT_ARR_MAX_RANK];
7055 for (unsigned dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
7056 inds[dim] = gtCloneExpr(tree->gtArrElem.gtArrInds[dim], addFlags, varNum, varVal);
7057 copy = new (this, GT_ARR_ELEM)
7058 GenTreeArrElem(tree->TypeGet(),
7059 gtCloneExpr(tree->gtArrElem.gtArrObj, addFlags, varNum, varVal),
7060 tree->gtArrElem.gtArrRank,
7061 tree->gtArrElem.gtArrElemSize,
7062 tree->gtArrElem.gtArrElemType,
7070 copy = new (this, GT_ARR_OFFSET)
7071 GenTreeArrOffs(tree->TypeGet(),
7072 gtCloneExpr(tree->gtArrOffs.gtOffset, addFlags, varNum, varVal),
7073 gtCloneExpr(tree->gtArrOffs.gtIndex, addFlags, varNum, varVal),
7074 gtCloneExpr(tree->gtArrOffs.gtArrObj, addFlags, varNum, varVal),
7075 tree->gtArrOffs.gtCurrDim,
7076 tree->gtArrOffs.gtArrRank,
7077 tree->gtArrOffs.gtArrElemType);
7082 copy = new (this, GT_CMPXCHG)
7083 GenTreeCmpXchg(tree->TypeGet(),
7084 gtCloneExpr(tree->gtCmpXchg.gtOpLocation, addFlags, varNum, varVal),
7085 gtCloneExpr(tree->gtCmpXchg.gtOpValue, addFlags, varNum, varVal),
7086 gtCloneExpr(tree->gtCmpXchg.gtOpComparand, addFlags, varNum, varVal));
7089 case GT_ARR_BOUNDS_CHECK:
7092 #endif // FEATURE_SIMD
7093 copy = new (this, oper)
7094 GenTreeBoundsChk(oper,
7096 gtCloneExpr(tree->gtBoundsChk.gtArrLen, addFlags, varNum, varVal),
7097 gtCloneExpr(tree->gtBoundsChk.gtIndex, addFlags, varNum, varVal),
7098 tree->gtBoundsChk.gtThrowKind);
7106 NO_WAY("unexpected operator");
7111 // If it has a zero-offset field seq, copy annotation.
7112 if (tree->TypeGet() == TYP_BYREF)
7114 FieldSeqNode* fldSeq = nullptr;
7115 if (GetZeroOffsetFieldMap()->Lookup(tree, &fldSeq))
7116 GetZeroOffsetFieldMap()->Set(copy, fldSeq);
7119 copy->gtVNPair = tree->gtVNPair; // A cloned tree gets the orginal's Value number pair
7121 /* We assume the FP stack level will be identical */
7123 copy->gtCopyFPlvl(tree);
7125 /* Compute the flags for the copied node. Note that we can do this only
7126 if we didnt gtFoldExpr(copy) */
7128 if (copy->gtOper == oper)
7130 addFlags |= tree->gtFlags;
7133 /* GTF_NODE_MASK should not be propagated from 'tree' to 'copy' */
7134 addFlags &= ~GTF_NODE_MASK;
7136 // Some other flags depend on the context of the expression, and should not be preserved.
7137 // For example, GTF_RELOP_QMARK:
7138 if (copy->OperKind() & GTK_RELOP)
7139 addFlags &= ~GTF_RELOP_QMARK;
7140 // On the other hand, if we're creating such a context, restore this flag.
7141 if (copy->OperGet() == GT_QMARK)
7143 copy->gtOp.gtOp1->gtFlags |= GTF_RELOP_QMARK;
7146 copy->gtFlags |= addFlags;
7149 /* GTF_COLON_COND should be propagated from 'tree' to 'copy' */
7150 copy->gtFlags |= (tree->gtFlags & GTF_COLON_COND);
7153 // Non-node debug flags should be propagated from 'tree' to 'copy'
7154 copy->gtDebugFlags |= (tree->gtDebugFlags & ~GTF_DEBUG_NODE_MASK);
7157 /* Make sure to copy back fields that may have been initialized */
7159 copy->CopyRawCosts(tree);
7160 copy->gtRsvdRegs = tree->gtRsvdRegs;
7161 copy->CopyReg(tree);
7165 //------------------------------------------------------------------------
7166 // gtReplaceTree: Replace a tree with a new tree.
7169 // stmt - The top-level root stmt of the tree bing replaced.
7170 // Must not be null.
7171 // tree - The tree being replaced. Must not be null.
7172 // replacementTree - The replacement tree. Must not be null.
7175 // Return the tree node actually replaces the old tree.
7178 // The sequencing of the stmt has been done.
7181 // The caller must ensure that the original statement has been sequenced,
7182 // but this method will sequence 'replacementTree', and insert it into the
7183 // proper place in the statement sequence.
7185 GenTreePtr Compiler::gtReplaceTree(GenTreePtr stmt,
7187 GenTreePtr replacementTree)
7189 assert(fgStmtListThreaded);
7190 assert(tree != nullptr);
7191 assert(stmt != nullptr);
7192 assert(replacementTree != nullptr);
7194 GenTreePtr* treePtr = nullptr;
7195 GenTreePtr treeParent = tree->gtGetParent(&treePtr);
7197 assert(treeParent != nullptr || tree == stmt->gtStmt.gtStmtExpr);
7199 if (treePtr == nullptr)
7201 // Replace the stmt expr and rebuild the linear order for "stmt".
7202 assert(treeParent == nullptr);
7203 assert(fgOrder != FGOrderLinear);
7204 stmt->gtStmt.gtStmtExpr = tree;
7209 assert(treeParent != nullptr);
7211 GenTreePtr treeFirstNode = fgGetFirstNode(tree);
7212 GenTreePtr treeLastNode = tree;
7213 GenTreePtr treePrevNode = treeFirstNode->gtPrev;
7214 GenTreePtr treeNextNode = treeLastNode->gtNext;
7216 *treePtr = replacementTree;
7218 // Build the linear order for "replacementTree".
7219 fgSetTreeSeq(replacementTree, treePrevNode);
7221 // Restore linear-order Prev and Next for "replacementTree".
7222 if (treePrevNode != nullptr)
7224 treeFirstNode = fgGetFirstNode(replacementTree);
7225 treeFirstNode->gtPrev = treePrevNode;
7226 treePrevNode->gtNext = treeFirstNode;
7230 // Update the linear oder start of "stmt" if treeFirstNode
7231 // appears to have replaced the original first node.
7232 assert(treeFirstNode == stmt->gtStmt.gtStmtList);
7233 stmt->gtStmt.gtStmtList = fgGetFirstNode(replacementTree);
7236 if (treeNextNode != nullptr)
7238 treeLastNode = replacementTree;
7239 treeLastNode->gtNext = treeNextNode;
7240 treeNextNode->gtPrev = treeLastNode;
7243 bool needFixupCallArg = false;
7244 GenTreePtr node = treeParent;
7246 // If we have replaced an arg, then update pointers in argtable.
7249 // Look for the first enclosing callsite
7250 switch (node->OperGet())
7254 // "tree" is likely an argument of a call.
7255 needFixupCallArg = true;
7259 if (needFixupCallArg)
7261 // We have replaced an arg, so update pointers in argtable.
7262 fgFixupArgTabEntryPtr(node, tree, replacementTree);
7263 needFixupCallArg = false;
7268 // "tree" is unlikely an argument of a call.
7269 needFixupCallArg = false;
7273 if (needFixupCallArg)
7275 // Keep tracking to update the first enclosing call.
7276 node = node->gtGetParent(nullptr);
7283 } while (node != nullptr);
7285 // Propagate side-effect flags of "replacementTree" to its parents if needed.
7286 gtUpdateSideEffects(treeParent, tree->gtFlags, replacementTree->gtFlags);
7289 return replacementTree;
7292 //------------------------------------------------------------------------
7293 // gtUpdateSideEffects: Update the side effects for ancestors.
7296 // treeParent - The immediate parent node.
7297 // oldGtFlags - The stale gtFlags.
7298 // newGtFlags - The new gtFlags.
7302 // Linear order of the stmt has been established.
7305 // The routine is used for updating the stale side effect flags for ancestor
7306 // nodes starting from treeParent up to the top-level stmt expr.
7308 void Compiler::gtUpdateSideEffects(GenTreePtr treeParent,
7309 unsigned oldGtFlags,
7310 unsigned newGtFlags)
7312 assert(fgStmtListThreaded);
7314 oldGtFlags = oldGtFlags & GTF_ALL_EFFECT;
7315 newGtFlags = newGtFlags & GTF_ALL_EFFECT;
7317 if (oldGtFlags != newGtFlags)
7321 treeParent->gtFlags &= ~oldGtFlags;
7322 treeParent->gtFlags |= newGtFlags;
7323 treeParent = treeParent->gtGetParent(nullptr);
7328 /*****************************************************************************
7330 * Comapres two trees and returns true when both trees are the same.
7331 * Instead of fully comparing the two trees this method can just return false.
7332 * Thus callers should not assume that the trees are different when false is returned.
7333 * Only when true is returned can the caller perform code optimizations.
7334 * The current implementation only compares a limited set of LEAF/CONST node
7335 * and returns false for all othere trees.
7337 bool Compiler::gtCompareTree(GenTree * op1,
7340 /* Make sure that both trees are of the same GT node kind */
7341 if (op1->OperGet() != op2->OperGet())
7344 /* Make sure that both trees are returning the same type */
7345 if (op1->gtType != op2->gtType)
7348 /* Figure out what kind of a node we have */
7350 genTreeOps oper = op1->OperGet();
7351 unsigned kind = op1->OperKind();
7353 /* Is this a constant or leaf node? */
7355 if (kind & (GTK_CONST|GTK_LEAF))
7360 if ((op1->gtIntCon.gtIconVal == op2->gtIntCon.gtIconVal) &&
7361 GenTree::SameIconHandleFlag(op1, op2))
7368 if (op1->gtLngCon.gtLconVal == op2->gtLngCon.gtLconVal)
7375 if (op1->gtStrCon.gtSconCPX == op2->gtStrCon.gtSconCPX)
7382 if (op1->gtLclVarCommon.gtLclNum == op2->gtLclVarCommon.gtLclNum)
7389 if (op1->gtClsVar.gtClsVarHnd == op2->gtClsVar.gtClsVarHnd)
7396 // we return false for these unhandled 'oper' kinds
7404 GenTreePtr Compiler::gtGetThisArg(GenTreePtr call)
7406 assert(call->gtOper == GT_CALL);
7408 if (call->gtCall.gtCallObjp != NULL)
7410 if (call->gtCall.gtCallObjp->gtOper != GT_NOP && call->gtCall.gtCallObjp->gtOper != GT_ASG)
7412 if (!(call->gtCall.gtCallObjp->gtFlags & GTF_LATE_ARG))
7414 return call->gtCall.gtCallObjp;
7418 if (call->gtCall.gtCallLateArgs)
7420 regNumber thisReg = REG_ARG_0;
7421 unsigned argNum = 0;
7422 fgArgTabEntryPtr thisArgTabEntry = gtArgEntryByArgNum(call, argNum);
7423 GenTreePtr result = thisArgTabEntry->node;
7425 #if !FEATURE_FIXED_OUT_ARGS
7426 GenTreePtr lateArgs = call->gtCall.gtCallLateArgs;
7427 regList list = call->gtCall.regArgList;
7429 while (lateArgs != NULL)
7431 assert(lateArgs->gtOper == GT_LIST);
7432 assert(index < call->gtCall.regArgListCount);
7433 regNumber curArgReg = list[index];
7434 if (curArgReg == thisReg)
7436 if (optAssertionPropagatedCurrentStmt)
7437 result = lateArgs->gtOp.gtOp1;
7439 assert(result == lateArgs->gtOp.gtOp1);
7442 lateArgs = lateArgs->gtOp.gtOp2;
7452 bool GenTree::gtSetFlags() const
7455 // When FEATURE_SET_FLAGS (_TARGET_ARM_) is active the method returns true
7456 // when the gtFlags has the flag GTF_SET_FLAGS set
7457 // otherwise the architecture will be have instructions that typically set
7458 // the flags and this method will return true.
7460 // Exceptions: GT_IND (load/store) is not allowed to set the flags
7461 // and on XARCH the GT_MUL/GT_DIV and all overflow instructions
7462 // do not set the condition flags
7464 // Precondition we have a GTK_SMPOP
7466 assert(OperIsSimple());
7468 if (!varTypeIsIntegralOrI(TypeGet()))
7471 #if FEATURE_SET_FLAGS
7473 if ((gtFlags & GTF_SET_FLAGS) && gtOper != GT_IND)
7475 // GTF_SET_FLAGS is not valid on GT_IND and is overlaid with GTF_NONFAULTING_IND
7483 #else // !FEATURE_SET_FLAGS
7485 #ifdef _TARGET_XARCH_
7486 // Return true if/when the codegen for this node will set the flags
7489 if ((gtOper == GT_IND) || (gtOper == GT_MUL) || (gtOper == GT_DIV))
7491 else if (gtOverflowEx())
7496 // Otherwise for other architectures we should return false
7500 #endif // !FEATURE_SET_FLAGS
7503 bool GenTree::gtRequestSetFlags()
7505 bool result = false;
7507 // This method is a Nop unless FEATURE_SET_FLAGS is defined
7509 #if FEATURE_SET_FLAGS
7510 // In order to set GTF_SET_FLAGS
7511 // we must have a GTK_SMPOP
7512 // and we have a integer or machine size type (not floating point or TYP_LONG on 32-bit)
7514 if (!OperIsSimple())
7517 if (!varTypeIsIntegralOrI(TypeGet()))
7523 // These will turn into simple load from memory instructions
7524 // and we can't force the setting of the flags on load from memory
7529 // These instructions don't set the flags (on x86/x64)
7534 // Otherwise we can set the flags for this gtOper
7535 // and codegen must set the condition flags.
7537 gtFlags |= GTF_SET_FLAGS;
7541 #endif // FEATURE_SET_FLAGS
7543 // Codegen for this tree must set the condition flags if
7544 // this method returns true.
7549 /*****************************************************************************/
7550 void GenTree::CopyTo(class Compiler* comp, const GenTree& gt)
7554 gtAssertionNum = gt.gtAssertionNum;
7556 gtRegNum = gt.gtRegNum; // one union member.
7559 gtFlags = gt.gtFlags;
7560 gtVNPair = gt.gtVNPair;
7562 gtRsvdRegs = gt.gtRsvdRegs;
7564 #ifdef LEGACY_BACKEND
7565 gtUsedRegs = gt.gtUsedRegs;
7566 #endif // LEGACY_BACKEND
7568 #if FEATURE_STACK_FP_X87
7569 gtFPlvl = gt.gtFPlvl;
7570 #endif // FEATURE_STACK_FP_X87
7575 gtTreeID = gt.gtTreeID;
7576 gtSeqNum = gt.gtSeqNum;
7578 // Largest node subtype:
7579 void* remDst = reinterpret_cast<char*>(this) + sizeof(GenTree);
7580 void* remSrc = reinterpret_cast<char*>(const_cast<GenTree*>(>)) + sizeof(GenTree);
7581 memcpy(remDst, remSrc, TREE_NODE_SZ_LARGE - sizeof(GenTree));
7584 void GenTree::CopyToSmall(const GenTree& gt)
7586 // Small node size is defined by GenTreeOp.
7587 void* remDst = reinterpret_cast<char*>(this) + sizeof(GenTree);
7588 void* remSrc = reinterpret_cast<char*>(const_cast<GenTree*>(>)) + sizeof(GenTree);
7589 memcpy(remDst, remSrc, TREE_NODE_SZ_SMALL - sizeof(GenTree));
7592 unsigned GenTree::NumChildren()
7594 if (OperIsConst() || OperIsLeaf())
7598 else if (OperIsUnary())
7600 if (OperGet() == GT_NOP || OperGet() == GT_RETURN || OperGet() == GT_RETFILT)
7602 if (gtOp.gtOp1 == nullptr)
7612 else if (OperIsBinary())
7614 // All binary operators except LEA have at least one arg; the second arg may sometimes be null, however.
7615 if (OperGet() == GT_LEA)
7617 unsigned childCount = 0;
7618 if (gtOp.gtOp1 != nullptr)
7622 if (gtOp.gtOp2 != nullptr)
7628 assert(gtOp.gtOp1 != nullptr);
7629 if (gtOp.gtOp2 == nullptr)
7646 case GT_ARR_BOUNDS_CHECK:
7649 #endif // FEATURE_SIMD
7657 return 1 + AsArrElem()->gtArrRank;
7664 GenTreeCall* call = AsCall();
7665 unsigned res = 0; // arg list(s) (including late args).
7666 if (call->gtCallObjp != nullptr) res++; // Add objp?
7667 if (call->gtCallArgs != nullptr) res++; // Add args?
7668 if (call->gtCallLateArgs != nullptr) res++; // Add late args?
7669 if (call->gtControlExpr != nullptr) res++;
7671 if (call->gtCallType == CT_INDIRECT)
7673 if (call->gtCallCookie != nullptr) res++;
7674 if (call->gtCallAddr != nullptr) res++;
7686 GenTreePtr GenTree::GetChild(unsigned childNum)
7688 assert(childNum < NumChildren()); // Precondition.
7689 assert(NumChildren() <= MAX_CHILDREN);
7690 assert(!(OperIsConst() || OperIsLeaf()));
7693 return AsUnOp()->gtOp1;
7695 else if (OperIsBinary())
7697 if (OperIsAddrMode())
7699 // If this is the first (0th) child, only return op1 if it is non-null
7700 // Otherwise, we return gtOp2.
7701 if (childNum == 0 && AsOp()->gtOp1 != nullptr)
7702 return AsOp()->gtOp1;
7703 return AsOp()->gtOp2;
7705 // TODO-Cleanup: Consider handling ReverseOps here, and then we wouldn't have to handle it in
7706 // fgGetFirstNode(). However, it seems that it causes loop hoisting behavior to change.
7709 return AsOp()->gtOp1;
7713 return AsOp()->gtOp2;
7725 return AsCmpXchg()->gtOpLocation;
7727 return AsCmpXchg()->gtOpValue;
7729 return AsCmpXchg()->gtOpComparand;
7733 case GT_ARR_BOUNDS_CHECK:
7736 #endif // FEATURE_SIMD
7740 return AsBoundsChk()->gtArrLen;
7742 return AsBoundsChk()->gtIndex;
7748 return AsField()->gtFldObj;
7751 return AsStmt()->gtStmtExpr;
7756 return AsArrElem()->gtArrObj;
7760 return AsArrElem()->gtArrInds[childNum-1];
7767 return AsArrOffs()->gtOffset;
7769 return AsArrOffs()->gtIndex;
7771 return AsArrOffs()->gtArrObj;
7778 // The if chain below assumes that all possible children are non-null.
7779 // If some are null, "virtually skip them."
7780 // If there isn't "virtually skip it."
7781 GenTreeCall* call = AsCall();
7783 if (call->gtCallObjp == nullptr)
7785 if (childNum >= 1 && call->gtCallArgs == nullptr)
7787 if (childNum >= 2 && call->gtCallLateArgs == nullptr)
7789 if (childNum >= 3 && call->gtControlExpr == nullptr)
7791 if (call->gtCallType == CT_INDIRECT)
7793 if (childNum >= 4 && call->gtCallCookie == nullptr) childNum++;
7798 return call->gtCallObjp;
7800 else if (childNum == 1)
7802 return call->gtCallArgs;
7804 else if (childNum == 2)
7806 return call->gtCallLateArgs;
7808 else if (childNum == 3)
7810 return call->gtControlExpr;
7814 assert(call->gtCallType == CT_INDIRECT);
7817 return call->gtCallCookie;
7821 assert (childNum == 5);
7822 return call->gtCallAddr;
7836 /* static */ int GenTree::gtDispFlags(unsigned flags, unsigned debugFlags)
7838 printf("%c", (flags & GTF_ASG ) ? 'A' : '-');
7839 printf("%c", (flags & GTF_CALL ) ? 'C' : '-');
7840 printf("%c", (flags & GTF_EXCEPT ) ? 'X' : '-');
7841 printf("%c", (flags & GTF_GLOB_REF ) ? 'G' : '-');
7842 printf("%c", (debugFlags & GTF_DEBUG_NODE_MORPHED) ? '+' : // First print '+' if GTF_DEBUG_NODE_MORPHED is set
7843 (flags & GTF_ORDER_SIDEEFF ) ? 'O' : '-'); // otherwise print 'O' or '-'
7844 printf("%c", (flags & GTF_COLON_COND ) ? '?' : '-');
7845 printf("%c", (flags & GTF_DONT_CSE ) ? 'N' : // N is for No cse
7846 (flags & GTF_MAKE_CSE ) ? 'H' : '-'); // H is for Hoist this expr
7847 printf("%c", (flags & GTF_REVERSE_OPS ) ? 'R' : '-');
7848 printf("%c", (flags & GTF_UNSIGNED ) ? 'U' :
7849 (flags & GTF_BOOLEAN ) ? 'B' : '-');
7850 #if FEATURE_SET_FLAGS
7851 printf("%c", (flags & GTF_SET_FLAGS ) ? 'S' : '-');
7853 printf("%c", (flags & GTF_LATE_ARG ) ? 'L' : '-');
7854 printf("%c", (flags & GTF_SPILLED ) ? 'z' :
7855 (flags & GTF_SPILL ) ? 'Z' : '-');
7856 return 12; // displayed 12 flag characters
7859 /*****************************************************************************/
7862 Compiler::gtDispNodeName(GenTree *tree)
7864 /* print the node name */
7869 if (tree->gtOper < GT_COUNT)
7870 name = GenTree::NodeName(tree->OperGet());
7875 char * bufp = &buf[0];
7877 if ((tree->gtOper == GT_CNS_INT) && tree->IsIconHandle())
7879 sprintf_s(bufp, sizeof(buf), " %s(h)%c", name, 0);
7881 else if (tree->gtOper == GT_PUTARG_STK)
7883 sprintf_s(bufp, sizeof(buf), " %s [+0x%02x]%c", name, tree->AsPutArgStk()->getArgOffset(), 0);
7885 else if (tree->gtOper == GT_CALL)
7887 const char * callType = "call";
7888 const char * gtfType = "";
7889 const char * ctType = "";
7890 char gtfTypeBuf[100];
7892 if (tree->gtCall.gtCallType == CT_USER_FUNC)
7894 if ((tree->gtFlags & GTF_CALL_VIRT_KIND_MASK) != GTF_CALL_NONVIRT)
7897 else if (tree->gtCall.gtCallType == CT_HELPER)
7899 else if (tree->gtCall.gtCallType == CT_INDIRECT)
7902 assert(!"Unknown gtCallType");
7904 if (tree->gtFlags & GTF_CALL_NULLCHECK)
7905 gtfType = " nullcheck";
7907 if (tree->gtFlags & GTF_CALL_VIRT_VTABLE)
7909 else if (tree->gtFlags & GTF_CALL_VIRT_STUB)
7911 #ifdef FEATURE_READYTORUN_COMPILER
7912 else if (tree->gtCall.IsR2RRelativeIndir())
7913 gtfType = " r2r_ind";
7914 #endif // FEATURE_READYTORUN_COMPILER
7915 else if (tree->gtFlags & GTF_CALL_UNMANAGED)
7917 char * gtfTypeBufWalk = gtfTypeBuf;
7918 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf,
7919 sizeof(gtfTypeBuf), " unman");
7920 if (tree->gtFlags & GTF_CALL_POP_ARGS)
7921 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf,
7922 sizeof(gtfTypeBuf), " popargs");
7923 if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
7925 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf,
7929 gtfType = gtfTypeBuf;
7932 sprintf_s(bufp, sizeof(buf), " %s%s%s%c", callType, ctType, gtfType, 0);
7934 else if (tree->gtOper == GT_ARR_ELEM)
7936 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s[", name);
7937 for (unsigned rank = tree->gtArrElem.gtArrRank-1; rank; rank--)
7938 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), ",");
7939 SimpleSprintf_s(bufp, buf, sizeof(buf), "]");
7941 else if (tree->gtOper == GT_ARR_OFFSET || tree->gtOper == GT_ARR_INDEX)
7943 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s[", name);
7944 unsigned char currDim;
7946 if (tree->gtOper == GT_ARR_OFFSET)
7948 currDim = tree->gtArrOffs.gtCurrDim;
7949 rank = tree->gtArrOffs.gtArrRank;
7953 currDim = tree->gtArrIndex.gtCurrDim;
7954 rank = tree->gtArrIndex.gtArrRank;
7957 for (unsigned char dim = 0; dim < rank; dim++)
7959 // Use a defacto standard i,j,k for the dimensions.
7960 // Note that we only support up to rank 3 arrays with these nodes, so we won't run out of characters.
7964 dimChar = 'i' + dim;
7966 else if (dim > currDim)
7971 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "%c", dimChar);
7974 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), ",");
7977 SimpleSprintf_s(bufp, buf, sizeof(buf), "]");
7979 else if (tree->gtOper == GT_LEA)
7981 GenTreeAddrMode * lea = tree->AsAddrMode();
7982 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s(", name);
7983 if (lea->Base() != NULL) bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "b+");
7984 if (lea->Index() != NULL) bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "(i*%d)+", lea->gtScale);
7985 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "%d)", lea->gtOffset);
7987 else if (tree->gtOper == GT_ARR_BOUNDS_CHECK)
7989 switch(tree->gtBoundsChk.gtThrowKind)
7991 case SCK_RNGCHK_FAIL: sprintf_s(bufp, sizeof(buf), " %s_Rng", name); break;
7992 case SCK_ARG_EXCPN: sprintf_s(bufp, sizeof(buf), " %s_Arg", name); break;
7993 case SCK_ARG_RNG_EXCPN: sprintf_s(bufp, sizeof(buf), " %s_ArgRng", name); break;
7994 default: unreached();
7997 else if (tree->gtOverflowEx())
7999 sprintf_s(bufp, sizeof(buf), " %s_ovfl%c", name, 0);
8003 sprintf_s(bufp, sizeof(buf), " %s%c", name, 0);
8006 if (strlen(buf) < 10)
8007 printf(" %-10s", buf);
8012 void Compiler::gtDispVN(GenTree* tree)
8014 if (tree->gtVNPair.GetLiberal() != ValueNumStore::NoVN)
8016 assert(tree->gtVNPair.GetConservative() != ValueNumStore::NoVN);
8018 vnpPrint(tree->gtVNPair, 0);
8022 //------------------------------------------------------------------------
8023 // gtDispNode: Print a tree to jitstdout.
8026 // tree - the tree to be printed
8027 // indentStack - the specification for the current level of indentation & arcs
8028 // msg - a contextual method (i.e. from the parent) to print
8034 // 'indentStack' may be null, in which case no indentation or arcs are printed
8035 // 'msg' may be null
8037 void Compiler::gtDispNode(GenTreePtr tree,
8038 IndentStack* indentStack,
8039 __in __in_z __in_opt const char * msg)
8041 bool printPointer = true; // always true..
8042 bool printFlags = true; // always true..
8043 bool printCost = true; // always true..
8051 printf("N%03u ", tree->gtSeqNum);
8052 if (tree->gtCostsInitialized)
8054 printf("(%3u,%3u) ", tree->gtCostEx, tree->gtCostSz);
8058 printf("(???" ",???" ") "); // This probably indicates a bug: the node has a sequence number, but not costs.
8063 if (tree->gtOper == GT_STMT)
8065 prev = tree->gtStmt.gtStmtExpr;
8072 bool hasSeqNum = true;
8073 unsigned dotNum = 0;
8077 prev = prev->gtPrev;
8079 if ((prev == NULL) || (prev == tree))
8086 } while (prev->gtSeqNum == 0);
8088 // If we have an indent stack, don't add additional characters,
8089 // as it will mess up the alignment.
8090 if (tree->gtOper != GT_STMT && hasSeqNum && (indentStack == nullptr))
8091 printf("N%03u.%02u ", prev->gtSeqNum, dotNum);
8095 if (tree->gtCostsInitialized)
8097 printf("(%3u,%3u) ", tree->gtCostEx, tree->gtCostSz);
8101 if (tree->gtOper != GT_STMT && hasSeqNum)
8103 // Do better alignment in this case
8113 if (optValnumCSE_phase)
8115 if (IS_CSE_INDEX(tree->gtCSEnum))
8117 printf("CSE #%02d (%s)", GET_CSE_INDEX(tree->gtCSEnum),
8118 (IS_CSE_USE(tree->gtCSEnum) ? "use" : "def"));
8126 /* Print the node ID */
8130 if (tree->gtOper >= GT_COUNT)
8132 printf(" **** ILLEGAL NODE ****");
8138 /* First print the flags associated with the node */
8139 switch (tree->gtOper)
8143 // We prefer printing R, V or U
8144 if ((tree->gtFlags & (GTF_IND_REFARR_LAYOUT | GTF_IND_VOLATILE | GTF_IND_UNALIGNED)) == 0)
8146 if (tree->gtFlags & GTF_IND_TGTANYWHERE)
8147 { printf("*"); --msgLength; break; }
8148 if (tree->gtFlags & GTF_IND_INVARIANT)
8149 { printf("#"); --msgLength; break; }
8150 if (tree->gtFlags & GTF_IND_ARR_INDEX)
8151 { printf("a"); --msgLength; break; }
8157 if ((tree->gtFlags & (GTF_IND_VOLATILE | GTF_IND_UNALIGNED)) == 0) // We prefer printing V or U over R
8159 if (tree->gtFlags & GTF_IND_REFARR_LAYOUT)
8160 { printf("R"); --msgLength; break; } // R means RefArray
8166 if (tree->gtFlags & GTF_IND_VOLATILE)
8167 { printf("V"); --msgLength; break; }
8168 if (tree->gtFlags & GTF_IND_UNALIGNED)
8169 { printf("U"); --msgLength; break; }
8175 if (tree->AsBlkOp()->IsVolatile())
8176 { printf("V"); --msgLength; break; }
8177 if (tree->gtFlags & GTF_BLK_UNALIGNED)
8178 { printf("U"); --msgLength; break; }
8182 if (tree->gtFlags & GTF_CALL_INLINE_CANDIDATE)
8183 { printf("I"); --msgLength; break; }
8184 if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_RETBUFFARG)
8185 { printf("S"); --msgLength; break; }
8186 if (tree->gtFlags & GTF_CALL_HOISTABLE)
8187 { printf("H"); --msgLength; break; }
8192 if (tree->gtFlags & GTF_MUL_64RSLT)
8193 { printf("L"); --msgLength; break; }
8197 if (tree->gtFlags & GTF_ADDR_ONSTACK)
8198 { printf("L"); --msgLength; break; } // L means LclVar
8203 case GT_LCL_VAR_ADDR:
8204 case GT_LCL_FLD_ADDR:
8205 case GT_STORE_LCL_FLD:
8206 case GT_STORE_LCL_VAR:
8208 if (tree->gtFlags & GTF_VAR_USEASG)
8209 { printf("U"); --msgLength; break; }
8210 if (tree->gtFlags & GTF_VAR_USEDEF)
8211 { printf("B"); --msgLength; break; }
8212 if (tree->gtFlags & GTF_VAR_DEF)
8213 { printf("D"); --msgLength; break; }
8214 if (tree->gtFlags & GTF_VAR_CAST)
8215 { printf("C"); --msgLength; break; }
8216 if (tree->gtFlags & GTF_VAR_ARR_INDEX)
8217 { printf("i"); --msgLength; break; }
8226 if (tree->gtFlags & GTF_RELOP_NAN_UN)
8227 { printf("N"); --msgLength; break; }
8228 if (tree->gtFlags & GTF_RELOP_JMP_USED)
8229 { printf("J"); --msgLength; break; }
8230 if (tree->gtFlags & GTF_RELOP_QMARK)
8231 { printf("Q"); --msgLength; break; }
8232 if (tree->gtFlags & GTF_RELOP_SMALL)
8233 { printf("S"); --msgLength; break; }
8243 /* Then print the general purpose flags */
8244 unsigned flags = tree->gtFlags;
8246 if (tree->OperIsBinary())
8248 genTreeOps oper = tree->OperGet();
8250 // Check for GTF_ADDRMODE_NO_CSE flag on add/mul/shl Binary Operators
8251 if ((oper == GT_ADD) || (oper == GT_MUL) || (oper == GT_LSH))
8253 if ((tree->gtFlags & GTF_ADDRMODE_NO_CSE) != 0)
8255 flags |= GTF_DONT_CSE; // Force the GTF_ADDRMODE_NO_CSE flag to print out like GTF_DONT_CSE
8259 else // !tree->OperIsBinary()
8261 // the GTF_REVERSE flag only applies to binary operations
8262 flags &= ~GTF_REVERSE_OPS; // we use this value for GTF_VAR_ARR_INDEX above
8265 msgLength -= GenTree::gtDispFlags(flags, tree->gtDebugFlags);
8267 printf("%c", (flags & GTF_ASG ) ? 'A' : '-');
8268 printf("%c", (flags & GTF_CALL ) ? 'C' : '-');
8269 printf("%c", (flags & GTF_EXCEPT ) ? 'X' : '-');
8270 printf("%c", (flags & GTF_GLOB_REF ) ? 'G' : '-');
8271 printf("%c", (flags & GTF_ORDER_SIDEEFF ) ? 'O' : '-');
8272 printf("%c", (flags & GTF_COLON_COND ) ? '?' : '-');
8273 printf("%c", (flags & GTF_DONT_CSE ) ? 'N' : // N is for No cse
8274 (flags & GTF_MAKE_CSE ) ? 'H' : '-'); // H is for Hoist this expr
8275 printf("%c", (flags & GTF_REVERSE_OPS ) ? 'R' : '-');
8276 printf("%c", (flags & GTF_UNSIGNED ) ? 'U' :
8277 (flags & GTF_BOOLEAN ) ? 'B' : '-');
8278 printf("%c", (flags & GTF_SET_FLAGS ) ? 'S' : '-');
8279 printf("%c", (flags & GTF_SPILLED ) ? 'z' : '-');
8280 printf("%c", (flags & GTF_SPILL ) ? 'Z' : '-');
8283 #if FEATURE_STACK_FP_X87
8284 BYTE fpLvl = (BYTE)tree->gtFPlvl;
8285 if (IsUninitialized(fpLvl) || fpLvl == 0x00)
8291 printf("%1u", tree->gtFPlvl);
8293 #endif // FEATURE_STACK_FP_X87
8296 /* print the msg associated with the node */
8303 printf(" %-*s", msgLength, msg);
8305 /* Indent the node accordingly */
8306 printIndent(indentStack);
8308 gtDispNodeName(tree);
8310 assert(tree == 0 || tree->gtOper < GT_COUNT);
8314 /* print the type of the node */
8315 if (tree->gtOper != GT_CAST)
8317 printf(" %-6s", varTypeName(tree->TypeGet()));
8318 if (tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_STORE_LCL_VAR)
8320 LclVarDsc * varDsc = &lvaTable[tree->gtLclVarCommon.gtLclNum];
8321 if (varDsc->lvAddrExposed)
8323 printf("(AX)"); // Variable has address exposed.
8326 if (varDsc->lvUnusedStruct)
8328 assert(varDsc->lvPromoted);
8329 printf("(U)"); // Unused struct
8331 else if (varDsc->lvPromoted)
8333 assert(varTypeIsPromotable(varDsc));
8334 printf("(P)"); // Promoted struct
8338 if (tree->gtOper == GT_STMT)
8340 if (tree->gtFlags & GTF_STMT_TOP_LEVEL)
8341 printf("(top level) ");
8343 printf("(embedded) ");
8345 if (opts.compDbgInfo)
8347 IL_OFFSET endIL = tree->gtStmt.gtStmtLastILoffs;
8350 if (tree->gtStmt.gtStmtILoffsx == BAD_IL_OFFSET)
8353 printf("0x%03X", jitGetILoffs(tree->gtStmt.gtStmtILoffsx));
8355 if (endIL == BAD_IL_OFFSET)
8358 printf("0x%03X", endIL);
8363 if (tree->IsArgPlaceHolderNode() && (tree->gtArgPlace.gtArgPlaceClsHnd != NULL))
8365 printf(" => [clsHnd=%08X]", dspPtr(tree->gtArgPlace.gtArgPlaceClsHnd));
8369 // for tracking down problems in reguse prediction or liveness tracking
8373 printf(" RR="); dspRegMask(tree->gtRsvdRegs);
8374 #ifdef LEGACY_BACKEND
8375 printf(",UR="); dspRegMask(tree->gtUsedRegs);
8376 #endif // LEGACY_BACKEND
8382 void Compiler::gtDispRegVal(GenTree * tree)
8384 switch (tree->GetRegTag())
8386 // Don't display NOREG; the absence of this tag will imply this state
8387 //case GenTree::GT_REGTAG_NONE: printf(" NOREG"); break;
8389 case GenTree::GT_REGTAG_REG:
8390 printf(" REG %s", compRegVarName(tree->gtRegNum));
8393 #if CPU_LONG_USES_REGPAIR
8394 case GenTree::GT_REGTAG_REGPAIR:
8395 printf(" PAIR %s", compRegPairName(tree->gtRegPair));
8403 if (tree->IsMultiRegCall())
8405 // 0th reg is gtRegNum, which is already printed above.
8406 // Print the remaining regs of a multi-reg call node.
8407 GenTreeCall* call = tree->AsCall();
8408 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
8409 for (unsigned i = 1; i < regCount; ++i)
8411 printf(",%s", compRegVarName(call->GetRegNumByIdx(i)));
8414 else if (tree->IsCopyOrReloadOfMultiRegCall())
8416 GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
8417 GenTreeCall* call = tree->gtGetOp1()->AsCall();
8418 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
8419 for (unsigned i = 1; i < regCount; ++i)
8421 printf(",%s", compRegVarName(copyOrReload->GetRegNumByIdx(i)));
8425 if (tree->gtFlags & GTF_REG_VAL)
8431 // We usually/commonly don't expect to print anything longer than this string,
8432 #define LONGEST_COMMON_LCL_VAR_DISPLAY "V99 PInvokeFrame"
8433 #define LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH (sizeof(LONGEST_COMMON_LCL_VAR_DISPLAY))
8434 #define BUF_SIZE (LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH*2)
8436 void Compiler::gtGetLclVarNameInfo(unsigned lclNum, const char** ilKindOut, const char** ilNameOut, unsigned * ilNumOut)
8438 const char* ilKind = nullptr;
8439 const char* ilName = nullptr;
8441 unsigned ilNum = compMap2ILvarNum(lclNum);
8443 if (ilNum == (unsigned)ICorDebugInfo::RETBUF_ILNUM)
8447 else if (ilNum == (unsigned)ICorDebugInfo::VARARGS_HND_ILNUM)
8449 ilName = "VarArgHandle";
8451 else if (ilNum == (unsigned)ICorDebugInfo::TYPECTXT_ILNUM)
8455 else if (ilNum == (unsigned)ICorDebugInfo::UNKNOWN_ILNUM)
8458 if (lclNumIsTrueCSE(lclNum))
8461 ilNum = lclNum - optCSEstart;
8463 else if (lclNum >= optCSEstart)
8465 // Currently any new LclVar's introduced after the CSE phase
8466 // are believed to be created by the "rationalizer" that is what is meant by the "rat" prefix.
8468 ilNum = lclNum - (optCSEstart+optCSEcount);
8471 #endif // FEATURE_ANYCSE
8473 if (lclNum == info.compLvFrameListRoot)
8474 ilName = "FramesRoot";
8475 else if (lclNum == lvaInlinedPInvokeFrameVar)
8476 ilName = "PInvokeFrame";
8477 else if (lclNum == lvaGSSecurityCookie)
8478 ilName = "GsCookie";
8479 #if FEATURE_FIXED_OUT_ARGS
8480 else if (lclNum == lvaPInvokeFrameRegSaveVar)
8481 ilName = "PInvokeFrameRegSave";
8482 else if (lclNum == lvaOutgoingArgSpaceVar)
8484 #endif // FEATURE_FIXED_OUT_ARGS
8486 else if (lclNum == lvaPromotedStructAssemblyScratchVar)
8487 ilName = "PromotedStructScratch";
8488 #endif // _TARGET_ARM_
8489 #if !FEATURE_EH_FUNCLETS
8490 else if (lclNum == lvaShadowSPslotsVar)
8492 #endif // !FEATURE_EH_FUNCLETS
8493 else if (lclNum == lvaLocAllocSPvar)
8494 ilName = "LocAllocSP";
8495 #if FEATURE_EH_FUNCLETS
8496 else if (lclNum == lvaPSPSym)
8498 #endif // FEATURE_EH_FUNCLETS
8502 if (compIsForInlining())
8504 ilNum = lclNum - impInlineInfo->InlinerCompiler->info.compLocalsCount;
8508 ilNum = lclNum - info.compLocalsCount;
8513 else if (lclNum < (compIsForInlining()
8514 ? impInlineInfo->InlinerCompiler->info.compArgsCount
8515 : info.compArgsCount))
8517 if (ilNum == 0 && !info.compIsStatic)
8524 if (!lvaTable[lclNum].lvIsStructField)
8527 if (compIsForInlining())
8529 ilNum -= impInlineInfo->InlinerCompiler->info.compILargsCount;
8533 ilNum -= info.compILargsCount;
8537 *ilKindOut = ilKind;
8538 *ilNameOut = ilName;
8542 /*****************************************************************************/
8543 int Compiler::gtGetLclVarName(unsigned lclNum, char* buf, unsigned buf_remaining)
8545 char* bufp_next = buf;
8546 unsigned charsPrinted = 0;
8549 sprintf_result = sprintf_s(bufp_next, buf_remaining, "V%02u", lclNum);
8551 if (sprintf_result < 0)
8552 return sprintf_result;
8554 charsPrinted += sprintf_result;
8555 bufp_next += sprintf_result;
8556 buf_remaining -= sprintf_result;
8558 const char* ilKind = nullptr;
8559 const char* ilName = nullptr;
8562 Compiler::gtGetLclVarNameInfo(lclNum, &ilKind, &ilName, &ilNum);
8564 if (ilName != nullptr)
8566 sprintf_result = sprintf_s(bufp_next, buf_remaining, " %s", ilName);
8567 if (sprintf_result < 0) return sprintf_result;
8568 charsPrinted += sprintf_result;
8569 bufp_next += sprintf_result;
8570 buf_remaining -= sprintf_result;
8572 else if (ilKind != nullptr)
8574 sprintf_result = sprintf_s(bufp_next, buf_remaining, " %s%d", ilKind, ilNum);
8575 if (sprintf_result < 0) return sprintf_result;
8576 charsPrinted += sprintf_result;
8577 bufp_next += sprintf_result;
8578 buf_remaining -= sprintf_result;
8581 assert(charsPrinted > 0);
8582 assert(buf_remaining > 0);
8584 return (int)charsPrinted;
8587 /*****************************************************************************
8588 * Get the local var name, and create a copy of the string that can be used in debug output.
8590 char* Compiler::gtGetLclVarName(unsigned lclNum)
8593 int charsPrinted = gtGetLclVarName(lclNum, buf, sizeof(buf)/sizeof(buf[0]));
8594 if (charsPrinted < 0)
8597 char* retBuf = new (this, CMK_DebugOnly) char[charsPrinted + 1];
8598 strcpy_s(retBuf, charsPrinted + 1, buf);
8602 /*****************************************************************************/
8603 void Compiler::gtDispLclVar(unsigned lclNum, bool padForBiggestDisp)
8606 int charsPrinted = gtGetLclVarName(lclNum, buf, sizeof(buf)/sizeof(buf[0]));
8608 if (charsPrinted < 0)
8613 if (padForBiggestDisp && (charsPrinted < LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH))
8614 printf("%*c", LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH - charsPrinted, ' ');
8617 /*****************************************************************************/
8619 Compiler::gtDispConst(GenTree *tree)
8621 assert(tree->OperKind() & GTK_CONST);
8623 switch (tree->gtOper)
8626 if (tree->IsIconHandle(GTF_ICON_STR_HDL))
8628 printf(" 0x%X \"%S\"", dspPtr(tree->gtIntCon.gtIconVal), eeGetCPString(tree->gtIntCon.gtIconVal));
8632 ssize_t dspIconVal = tree->IsIconHandle() ? dspPtr(tree->gtIntCon.gtIconVal) : tree->gtIntCon.gtIconVal;
8634 if (tree->TypeGet() == TYP_REF)
8636 assert(tree->gtIntCon.gtIconVal == 0);
8639 else if ((tree->gtIntCon.gtIconVal > -1000) && (tree->gtIntCon.gtIconVal < 1000))
8640 printf(" %ld", dspIconVal);
8641 #ifdef _TARGET_64BIT_
8642 else if ((tree->gtIntCon.gtIconVal & 0xFFFFFFFF00000000LL) != 0)
8643 printf(" 0x%llx", dspIconVal);
8646 printf(" 0x%X", dspIconVal);
8648 if (tree->IsIconHandle())
8650 switch (tree->GetIconHandleFlag())
8652 case GTF_ICON_SCOPE_HDL:
8655 case GTF_ICON_CLASS_HDL:
8658 case GTF_ICON_METHOD_HDL:
8661 case GTF_ICON_FIELD_HDL:
8664 case GTF_ICON_STATIC_HDL:
8667 case GTF_ICON_STR_HDL:
8668 unreached(); // This case is handled above
8670 case GTF_ICON_PSTR_HDL:
8673 case GTF_ICON_PTR_HDL:
8676 case GTF_ICON_VARG_HDL:
8679 case GTF_ICON_PINVKI_HDL:
8682 case GTF_ICON_TOKEN_HDL:
8685 case GTF_ICON_TLS_HDL:
8688 case GTF_ICON_FTN_ADDR:
8691 case GTF_ICON_CIDMID_HDL:
8694 case GTF_ICON_BBC_PTR:
8703 if ((tree->gtFlags & GTF_ICON_FIELD_OFF) != 0)
8704 printf(" field offset");
8706 if ((tree->IsReuseRegVal()) != 0)
8707 printf(" reuse reg val");
8710 gtDispFieldSeq(tree->gtIntCon.gtFieldSeq);
8715 printf(" 0x%016I64x", tree->gtLngCon.gtLconVal);
8719 if (*((__int64 *)&tree->gtDblCon.gtDconVal) == (__int64)I64(0x8000000000000000))
8720 printf(" -0.00000");
8722 printf(" %#.17g", tree->gtDblCon.gtDconVal);
8725 printf("<string constant>");
8727 default: assert(!"unexpected constant node");
8733 void Compiler::gtDispFieldSeq(FieldSeqNode* pfsn)
8735 if (pfsn == FieldSeqStore::NotAField() || (pfsn == nullptr))
8742 while (pfsn != NULL)
8744 assert(pfsn != FieldSeqStore::NotAField()); // Can't exist in a field sequence list except alone
8745 CORINFO_FIELD_HANDLE fldHnd = pfsn->m_fieldHnd;
8746 // First check the "pseudo" field handles...
8747 if (fldHnd == FieldSeqStore::FirstElemPseudoField)
8749 printf("#FirstElem");
8751 else if (fldHnd == FieldSeqStore::ConstantIndexPseudoField)
8753 printf("#ConstantIndex");
8757 printf("%s", eeGetFieldName(fldHnd));
8759 pfsn = pfsn->m_next;
8760 if (pfsn != NULL) printf(", ");
8765 //------------------------------------------------------------------------
8766 // gtDispLeaf: Print a single leaf node to jitstdout.
8769 // tree - the tree to be printed
8770 // indentStack - the specification for the current level of indentation & arcs
8776 // 'indentStack' may be null, in which case no indentation or arcs are printed
8779 Compiler::gtDispLeaf(GenTree *tree, IndentStack* indentStack)
8781 if (tree->OperKind() & GTK_CONST)
8787 bool isLclFld = false;
8789 switch (tree->gtOper)
8795 case GT_LCL_FLD_ADDR:
8796 case GT_STORE_LCL_FLD:
8802 case GT_LCL_VAR_ADDR:
8803 case GT_STORE_LCL_VAR:
8805 varNum = tree->gtLclVarCommon.gtLclNum;
8806 varDsc = &lvaTable[varNum];
8807 gtDispLclVar(varNum);
8808 if (tree->gtLclVarCommon.HasSsaName())
8810 if (tree->gtFlags & GTF_VAR_USEASG)
8812 assert(tree->gtFlags & GTF_VAR_DEF);
8813 printf("ud:%d->%d", tree->gtLclVarCommon.gtSsaNum, GetSsaNumForLocalVarDef(tree));
8817 printf("%s:%d", (tree->gtFlags & GTF_VAR_DEF) ? "d" : "u", tree->gtLclVarCommon.gtSsaNum);
8823 printf("[+%u]", tree->gtLclFld.gtLclOffs);
8824 gtDispFieldSeq(tree->gtLclFld.gtFieldSeq);
8827 if (varDsc->lvRegister)
8830 varDsc->PrintVarReg();
8832 #ifndef LEGACY_BACKEND
8833 else if (tree->InReg())
8835 #if CPU_LONG_USES_REGPAIR
8836 if (isRegPairType(tree->TypeGet()))
8837 printf(" %s", compRegPairName(tree->gtRegPair));
8840 printf(" %s", compRegVarName(tree->gtRegNum));
8842 #endif // !LEGACY_BACKEND
8844 if (varDsc->lvPromoted)
8846 assert(varTypeIsPromotable(varDsc) || varDsc->lvUnusedStruct);
8848 CORINFO_CLASS_HANDLE typeHnd = varDsc->lvVerTypeInfo.GetClassHandle();
8849 CORINFO_FIELD_HANDLE fldHnd;
8851 for (unsigned i = varDsc->lvFieldLclStart;
8852 i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt;
8855 LclVarDsc * fieldVarDsc = &lvaTable[i];
8856 const char* fieldName;
8857 #if !defined(_TARGET_64BIT_)
8858 if (varTypeIsLong(varDsc))
8860 fieldName = (i == 0) ? "lo" : "hi";
8863 #endif // !defined(_TARGET_64BIT_)
8865 fldHnd = info.compCompHnd->getFieldInClass(typeHnd, fieldVarDsc->lvFldOrdinal);
8866 fieldName = eeGetFieldName(fldHnd);
8871 printIndent(indentStack);
8872 printf(" %-6s V%02u.%s (offs=0x%02x) -> ",
8873 varTypeName(fieldVarDsc->TypeGet()),
8874 tree->gtLclVarCommon.gtLclNum,
8876 fieldVarDsc->lvFldOffset
8880 if (fieldVarDsc->lvRegister)
8883 fieldVarDsc->PrintVarReg();
8886 if (fieldVarDsc->lvTracked &&
8887 fgLocalVarLivenessDone && // Includes local variable liveness
8888 ((tree->gtFlags & GTF_VAR_DEATH) != 0))
8890 printf(" (last use)");
8894 else // a normal not-promoted lclvar
8896 if (varDsc->lvTracked &&
8897 fgLocalVarLivenessDone &&
8898 ((tree->gtFlags & GTF_VAR_DEATH) != 0))
8900 printf(" (last use)");
8907 gtDispLclVar(tree->gtRegVar.gtLclNum);
8908 if (isFloatRegType(tree->gtType))
8910 assert(tree->gtRegVar.gtRegNum == tree->gtRegNum);
8911 printf(" FPV%u", tree->gtRegNum);
8915 printf(" %s", compRegVarName(tree->gtRegVar.gtRegNum));
8918 varNum = tree->gtRegVar.gtLclNum;
8919 varDsc = &lvaTable[varNum];
8921 if (varDsc->lvTracked &&
8922 fgLocalVarLivenessDone &&
8923 ((tree->gtFlags & GTF_VAR_DEATH) != 0))
8925 printf(" (last use)");
8932 const char * methodName;
8933 const char * className;
8935 methodName = eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtVal.gtVal1, &className);
8936 printf(" %s.%s\n", className, methodName);
8941 printf(" Hnd=%#x" , dspPtr(tree->gtClsVar.gtClsVarHnd));
8942 gtDispFieldSeq(tree->gtClsVar.gtFieldSeq);
8945 case GT_CLS_VAR_ADDR:
8946 printf(" Hnd=%#x" , dspPtr(tree->gtClsVar.gtClsVarHnd));
8950 if (tree->gtLabel.gtLabBB)
8951 printf(" dst=BB%02u" , tree->gtLabel.gtLabBB->bbNum);
8953 printf(" dst=<null>");
8959 const char * methodName;
8960 const char * className;
8962 methodName = eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtFptrVal.gtFptrMethod, &className);
8963 printf(" %s.%s\n", className, methodName);
8967 #if !FEATURE_EH_FUNCLETS
8969 printf(" endNstLvl=%d", tree->gtVal.gtVal1);
8971 #endif // !FEATURE_EH_FUNCLETS
8973 // Vanilla leaves. No qualifying information available. So do nothing
8976 case GT_START_NONGC:
8979 case GT_MEMORYBARRIER:
8981 case GT_PINVOKE_PROLOG:
8982 #ifndef LEGACY_BACKEND
8984 #endif // !LEGACY_BACKEND
8988 printf("(inl return from call ");
8989 printTreeID(tree->gtRetExpr.gtInlineCandidate);
8994 printf(" %s", getRegName(tree->gtPhysReg.gtSrcReg, varTypeIsFloating(tree)));
8998 assert(!"don't know how to display tree leaf node");
9004 //------------------------------------------------------------------------
9005 // gtDispLeaf: Print a child node to jitstdout.
9008 // tree - the tree to be printed
9009 // indentStack - the specification for the current level of indentation & arcs
9010 // arcType - the type of arc to use for this child
9011 // msg - a contextual method (i.e. from the parent) to print
9012 // topOnly - a boolean indicating whether to print the children, or just the top node
9018 // 'indentStack' may be null, in which case no indentation or arcs are printed
9019 // 'msg' has a default value of null
9020 // 'topOnly' is an optional argument that defaults to false
9022 void Compiler::gtDispChild(GenTreePtr child,
9023 IndentStack* indentStack,
9025 __in_opt const char* msg, /* = nullptr */
9026 bool topOnly) /* = false */
9029 indentStack->Push(arcType);
9030 gtDispTree(child, indentStack, msg, topOnly);
9035 // Intrinsic Id to name map
9037 const char * const simdIntrinsicNames[] =
9039 #define SIMD_INTRINSIC(mname, inst, id, name, r, ac, arg1, arg2, arg3, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) name,
9040 #include "simdintrinsiclist.h"
9042 #endif //FEATURE_SIMD
9045 /*****************************************************************************/
9047 void Compiler::gtDispTree(GenTreePtr tree,
9048 IndentStack* indentStack, /* = nullptr */
9049 __in __in_z __in_opt const char * msg, /* = nullptr */
9050 bool topOnly) /* = false */
9054 printf(" [%08X] <NULL>\n", tree);
9055 printf(""); // null string means flush
9059 if (fgOrder == FGOrderLinear && !topOnly)
9061 if (tree->gtOper == GT_STMT)
9063 (void) gtDispLinearStmt(tree->AsStmt());
9067 gtDispLinearTree(nullptr, fgGetFirstNode(tree), tree, new (this, CMK_DebugOnly) IndentStack(this));
9072 if (indentStack == nullptr)
9074 indentStack = new (this, CMK_DebugOnly) IndentStack(this);
9077 if (IsUninitialized(tree))
9079 /* Value used to initalize nodes */
9080 printf("Uninitialized tree node!");
9084 if (tree->gtOper >= GT_COUNT)
9086 gtDispNode(tree, indentStack, msg);
9087 printf("Bogus operator!");
9091 /* Is tree a leaf node? */
9093 if (tree->OperIsLeaf()
9094 || tree->OperIsLocalStore()) // local stores used to be leaves
9096 gtDispNode(tree, indentStack, msg);
9097 gtDispLeaf(tree, indentStack);
9100 if (tree->OperIsLocalStore() && !topOnly)
9102 gtDispChild(tree->gtOp.gtOp1, indentStack, IINone);
9107 // Determine what kind of arc to propagate.
9108 IndentInfo myArc = IINone;
9109 IndentInfo lowerArc = IINone;
9110 if (indentStack->Depth() > 0)
9112 myArc = indentStack->Pop();
9116 indentStack->Push(IIArc);
9120 indentStack->Push(IIArc);
9124 indentStack->Push(IINone);
9128 indentStack->Push(IIEmbedded);
9129 lowerArc = IIEmbedded;
9132 // Should never get here; just use IINone.
9137 // Special case formatting for PHI nodes -- arg lists like calls.
9139 if (tree->OperGet() == GT_PHI)
9141 gtDispNode(tree, indentStack, msg);
9145 if (tree->gtOp.gtOp1 != NULL)
9147 IndentInfo arcType = IIArcTop;
9148 for (GenTreeArgList* args = tree->gtOp.gtOp1->AsArgList(); args != NULL; args = args->Rest())
9150 if (args->Rest() == nullptr)
9152 arcType = IIArcBottom;
9154 gtDispChild(args->Current(), indentStack, arcType);
9161 /* Is it a 'simple' unary/binary operator? */
9163 const char * childMsg = NULL;
9165 if (tree->OperIsSimple())
9169 if (tree->gtGetOp2())
9171 // Label the childMsgs of the GT_COLON operator
9172 // op2 is the then part
9174 if (tree->gtOper == GT_COLON)
9177 gtDispChild(tree->gtOp.gtOp2, indentStack, IIArcTop, childMsg, topOnly);
9181 // Now, get the right type of arc for this node
9182 if (myArc != IINone)
9185 indentStack->Push(myArc);
9187 gtDispNode(tree, indentStack, msg);
9189 // Propagate lowerArc to the lower children.
9190 if (indentStack->Depth() > 0)
9192 (void) indentStack->Pop();
9193 indentStack->Push(lowerArc);
9196 if (tree->gtOper == GT_CAST)
9198 /* Format a message that explains the effect of this GT_CAST */
9200 var_types fromType = genActualType(tree->gtCast.CastOp()->TypeGet());
9201 var_types toType = tree->CastToType();
9202 var_types finalType = tree->TypeGet();
9204 /* if GTF_UNSIGNED is set then force fromType to an unsigned type */
9205 if (tree->gtFlags & GTF_UNSIGNED)
9206 fromType = genUnsignedType(fromType);
9208 if (finalType != toType)
9209 printf(" %s <-", varTypeName(finalType));
9211 printf(" %s <- %s", varTypeName(toType), varTypeName(fromType));
9214 if (tree->gtOper == GT_OBJ && (tree->gtFlags & GTF_VAR_DEATH))
9216 printf(" (last use)");
9219 IndirectAssignmentAnnotation* pIndirAnnote;
9220 if (tree->gtOper == GT_ASG && GetIndirAssignMap()->Lookup(tree, &pIndirAnnote))
9222 printf(" indir assign of V%02d:", pIndirAnnote->m_lclNum);
9223 if (pIndirAnnote->m_isEntire)
9225 printf("d:%d", pIndirAnnote->m_defSsaNum);
9229 printf("ud:%d->%d", pIndirAnnote->m_useSsaNum, pIndirAnnote->m_defSsaNum);
9233 if (tree->gtOper == GT_INTRINSIC)
9235 switch (tree->gtIntrinsic.gtIntrinsicId)
9237 case CORINFO_INTRINSIC_Sin: printf(" sin"); break;
9238 case CORINFO_INTRINSIC_Cos: printf(" cos"); break;
9239 case CORINFO_INTRINSIC_Sqrt: printf(" sqrt"); break;
9240 case CORINFO_INTRINSIC_Abs: printf(" abs"); break;
9241 case CORINFO_INTRINSIC_Round: printf(" round"); break;
9242 case CORINFO_INTRINSIC_Cosh: printf(" cosh"); break;
9243 case CORINFO_INTRINSIC_Sinh: printf(" sinh"); break;
9244 case CORINFO_INTRINSIC_Tan: printf(" tan"); break;
9245 case CORINFO_INTRINSIC_Tanh: printf(" tanh"); break;
9246 case CORINFO_INTRINSIC_Asin: printf(" asin"); break;
9247 case CORINFO_INTRINSIC_Acos: printf(" acos"); break;
9248 case CORINFO_INTRINSIC_Atan: printf(" atan"); break;
9249 case CORINFO_INTRINSIC_Atan2: printf(" atan2"); break;
9250 case CORINFO_INTRINSIC_Log10: printf(" log10"); break;
9251 case CORINFO_INTRINSIC_Pow: printf(" pow"); break;
9252 case CORINFO_INTRINSIC_Exp: printf(" exp"); break;
9253 case CORINFO_INTRINSIC_Ceiling: printf(" ceiling"); break;
9254 case CORINFO_INTRINSIC_Floor: printf(" floor"); break;
9255 case CORINFO_INTRINSIC_Object_GetType: printf(" objGetType"); break;
9263 if (tree->gtOper == GT_SIMD)
9265 printf(" %s %s", varTypeName(tree->gtSIMD.gtSIMDBaseType), simdIntrinsicNames[tree->gtSIMD.gtSIMDIntrinsicID]);
9267 #endif // FEATURE_SIMD
9273 if (!topOnly && tree->gtOp.gtOp1)
9276 // Label the child of the GT_COLON operator
9277 // op1 is the else part
9279 if (tree->gtOper == GT_COLON)
9281 else if (tree->gtOper == GT_QMARK)
9284 gtDispChild(tree->gtOp.gtOp1, indentStack, IIArcBottom, childMsg, topOnly);
9291 // Now, get the right type of arc for this node
9292 if (myArc != IINone)
9295 indentStack->Push(myArc);
9297 gtDispNode(tree, indentStack, msg);
9299 // Propagate lowerArc to the lower children.
9300 if (indentStack->Depth() > 0)
9302 (void) indentStack->Pop();
9303 indentStack->Push(lowerArc);
9306 // See what kind of a special operator we have here, and handle its special children.
9308 switch (tree->gtOper)
9311 printf(" %s", eeGetFieldName(tree->gtField.gtFldHnd), 0);
9313 if (tree->gtField.gtFldObj && !topOnly)
9317 gtDispChild(tree->gtField.gtFldObj, indentStack, IIArcBottom);
9329 assert(tree->gtFlags & GTF_CALL);
9330 unsigned numChildren = tree->NumChildren();
9331 GenTree* lastChild = nullptr;
9332 if (numChildren != 0)
9334 lastChild = tree->GetChild(numChildren - 1);
9337 if (tree->gtCall.gtCallType != CT_INDIRECT)
9339 const char * methodName;
9340 const char * className;
9342 methodName = eeGetMethodName(tree->gtCall.gtCallMethHnd, &className);
9344 printf(" %s.%s", className, methodName);
9347 if ((tree->gtFlags & GTF_CALL_UNMANAGED) && (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_FRAME_VAR_DEATH))
9349 printf(" (FramesRoot last use)");
9352 if (((tree->gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0) &&
9353 (tree->gtCall.gtInlineCandidateInfo != NULL) &&
9354 (tree->gtCall.gtInlineCandidateInfo->exactContextHnd != NULL))
9356 printf(" (exactContextHnd=0x%p)", dspPtr(tree->gtCall.gtInlineCandidateInfo->exactContextHnd));
9360 if (tree->IsMultiRegCall())
9373 if ((tree->gtCall.gtCallObjp != NULL) &&
9374 (tree->gtCall.gtCallObjp->gtOper != GT_NOP) &&
9375 (!tree->gtCall.gtCallObjp->IsArgPlaceHolderNode()))
9377 if (tree->gtCall.gtCallObjp->gtOper == GT_ASG)
9378 sprintf_s(bufp, sizeof(buf), "this SETUP%c", 0);
9380 sprintf_s(bufp, sizeof(buf), "this in %s%c", compRegVarName(REG_ARG_0), 0);
9381 gtDispChild(tree->gtCall.gtCallObjp, indentStack, (tree->gtCall.gtCallObjp == lastChild) ? IIArcBottom : IIArc, bufp, topOnly);
9384 if (tree->gtCall.gtCallArgs)
9385 gtDispArgList(tree, indentStack);
9387 if (tree->gtCall.gtCallType == CT_INDIRECT)
9388 gtDispChild(tree->gtCall.gtCallAddr, indentStack, (tree->gtCall.gtCallAddr == lastChild) ? IIArcBottom : IIArc, "calli tgt", topOnly);
9390 if (tree->gtCall.gtControlExpr != nullptr)
9391 gtDispChild(tree->gtCall.gtControlExpr, indentStack, (tree->gtCall.gtControlExpr == lastChild) ? IIArcBottom : IIArc, "control expr", topOnly);
9393 #if !FEATURE_FIXED_OUT_ARGS
9394 regList list = tree->gtCall.regArgList;
9396 /* process the late argument list */
9398 for (GenTreeArgList* lateArgs = tree->gtCall.gtCallLateArgs; lateArgs; (lateArgIndex++, lateArgs = lateArgs->Rest()))
9402 argx = lateArgs->Current();
9404 IndentInfo arcType = (lateArgs->Rest() == nullptr) ? IIArcBottom : IIArc;
9405 gtGetLateArgMsg(tree, argx, lateArgIndex, -1, bufp, sizeof(buf));
9406 gtDispChild(argx, indentStack, arcType, bufp, topOnly);
9416 gtDispChild(tree->gtStmt.gtStmtExpr, indentStack, IIArcBottom);
9425 gtDispChild(tree->gtArrElem.gtArrObj, indentStack, IIArc, nullptr, topOnly);
9428 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
9430 IndentInfo arcType = ((dim + 1) == tree->gtArrElem.gtArrRank) ? IIArcBottom : IIArc;
9431 gtDispChild(tree->gtArrElem.gtArrInds[dim], indentStack, arcType, nullptr, topOnly);
9441 gtDispChild(tree->gtArrOffs.gtOffset, indentStack, IIArc, nullptr, topOnly);
9442 gtDispChild(tree->gtArrOffs.gtIndex, indentStack, IIArc, nullptr, topOnly);
9443 gtDispChild(tree->gtArrOffs.gtArrObj, indentStack, IIArcBottom, nullptr, topOnly);
9452 gtDispChild(tree->gtCmpXchg.gtOpLocation, indentStack, IIArc, nullptr, topOnly);
9453 gtDispChild(tree->gtCmpXchg.gtOpValue, indentStack, IIArc, nullptr, topOnly);
9454 gtDispChild(tree->gtCmpXchg.gtOpComparand, indentStack, IIArcBottom, nullptr, topOnly);
9458 case GT_ARR_BOUNDS_CHECK:
9461 #endif // FEATURE_SIMD
9466 gtDispChild(tree->gtBoundsChk.gtArrLen, indentStack, IIArc, nullptr, topOnly);
9467 gtDispChild(tree->gtBoundsChk.gtIndex, indentStack, IIArcBottom, nullptr, topOnly);
9472 printf("<DON'T KNOW HOW TO DISPLAY THIS NODE> :");
9473 printf(""); // null string means flush
9478 //------------------------------------------------------------------------
9479 // gtGetArgMsg: Construct a message about the given argument
9482 // call - The call for which 'arg' is an argument
9483 // arg - The argument for which a message should be constructed
9484 // argNum - The ordinal number of the arg in the argument list
9485 // listCount - When printing in Linear form this is the count for a multireg GT_LIST
9486 // or -1 if we are not printing in Linear form
9487 // bufp - A pointer to the buffer into which the message is written
9488 // bufLength - The length of the buffer pointed to by bufp
9491 // No return value, but bufp is written.
9494 // 'call' must be a call node
9495 // 'arg' must be an argument to 'call' (else gtArgEntryByNode will assert)
9497 void Compiler::gtGetArgMsg(GenTreePtr call,
9504 if (call->gtCall.gtCallLateArgs != NULL)
9506 fgArgTabEntryPtr curArgTabEntry = gtArgEntryByArgNum(call, argNum);
9507 assert(curArgTabEntry);
9509 if (arg->gtFlags & GTF_LATE_ARG)
9511 sprintf_s(bufp, bufLength, "arg%d SETUP%c", argNum, 0);
9515 #if FEATURE_FIXED_OUT_ARGS
9516 if (listCount == -1)
9518 sprintf_s(bufp, bufLength, "arg%d out+%02x%c", argNum, curArgTabEntry->slotNum * TARGET_POINTER_SIZE, 0);
9520 else // listCount is 0,1,2 or 3
9522 assert(listCount <= MAX_ARG_REG_COUNT);
9523 sprintf_s(bufp, bufLength, "arg%d out+%02x%c", argNum, (curArgTabEntry->slotNum + listCount) * TARGET_POINTER_SIZE, 0);
9526 sprintf_s(bufp, bufLength, "arg%d on STK%c", argNum, 0);
9532 sprintf_s(bufp, bufLength, "arg%d%c", argNum, 0);
9536 //------------------------------------------------------------------------
9537 // gtGetLateArgMsg: Construct a message about the given argument
9540 // call - The call for which 'arg' is an argument
9541 // argx - The argument for which a message should be constructed
9542 // lateArgIndex - The ordinal number of the arg in the lastArg list
9543 // listCount - When printing in Linear form this is the count for a multireg GT_LIST
9544 // or -1 if we are not printing in Linear form
9545 // bufp - A pointer to the buffer into which the message is written
9546 // bufLength - The length of the buffer pointed to by bufp
9549 // No return value, but bufp is written.
9552 // 'call' must be a call node
9553 // 'arg' must be an argument to 'call' (else gtArgEntryByNode will assert)
9555 void Compiler::gtGetLateArgMsg(GenTreePtr call,
9562 assert(!argx->IsArgPlaceHolderNode()); // No place holders nodes are in gtCallLateArgs;
9564 fgArgTabEntryPtr curArgTabEntry = gtArgEntryByLateArgIndex(call, lateArgIndex);
9565 assert(curArgTabEntry);
9566 regNumber argReg = curArgTabEntry->regNum;
9568 #if !FEATURE_FIXED_OUT_ARGS
9569 assert(lateArgIndex < call->gtCall.regArgListCount);
9570 assert(argReg == call->gtCall.regArgList[lateArgIndex]);
9572 if (argReg == REG_STK)
9574 sprintf_s(bufp, bufLength, "arg%d in out+%02x%c", curArgTabEntry->argNum, curArgTabEntry->slotNum * TARGET_POINTER_SIZE, 0);
9579 if (gtArgIsThisPtr(curArgTabEntry))
9581 sprintf_s(bufp, bufLength, "this in %s%c", compRegVarName(argReg), 0);
9585 #if FEATURE_MULTIREG_ARGS
9586 if (curArgTabEntry->numRegs >= 2)
9588 regNumber otherRegNum;
9589 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
9590 assert(curArgTabEntry->numRegs == 2);
9591 otherRegNum = curArgTabEntry->otherRegNum;
9593 otherRegNum = (regNumber)(((unsigned)curArgTabEntry->regNum) + curArgTabEntry->numRegs - 1);
9594 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
9596 if (listCount == -1)
9598 char seperator = (curArgTabEntry->numRegs == 2) ? ',' : '-';
9600 sprintf_s(bufp, bufLength, "arg%d %s%c%s%c", curArgTabEntry->argNum,
9601 compRegVarName(argReg), seperator, compRegVarName(otherRegNum), 0);
9603 else // listCount is 0,1,2 or 3
9605 assert(listCount <= MAX_ARG_REG_COUNT);
9606 regNumber curReg = (listCount == 1) ? otherRegNum : (regNumber)((unsigned)(argReg)+listCount);
9607 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", curArgTabEntry->argNum, listCount, compRegVarName(curReg), 0);
9613 sprintf_s(bufp, bufLength, "arg%d in %s%c", curArgTabEntry->argNum, compRegVarName(argReg), 0);
9619 //------------------------------------------------------------------------
9620 // gtDispArgList: Dump the tree for a call arg list
9623 // tree - The call for which 'arg' is an argument
9624 // indentStack - the specification for the current level of indentation & arcs
9630 // 'tree' must be a call node
9632 void Compiler::gtDispArgList(GenTreePtr tree,
9633 IndentStack* indentStack)
9635 GenTree * args = tree->gtCall.gtCallArgs;
9636 unsigned argnum = 0;
9637 const int BufLength = 256;
9638 char buf[BufLength];
9639 char * bufp = &buf[0];
9640 unsigned numChildren = tree->NumChildren();
9641 assert(numChildren != 0);
9642 bool argListIsLastChild = (args == tree->GetChild(numChildren - 1));
9644 IndentInfo arcType = IIArc;
9645 if (tree->gtCall.gtCallObjp != NULL)
9650 assert(args->gtOper == GT_LIST);
9651 GenTree* arg = args->gtOp.gtOp1;
9652 if (!arg->IsNothingNode() && !arg->IsArgPlaceHolderNode())
9654 gtGetArgMsg(tree, arg, argnum, -1, bufp, BufLength);
9655 if (argListIsLastChild && (args->gtOp.gtOp2 == nullptr))
9657 arcType = IIArcBottom;
9659 gtDispChild(arg, indentStack, arcType, bufp, false);
9661 args = args->gtOp.gtOp2;
9666 //------------------------------------------------------------------------
9667 // gtDispArgList: Dump the tree for a call arg list
9670 // tree - The call for which 'arg' is an argument
9671 // indentStack - the specification for the current level of indentation & arcs
9677 // 'tree' must be a GT_LIST node
9679 void Compiler::gtDispTreeList(GenTreePtr tree,
9680 IndentStack* indentStack /* = nullptr */)
9682 for (/*--*/; tree != nullptr; tree = tree->gtNext)
9684 gtDispTree(tree, indentStack);
9689 //------------------------------------------------------------------------
9690 // nextPrintable: Retrieves the next gtNode that can be dumped in linear order
9693 // next - The call for which 'arg' is an argument
9694 // tree - the specification for the current level of indentation & arcs
9697 // The next node to be printed in linear order.
9699 GenTree* nextPrintable(GenTree* next, GenTree* tree)
9701 assert(next != nullptr);
9702 assert(tree != nullptr);
9704 // Skip any nodes that are in the linear order, but that we don't actually visit
9705 while (next != tree && (next->IsList() || next->IsArgPlaceHolderNode()))
9707 next = next->gtNext;
9712 //------------------------------------------------------------------------
9713 // gtDispLinearTree: Dump a tree in linear order
9716 // curStmt - The current statement being dumped
9717 // nextLinearNode - The next node to be printed
9718 // tree - The current tree being traversed
9719 // indentStack - the specification for the current level of indentation & arcs
9720 // msg - a contextual method (i.e. from the parent) to print
9726 // 'tree' must be a GT_LIST node
9729 // 'nextLinearNode' tracks the node we should be printing next.
9730 // In general, we should encounter it as we traverse the tree. If not, we
9731 // have an embedded statement, so that statement is then printed within
9732 // the dump for this statement.
9734 GenTreePtr Compiler::gtDispLinearTree(GenTreeStmt* curStmt,
9735 GenTreePtr nextLinearNode,
9737 IndentStack* indentStack,
9738 __in __in_z __in_opt const char * msg /* = nullptr */)
9740 const int BufLength = 256;
9741 char buf[BufLength];
9742 char * bufp = &buf[0];
9744 // Determine what kind of arc to propagate
9745 IndentInfo myArc = IINone;
9746 if (indentStack->Depth() > 0)
9748 myArc = indentStack->Pop();
9749 if (myArc == IIArcBottom || myArc == IIArc)
9751 indentStack->Push(IIArc);
9755 assert(myArc == IIArcTop);
9756 indentStack->Push(IINone);
9761 unsigned childCount = tree->NumChildren();
9762 GenTreePtr deferChild = nullptr;
9763 for (unsigned i = 0;
9767 unsigned childIndex = i;
9768 if (tree->OperIsBinary() && tree->IsReverseOp())
9770 childIndex = (i == 0) ? 1 : 0;
9773 GenTreePtr child = tree->GetChild(childIndex);
9774 IndentInfo indentInfo = (i == 0) ? IIArcTop : IIArc;
9776 if (tree->OperGet() == GT_COLON && i == 1)
9782 unsigned listElemNum = 0;
9783 const char* childMsg = nullptr;
9786 if (child == tree->gtCall.gtCallObjp)
9788 if (child->gtOper == GT_ASG)
9790 sprintf_s(bufp, sizeof(buf), "this SETUP%c", 0);
9794 sprintf_s(bufp, sizeof(buf), "this in %s%c", compRegVarName(REG_ARG_0), 0);
9798 else if (child == tree->gtCall.gtCallAddr)
9800 childMsg = "calli tgt";
9802 else if (child == tree->gtCall.gtControlExpr)
9804 childMsg = "control expr";
9806 else if (child == tree->gtCall.gtCallCookie)
9808 childMsg = "cookie";
9810 else if (child == tree->gtCall.gtCallArgs)
9812 // List is handled below, but adjust listElemNum to account for "this" if necessary
9813 if (tree->gtCall.gtCallObjp != nullptr)
9818 // Late args list is handled below
9819 assert(child == tree->gtCall.gtCallLateArgs);
9823 if (child->OperGet() == GT_LIST)
9825 // For each list element
9826 GenTreePtr nextList = nullptr;
9827 if (child->gtOp.gtOp2 != nullptr
9828 && child->gtOp.gtOp2->gtOper != GT_LIST)
9830 // special case for child of initblk and cpblk
9831 // op1 is dst, op2 is src, and op2 must show up first
9832 assert(tree->OperIsBlkOp());
9833 sprintf_s(bufp, sizeof(buf), "Source");
9834 indentStack->Push(indentInfo);
9835 nextLinearNode = gtDispLinearTree(curStmt, nextLinearNode, child->gtOp.gtOp2, indentStack, bufp);
9839 sprintf_s(bufp, sizeof(buf), "Destination");
9840 indentStack->Push(indentInfo);
9841 nextLinearNode = gtDispLinearTree(curStmt, nextLinearNode, child->gtOp.gtOp1, indentStack, bufp);
9846 // normal null-terminated list case
9848 for (GenTreePtr list = child; list != nullptr; list = nextList)
9850 GenTreePtr listElem;
9851 if (list->gtOper == GT_LIST)
9853 nextList = list->gtGetOp2();
9854 listElem = list->gtGetOp1();
9858 // GT_LIST nodes (under initBlk, others?) can have a non-null op2 that's not a GT_LIST
9866 // If this is a call and the arg (listElem) is a GT_LIST (Unix LCL_FLD for passing a var in multiple registers)
9867 // print the nodes of the nested list and continue to the next argument.
9868 if (listElem->gtOper == GT_LIST)
9871 GenTreePtr nextListNested = nullptr;
9872 for (GenTreePtr listNested = listElem; listNested != nullptr; listNested = nextListNested)
9874 GenTreePtr listElemNested;
9875 if (listNested->gtOper == GT_LIST)
9877 nextListNested = listNested->MoveNext();
9878 listElemNested = listNested->Current();
9882 // GT_LIST nodes (under initBlk, others?) can have a non-null op2 that's not a GT_LIST
9883 nextListNested = nullptr;
9884 listElemNested = listNested;
9887 indentStack->Push(indentInfo);
9888 if (child == tree->gtCall.gtCallArgs)
9890 gtGetArgMsg(tree, listNested, listElemNum, listCount, bufp, BufLength);
9894 assert(child == tree->gtCall.gtCallLateArgs);
9895 gtGetLateArgMsg(tree, listNested, listElemNum, listCount, bufp, BufLength);
9898 nextLinearNode = gtDispLinearTree(curStmt, nextLinearNode, listElemNested, indentStack, bufp);
9902 // Skip the GT_LIST nodes, as we do not print them, and the next node to print will occur
9904 while (nextLinearNode->OperGet() == GT_LIST)
9906 nextLinearNode = nextLinearNode->gtNext;
9913 if (child == tree->gtCall.gtCallArgs)
9915 gtGetArgMsg(tree, listElem, listElemNum, -1, bufp, BufLength);
9919 assert(child == tree->gtCall.gtCallLateArgs);
9920 gtGetLateArgMsg(tree, listElem, listElemNum, -1, bufp, BufLength);
9925 sprintf_s(bufp, sizeof(buf), "List Item %d", listElemNum);
9928 indentStack->Push(indentInfo);
9929 nextLinearNode = gtDispLinearTree(curStmt, nextLinearNode, listElem, indentStack, bufp);
9936 // Skip the GT_LIST nodes, as we do not print them, and the next node to print will occur
9938 while (nextLinearNode->OperGet() == GT_LIST)
9940 nextLinearNode = nextLinearNode->gtNext;
9945 indentStack->Push(indentInfo);
9946 nextLinearNode = gtDispLinearTree(curStmt, nextLinearNode, child, indentStack, childMsg);
9950 // This sometimes gets called before nodes have been properly sequenced.
9951 // TODO-Cleanup: Determine whether this needs to be hardened in some way.
9952 if (nextLinearNode == nullptr)
9954 printf("BROKEN LINEAR ORDER\n");
9955 nextLinearNode = tree;
9958 // If we don't have a 'curStmt', we're only printing the local tree, so skip
9959 // any embedded statements
9960 if (curStmt != nullptr)
9962 while (nextLinearNode != tree)
9964 // Get the next statement, which had better be embedded
9965 GenTreePtr nextStmt = curStmt->gtNext;
9966 while (nextStmt != nullptr &&
9967 nextStmt->gtStmt.gtStmtIsEmbedded() &&
9968 nextStmt->gtStmt.gtStmtList != nextLinearNode)
9970 nextStmt = nextStmt->gtNext;
9973 if(nextStmt != nullptr && nextStmt->gtStmt.gtStmtList == nextLinearNode)
9975 indentStack->Push(IIEmbedded);
9976 nextLinearNode = gtDispLinearStmt(nextStmt->AsStmt(), indentStack);
9979 else if (nextLinearNode != nullptr)
9981 // If we have an inconsistency, attempt to print the rest of the broken tree, but don't assert,
9982 // since we don't really want to have different asserts when dumping.
9983 // The method should fail later with an assert in fgDebugCheckNodeLinks() the next time it's called.
9984 // Print the next node in linear order, and eventually we will reach the end of the statement,
9985 // or sync up to 'tree'
9986 IndentInfo saveInfo = indentStack->Pop();
9987 indentStack->Push(IIError);
9988 gtDispTree(nextLinearNode, indentStack, msg, true /*topOnly*/);
9989 nextLinearNode = nextLinearNode->gtNext;
9991 indentStack->Push(saveInfo);
10000 // Now, get the right type of arc for this node
10001 if (myArc != IINone)
10003 indentStack->Pop();
10004 indentStack->Push(myArc);
10006 gtDispTree(tree, indentStack, msg, true /*topOnly*/);
10007 nextLinearNode = tree->gtNext;
10009 if (deferChild != nullptr)
10011 indentStack->Push(IIArcBottom);
10012 nextLinearNode = gtDispLinearTree(curStmt, nextLinearNode, deferChild, indentStack);
10013 indentStack->Pop();
10016 return nextLinearNode;
10019 //------------------------------------------------------------------------
10020 // gtDispLinearStmt: Dump a statement in linear order
10023 // stmt - The current statement being dumped
10024 // indentStack - the specification for the current level of indentation & arcs
10027 // A pointer to the tree that is next in the linear traversal.
10028 // This will generally be null, except when this statement is embedded.
10031 // 'stmt' must be a GT_STMT node
10033 GenTreePtr Compiler::gtDispLinearStmt(GenTreeStmt* stmt, IndentStack *indentStack /* = nullptr */)
10035 if (indentStack == nullptr)
10037 indentStack = new (this, CMK_DebugOnly) IndentStack(this);
10039 gtDispTree(stmt, indentStack, nullptr, true /*topOnly*/);
10040 indentStack->Push(IIArcBottom);
10041 GenTreePtr nextLinearNode = gtDispLinearTree(stmt, stmt->gtStmtList, stmt->gtStmtExpr, indentStack);
10042 indentStack->Pop();
10043 return nextLinearNode;
10046 /*****************************************************************************/
10049 /*****************************************************************************
10051 * Check if the given node can be folded,
10052 * and call the methods to perform the folding
10055 GenTreePtr Compiler::gtFoldExpr(GenTreePtr tree)
10057 unsigned kind = tree->OperKind();
10059 /* We must have a simple operation to fold */
10061 // If we're in CSE, it's not safe to perform tree
10062 // folding given that it can will potentially
10063 // change considered CSE candidates.
10064 if(optValnumCSE_phase)
10067 if (!(kind & GTK_SMPOP))
10070 GenTreePtr op1 = tree->gtOp.gtOp1;
10072 /* Filter out non-foldable trees that can have constant children */
10074 assert (kind & (GTK_UNOP | GTK_BINOP));
10075 switch (tree->gtOper)
10085 /* try to fold the current node */
10087 if ((kind & GTK_UNOP) && op1)
10089 if (op1->OperKind() & GTK_CONST)
10090 return gtFoldExprConst(tree);
10092 else if ((kind & GTK_BINOP) && op1 && tree->gtOp.gtOp2 &&
10093 // Don't take out conditionals for debugging
10094 !((opts.compDbgCode || opts.MinOpts()) &&
10095 tree->OperIsCompare()))
10097 GenTreePtr op2 = tree->gtOp.gtOp2;
10099 // The atomic operations are exempted here because they are never computable statically;
10100 // one of their arguments is an address.
10101 if (((op1->OperKind() & op2->OperKind()) & GTK_CONST) && !tree->OperIsAtomicOp())
10103 /* both nodes are constants - fold the expression */
10104 return gtFoldExprConst(tree);
10106 else if ((op1->OperKind() | op2->OperKind()) & GTK_CONST)
10108 /* at least one is a constant - see if we have a
10109 * special operator that can use only one constant
10110 * to fold - e.g. booleans */
10112 return gtFoldExprSpecial(tree);
10114 else if (tree->OperIsCompare())
10116 /* comparisons of two local variables can sometimes be folded */
10118 return gtFoldExprCompare(tree);
10120 else if (op2->OperGet() == GT_COLON)
10122 assert(tree->OperGet() == GT_QMARK);
10124 GenTreePtr colon_op1 = op2->gtOp.gtOp1;
10125 GenTreePtr colon_op2 = op2->gtOp.gtOp2;
10127 if (gtCompareTree(colon_op1, colon_op2))
10129 // Both sides of the GT_COLON are the same tree
10131 GenTreePtr sideEffList = NULL;
10132 gtExtractSideEffList(op1, &sideEffList);
10134 fgUpdateRefCntForExtract(op1, sideEffList); // Decrement refcounts for op1, Keeping any side-effects
10135 fgUpdateRefCntForExtract(colon_op1, NULL); // Decrement refcounts for colon_op1
10137 // Clear colon flags only if the qmark itself is not conditionaly executed
10138 if ( (tree->gtFlags & GTF_COLON_COND)==0 )
10140 fgWalkTreePre(&colon_op2, gtClearColonCond);
10143 if (sideEffList == NULL)
10145 // No side-effects, just return colon_op2
10153 printf("\nIdentical GT_COLON trees with side effects! Extracting side effects...\n");
10154 gtDispTree(sideEffList); printf("\n");
10157 // Change the GT_COLON into a GT_COMMA node with the side-effects
10158 op2->ChangeOper(GT_COMMA);
10159 op2->gtFlags |= (sideEffList->gtFlags & GTF_ALL_EFFECT);
10160 op2->gtOp.gtOp1 = sideEffList;
10168 /* Return the original node (folded/bashed or not) */
10173 /*****************************************************************************
10175 * Some comparisons can be folded:
10178 * classVarA == classVarA
10179 * locA + locB == locB + locA
10183 GenTreePtr Compiler::gtFoldExprCompare(GenTreePtr tree)
10185 GenTreePtr op1 = tree->gtOp.gtOp1;
10186 GenTreePtr op2 = tree->gtOp.gtOp2;
10188 assert(tree->OperIsCompare());
10190 /* Filter out cases that cannot be folded here */
10192 /* Do not fold floats or doubles (e.g. NaN != Nan) */
10194 if (varTypeIsFloating(op1->TypeGet()))
10197 /* Currently we can only fold when the two subtrees exactly match */
10199 if ((tree->gtFlags & GTF_SIDE_EFFECT) || GenTree::Compare(op1, op2, true) == false)
10200 return tree; /* return unfolded tree */
10204 switch (tree->gtOper)
10209 cons = gtNewIconNode(true); /* Folds to GT_CNS_INT(true) */
10215 cons = gtNewIconNode(false); /* Folds to GT_CNS_INT(false) */
10219 assert(!"Unexpected relOp");
10223 /* The node has beeen folded into 'cons' */
10227 if (!fgIsInlining())
10228 fgMorphTreeDone(cons);
10232 cons->gtNext = tree->gtNext;
10233 cons->gtPrev = tree->gtPrev;
10235 if (lvaLocalVarRefCounted)
10237 lvaRecursiveDecRefCounts(tree);
10243 /*****************************************************************************
10245 * Some binary operators can be folded even if they have only one
10246 * operand constant - e.g. boolean operators, add with 0
10247 * multiply with 1, etc
10250 GenTreePtr Compiler::gtFoldExprSpecial(GenTreePtr tree)
10252 GenTreePtr op1 = tree->gtOp.gtOp1;
10253 GenTreePtr op2 = tree->gtOp.gtOp2;
10254 genTreeOps oper = tree->OperGet();
10256 GenTreePtr op, cons;
10259 assert(tree->OperKind() & GTK_BINOP);
10261 /* Filter out operators that cannot be folded here */
10262 if (oper == GT_CAST)
10265 /* We only consider TYP_INT for folding
10266 * Do not fold pointer arithmetic (e.g. addressing modes!) */
10268 if (oper != GT_QMARK && !varTypeIsIntOrI(tree->gtType))
10271 /* Find out which is the constant node */
10273 if (op1->IsCnsIntOrI())
10278 else if (op2->IsCnsIntOrI())
10286 /* Get the constant value */
10288 val = cons->gtIntConCommon.IconValue();
10290 /* Here op is the non-constant operand, val is the constant,
10291 first is true if the constant is op1 */
10298 // Optimize boxed value classes; these are always false. This IL is
10299 // generated when a generic value is tested against null:
10300 // <T> ... foo(T x) { ... if ((object)x == null) ...
10301 if (val == 0 && op->IsBoxedValue())
10303 // Change the assignment node so we don't generate any code for it.
10305 GenTreePtr asgStmt = op->gtBox.gtAsgStmtWhenInlinedBoxValue;
10306 assert(asgStmt->gtOper == GT_STMT);
10307 GenTreePtr asg = asgStmt->gtStmt.gtStmtExpr;
10308 assert(asg->gtOper == GT_ASG);
10312 printf("Bashing ");
10314 printf(" to NOP as part of dead box operation\n");
10318 asg->gtBashToNOP();
10320 op = gtNewIconNode(oper == GT_NE);
10323 if (!fgIsInlining())
10324 fgMorphTreeDone(op);
10328 op->gtNext = tree->gtNext;
10329 op->gtPrev = tree->gtPrev;
10331 fgSetStmtSeq(asgStmt);
10338 if (val == 0) goto DONE_FOLD;
10347 /* Multiply by zero - return the 'zero' node, but not if side effects */
10348 if (!(op->gtFlags & GTF_SIDE_EFFECT))
10350 if (lvaLocalVarRefCounted)
10352 lvaRecursiveDecRefCounts(op);
10363 if ((op2 == cons) && (val == 1) && !(op1->OperKind() & GTK_CONST))
10371 if ((op2 == cons) && (val == 0) && !(op1->OperKind() & GTK_CONST))
10380 /* AND with zero - return the 'zero' node, but not if side effects */
10382 if (!(op->gtFlags & GTF_SIDE_EFFECT))
10384 if (lvaLocalVarRefCounted)
10386 lvaRecursiveDecRefCounts(op);
10394 /* The GTF_BOOLEAN flag is set for nodes that are part
10395 * of a boolean expression, thus all their children
10396 * are known to evaluate to only 0 or 1 */
10398 if (tree->gtFlags & GTF_BOOLEAN)
10401 /* The constant value must be 1
10402 * AND with 1 stays the same */
10412 else if (tree->gtFlags & GTF_BOOLEAN)
10414 /* The constant value must be 1 - OR with 1 is 1 */
10418 /* OR with one - return the 'one' node, but not if side effects */
10420 if (!(op->gtFlags & GTF_SIDE_EFFECT))
10422 if (lvaLocalVarRefCounted)
10424 lvaRecursiveDecRefCounts(op);
10444 else if (!(op->gtFlags & GTF_SIDE_EFFECT))
10446 if (lvaLocalVarRefCounted)
10448 lvaRecursiveDecRefCounts(op);
10458 assert(op1 == cons && op2 == op && op2->gtOper == GT_COLON);
10459 assert(op2->gtOp.gtOp1 && op2->gtOp.gtOp2);
10461 assert(val == 0 || val == 1);
10463 GenTree* opToDelete;
10466 op = op2->AsColon()->ThenNode();
10467 opToDelete = op2->AsColon()->ElseNode();
10471 op = op2->AsColon()->ElseNode();
10472 opToDelete = op2->AsColon()->ThenNode();
10474 if (lvaLocalVarRefCounted)
10476 lvaRecursiveDecRefCounts(opToDelete);
10479 // Clear colon flags only if the qmark itself is not conditionaly executed
10480 if ( (tree->gtFlags & GTF_COLON_COND)==0 )
10482 fgWalkTreePre(&op, gtClearColonCond);
10492 /* The node is not foldable */
10498 /* The node has beeen folded into 'op' */
10500 // If there was an assigment update, we just morphed it into
10501 // a use, update the flags appropriately
10502 if (op->gtOper == GT_LCL_VAR)
10504 assert ((tree->OperKind() & GTK_ASGOP) ||
10505 (op->gtFlags & (GTF_VAR_USEASG | GTF_VAR_USEDEF | GTF_VAR_DEF)) == 0);
10507 op->gtFlags &= ~(GTF_VAR_USEASG | GTF_VAR_USEDEF | GTF_VAR_DEF);
10510 op->gtNext = tree->gtNext;
10511 op->gtPrev = tree->gtPrev;
10516 /*****************************************************************************
10518 * Fold the given constant tree.
10522 #pragma warning(push)
10523 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
10525 GenTreePtr Compiler::gtFoldExprConst(GenTreePtr tree)
10527 unsigned kind = tree->OperKind();
10529 SSIZE_T i1, i2, itemp;
10530 INT64 lval1, lval2, ltemp;
10533 var_types switchType;
10534 FieldSeqNode* fieldSeq = FieldSeqStore::NotAField(); // default unless we override it when folding
10536 assert (kind & (GTK_UNOP | GTK_BINOP));
10538 GenTreePtr op1 = tree->gtOp.gtOp1;
10539 GenTreePtr op2 = tree->gtGetOp2();
10541 if (!opts.OptEnabled(CLFLG_CONSTANTFOLD))
10546 if (tree->OperGet() == GT_NOP)
10551 #ifdef FEATURE_SIMD
10552 if (tree->OperGet() == GT_SIMD)
10556 #endif // FEATURE_SIMD
10558 if (kind & GTK_UNOP)
10560 assert(op1->OperKind() & GTK_CONST);
10562 switch (op1->gtType)
10566 /* Fold constant INT unary operator */
10567 assert(op1->gtIntCon.ImmedValCanBeFolded(this, tree->OperGet()));
10568 i1 = (int) op1->gtIntCon.gtIconVal;
10570 // If we fold a unary oper, then the folded constant
10571 // is considered a ConstantIndexField if op1 was one
10574 if ((op1->gtIntCon.gtFieldSeq != nullptr) &&
10575 op1->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
10577 fieldSeq = op1->gtIntCon.gtFieldSeq;
10580 switch (tree->gtOper)
10582 case GT_NOT: i1 = ~i1; break;
10585 case GT_CHS: i1 = -i1; break;
10588 // assert (genActualType(tree->CastToType()) == tree->gtType);
10589 switch (tree->CastToType())
10592 itemp = INT32(INT8(i1));
10596 itemp = INT32(INT16(i1));
10598 if (tree->gtOverflow() &&
10600 ((tree->gtFlags & GTF_UNSIGNED) && i1 < 0)))
10604 i1 = itemp; goto CNS_INT;
10607 itemp = INT32(UINT16(i1));
10608 if (tree->gtOverflow())
10609 if (itemp != i1) goto INT_OVF;
10615 itemp = INT32(UINT8(i1));
10616 if (tree->gtOverflow()) if (itemp != i1) goto INT_OVF;
10617 i1 = itemp; goto CNS_INT;
10620 if (!(tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && i1 < 0)
10625 if ((tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && i1 < 0)
10630 if (!(tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && i1 < 0)
10632 op1->ChangeOperConst(GT_CNS_NATIVELONG); // need type of oper to be same as tree
10633 op1->gtType = TYP_LONG;
10634 // We don't care about the value as we are throwing an exception
10637 lval1 = UINT64(UINT32(i1));
10641 if (tree->gtFlags & GTF_UNSIGNED)
10643 lval1 = INT64(UINT32(i1));
10647 lval1 = INT64(INT32(i1));
10652 if (tree->gtFlags & GTF_UNSIGNED)
10653 f1 = forceCastToFloat(UINT32(i1));
10655 f1 = forceCastToFloat(INT32(i1));
10660 if (tree->gtFlags & GTF_UNSIGNED)
10661 d1 = (double) UINT32(i1);
10663 d1 = (double) INT32(i1);
10667 assert(!"BAD_TYP");
10680 /* Fold constant LONG unary operator */
10682 assert(op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()));
10683 lval1 = op1->gtIntConCommon.LngValue();
10685 switch (tree->gtOper)
10687 case GT_NOT: lval1 = ~lval1; break;
10690 case GT_CHS: lval1 = -lval1; break;
10693 assert (genActualType(tree->CastToType()) == tree->gtType);
10694 switch (tree->CastToType())
10697 i1 = INT32(INT8(lval1));
10698 goto CHECK_INT_OVERFLOW;
10701 i1 = INT32(INT16(lval1));
10702 goto CHECK_INT_OVERFLOW;
10705 i1 = INT32(UINT16(lval1));
10706 goto CHECK_UINT_OVERFLOW;
10709 i1 = INT32(UINT8(lval1));
10710 goto CHECK_UINT_OVERFLOW;
10715 CHECK_INT_OVERFLOW:
10716 if (tree->gtOverflow())
10720 if ((tree->gtFlags & GTF_UNSIGNED) && i1 < 0)
10726 i1 = UINT32(lval1);
10728 CHECK_UINT_OVERFLOW:
10729 if (tree->gtOverflow() && UINT32(i1) != lval1)
10734 if (!(tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && lval1 < 0)
10739 if ( (tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && lval1 < 0)
10745 if ((tree->gtFlags & GTF_UNSIGNED) && lval1 < 0)
10747 d1 = FloatingPointUtils::convertUInt64ToDouble((unsigned __int64)lval1);
10751 d1 = (double)lval1;
10754 if (tree->CastToType() == TYP_FLOAT)
10756 f1 = forceCastToFloat(d1); // truncate precision
10761 assert(!"BAD_TYP");
10774 assert(op1->gtOper == GT_CNS_DBL);
10776 /* Fold constant DOUBLE unary operator */
10778 d1 = op1->gtDblCon.gtDconVal;
10780 switch (tree->gtOper)
10789 if (tree->gtOverflowEx())
10792 assert (genActualType(tree->CastToType()) == tree->gtType);
10794 if ((op1->gtType == TYP_FLOAT && !_finite(forceCastToFloat(d1))) ||
10795 (op1->gtType == TYP_DOUBLE && !_finite(d1)))
10797 // The floating point constant is not finite. The ECMA spec says, in
10798 // III 3.27, that "...if overflow occurs converting a floating point type
10799 // to an integer, ..., the value returned is unspecified." However, it would
10800 // at least be desirable to have the same value returned for casting an overflowing
10801 // constant to an int as would obtained by passing that constant as a parameter
10802 // then casting that parameter to an int type. We will assume that the C compiler's
10803 // cast logic will yield the desired result (and trust testing to tell otherwise).
10804 // Cross-compilation is an issue here; if that becomes an important scenario, we should
10805 // capture the target-specific values of overflow casts to the various integral types as
10806 // constants in a target-specific function.
10808 #ifdef _TARGET_XARCH_
10809 // Don't fold conversions of +inf/-inf to integral value as the value returned by JIT helper
10810 // doesn't match with the C compiler's cast result.
10812 #else //!_TARGET_XARCH_
10814 switch (tree->CastToType())
10817 i1 = ssize_t(INT8(d1)); goto CNS_INT;
10819 i1 = ssize_t(UINT8(d1)); goto CNS_INT;
10821 i1 = ssize_t(INT16(d1)); goto CNS_INT;
10823 i1 = ssize_t(UINT16(d1)); goto CNS_INT;
10825 i1 = ssize_t(INT32(d1)); goto CNS_INT;
10827 i1 = ssize_t(UINT32(d1)); goto CNS_INT;
10829 lval1 = INT64(d1); goto CNS_LONG;
10831 lval1 = UINT64(d1); goto CNS_LONG;
10834 if (op1->gtType == TYP_FLOAT)
10835 d1 = forceCastToFloat(d1); // it's only !_finite() after this conversion
10840 #endif //!_TARGET_XARCH_
10843 switch (tree->CastToType())
10846 i1 = INT32(INT8(d1)); goto CNS_INT;
10849 i1 = INT32(INT16(d1)); goto CNS_INT;
10852 i1 = INT32(UINT16(d1)); goto CNS_INT;
10855 i1 = INT32(UINT8(d1)); goto CNS_INT;
10858 i1 = INT32(d1); goto CNS_INT;
10861 i1 = forceCastToUInt32(d1); goto CNS_INT;
10864 lval1 = INT64(d1); goto CNS_LONG;
10867 lval1 = FloatingPointUtils::convertDoubleToUInt64(d1);
10871 d1 = forceCastToFloat(d1);
10875 if (op1->gtType == TYP_FLOAT)
10876 d1 = forceCastToFloat(d1); // truncate precision
10877 goto CNS_DOUBLE; // redundant cast
10880 assert(!"BAD_TYP");
10891 /* not a foldable typ - e.g. RET const */
10896 /* We have a binary operator */
10898 assert(kind & GTK_BINOP);
10900 assert(op1->OperKind() & GTK_CONST);
10901 assert(op2->OperKind() & GTK_CONST);
10903 if (tree->gtOper == GT_COMMA)
10906 if (tree->gtOper == GT_LIST)
10909 switchType = op1->gtType;
10911 // Normally we will just switch on op1 types, but for the case where
10912 // only op2 is a GC type and op1 is not a GC type, we use the op2 type.
10913 // This makes us handle this as a case of folding for GC type.
10915 if (varTypeIsGC(op2->gtType) && !varTypeIsGC(op1->gtType))
10917 switchType = op2->gtType;
10920 switch (switchType)
10923 /*-------------------------------------------------------------------------
10924 * Fold constant REF of BYREF binary operator
10925 * These can only be comparisons or null pointers
10930 /* String nodes are an RVA at this point */
10932 if (op1->gtOper == GT_CNS_STR || op2->gtOper == GT_CNS_STR)
10939 i1 = op1->gtIntConCommon.IconValue();
10940 i2 = op2->gtIntConCommon.IconValue();
10942 switch (tree->gtOper)
10953 noway_assert(tree->gtType != TYP_REF);
10954 // We only fold a GT_ADD that involves a null reference.
10955 if (((op1->TypeGet() == TYP_REF) && (i1 == 0)) ||
10956 ((op2->TypeGet() == TYP_REF) && (i2 == 0)))
10961 printf("\nFolding operator with constant nodes into a constant:\n");
10965 // Fold into GT_IND of null byref
10966 tree->ChangeOperConst(GT_CNS_INT);
10967 tree->gtType = TYP_BYREF;
10968 tree->gtIntCon.gtIconVal = 0;
10969 tree->gtIntCon.gtFieldSeq = FieldSeqStore::NotAField();
10970 if (vnStore != nullptr)
10972 fgValueNumberTreeConst(tree);
10977 printf("\nFolded to null byref:\n");
10990 /*-------------------------------------------------------------------------
10991 * Fold constant INT binary operator
10996 if (tree->OperIsCompare() && (tree->gtType == TYP_BYTE))
10997 tree->gtType = TYP_INT;
10999 assert (tree->gtType == TYP_INT ||
11000 varTypeIsGC(tree->TypeGet()) ||
11001 tree->gtOper == GT_MKREFANY);
11003 // No GC pointer types should be folded here...
11005 assert(!varTypeIsGC(op1->gtType) && !varTypeIsGC(op2->gtType));
11007 assert(op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()));
11008 assert(op2->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()));
11010 i1 = op1->gtIntConCommon.IconValue();
11011 i2 = op2->gtIntConCommon.IconValue();
11013 switch (tree->gtOper)
11015 case GT_EQ : i1 = (INT32(i1) == INT32(i2)); break;
11016 case GT_NE : i1 = (INT32(i1) != INT32(i2)); break;
11019 if (tree->gtFlags & GTF_UNSIGNED)
11020 i1 = (UINT32(i1) < UINT32(i2));
11022 i1 = (INT32(i1) < INT32(i2));
11026 if (tree->gtFlags & GTF_UNSIGNED)
11027 i1 = (UINT32(i1) <= UINT32(i2));
11029 i1 = (INT32(i1) <= INT32(i2));
11033 if (tree->gtFlags & GTF_UNSIGNED)
11034 i1 = (UINT32(i1) >= UINT32(i2));
11036 i1 = (INT32(i1) >= INT32(i2));
11040 if (tree->gtFlags & GTF_UNSIGNED)
11041 i1 = (UINT32(i1) > UINT32(i2));
11043 i1 = (INT32(i1) > INT32(i2));
11048 if (tree->gtOverflow())
11050 if (tree->gtFlags & GTF_UNSIGNED)
11052 if (INT64(UINT32(itemp)) != INT64(UINT32(i1)) + INT64(UINT32(i2)))
11057 if (INT64(INT32(itemp)) != INT64(INT32(i1))+INT64(INT32(i2)))
11062 fieldSeq = GetFieldSeqStore()->Append(op1->gtIntCon.gtFieldSeq,
11063 op2->gtIntCon.gtFieldSeq);
11067 if (tree->gtOverflow())
11069 if (tree->gtFlags & GTF_UNSIGNED)
11071 if (INT64(UINT32(itemp)) != ((INT64)((UINT32)i1) - (INT64)((UINT32)i2)))
11076 if (INT64(INT32(itemp)) != INT64(INT32(i1)) - INT64(INT32(i2)))
11083 if (tree->gtOverflow())
11085 if (tree->gtFlags & GTF_UNSIGNED)
11087 if (INT64(UINT32(itemp)) != ((INT64)((UINT32)i1) * (INT64)((UINT32)i2)))
11092 if (INT64(INT32(itemp)) != INT64(INT32(i1)) * INT64(INT32(i2)))
11096 // For the very particular case of the "constant array index" pseudo-field, we
11097 // assume that multiplication is by the field width, and preserves that field.
11098 // This could obviously be made more robust by a more complicated set of annotations...
11099 if ((op1->gtIntCon.gtFieldSeq != nullptr) &&
11100 op1->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
11102 assert(op2->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField());
11103 fieldSeq = op1->gtIntCon.gtFieldSeq;
11105 else if ((op2->gtIntCon.gtFieldSeq != nullptr) &&
11106 op2->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
11108 assert(op1->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField());
11109 fieldSeq = op2->gtIntCon.gtFieldSeq;
11114 case GT_OR : i1 |= i2; break;
11115 case GT_XOR: i1 ^= i2; break;
11116 case GT_AND: i1 &= i2; break;
11118 case GT_LSH: i1 <<= (i2 & 0x1f); break;
11119 case GT_RSH: i1 >>= (i2 & 0x1f); break;
11121 /* logical shift -> make it unsigned to not propagate the sign bit */
11122 i1 = UINT32(i1) >> (i2 & 0x1f);
11124 case GT_ROL: i1 = (i1 << (i2 & 0x1f)) | (UINT32(i1) >> ((32 - i2) & 0x1f));
11126 case GT_ROR: i1 = (i1 << ((32 - i2) & 0x1f)) | (UINT32(i1) >> (i2 & 0x1f));
11129 /* DIV and MOD can generate an INT 0 - if division by 0
11130 * or overflow - when dividing MIN by -1 */
11136 if (INT32(i2) == 0)
11138 // Division by zero:
11139 // We have to evaluate this expression and throw an exception
11142 else if ((INT32(i2) == -1) &&
11143 (UINT32(i1) == 0x80000000))
11145 // Overflow Division:
11146 // We have to evaluate this expression and throw an exception
11150 if (tree->gtOper == GT_DIV)
11152 i1 = INT32(i1) / INT32(i2);
11154 else if (tree->gtOper == GT_MOD)
11156 i1 = INT32(i1) % INT32(i2);
11158 else if (tree->gtOper == GT_UDIV)
11160 i1 = UINT32(i1) / UINT32(i2);
11164 assert(tree->gtOper == GT_UMOD);
11165 i1 = UINT32(i1) % UINT32(i2);
11173 /* We get here after folding to a GT_CNS_INT type
11174 * change the node to the new type / value and make sure the node sizes are OK */
11181 printf("\nFolding operator with constant nodes into a constant:\n");
11186 #ifdef _TARGET_64BIT_
11187 // we need to properly re-sign-extend or truncate as needed.
11188 if (tree->gtFlags & GTF_UNSIGNED)
11192 #endif // _TARGET_64BIT_
11194 /* Also all conditional folding jumps here since the node hanging from
11195 * GT_JTRUE has to be a GT_CNS_INT - value 0 or 1 */
11197 tree->ChangeOperConst(GT_CNS_INT);
11198 tree->gtType = TYP_INT;
11199 tree->gtIntCon.gtIconVal = i1;
11200 tree->gtIntCon.gtFieldSeq = fieldSeq;
11201 if (vnStore != nullptr)
11203 fgValueNumberTreeConst(tree);
11208 printf("Bashed to int constant:\n");
11214 /* This operation is going to cause an overflow exception. Morph into
11215 an overflow helper. Put a dummy constant value for code generation.
11217 We could remove all subsequent trees in the current basic block,
11218 unless this node is a child of GT_COLON
11220 NOTE: Since the folded value is not constant we should not change the
11221 "tree" node - otherwise we confuse the logic that checks if the folding
11222 was successful - instead use one of the operands, e.g. op1
11226 // Don't fold overflow operations if not global morph phase.
11227 // The reason for this is that this optimization is replacing a gentree node
11228 // with another new gentree node. Say a GT_CALL(arglist) has one 'arg'
11229 // involving overflow arithmetic. During assertion prop, it is possible
11230 // that the 'arg' could be constant folded and the result could lead to an
11231 // overflow. In such a case 'arg' will get replaced with GT_COMMA node
11232 // but fgMorphArgs() - see the logic around "if(lateArgsComputed)" - doesn't
11233 // update args table. For this reason this optimization is enabled only
11234 // for global morphing phase.
11236 // X86/Arm32 legacy codegen note: This is not an issue on x86 for the reason that
11237 // it doesn't use arg table for calls. In addition x86/arm32 legacy codegen doesn't
11238 // expect long constants to show up as an operand of overflow cast operation.
11240 // TODO-CQ: Once fgMorphArgs() is fixed this restriction could be removed.
11241 #ifndef LEGACY_BACKEND
11242 if (!fgGlobalMorph)
11244 assert(tree->gtOverflow());
11247 #endif // !LEGACY_BACKEND
11249 op1 = gtNewLconNode(0);
11250 if (vnStore != nullptr)
11252 op1->gtVNPair.SetBoth(vnStore->VNZeroForType(TYP_LONG));
11257 // Don't fold overflow operations if not global morph phase.
11258 // The reason for this is that this optimization is replacing a gentree node
11259 // with another new gentree node. Say a GT_CALL(arglist) has one 'arg'
11260 // involving overflow arithmetic. During assertion prop, it is possible
11261 // that the 'arg' could be constant folded and the result could lead to an
11262 // overflow. In such a case 'arg' will get replaced with GT_COMMA node
11263 // but fgMorphArgs() - see the logic around "if(lateArgsComputed)" - doesn't
11264 // update args table. For this reason this optimization is enabled only
11265 // for global morphing phase.
11267 // X86/Arm32 legacy codegen note: This is not an issue on x86 for the reason that
11268 // it doesn't use arg table for calls. In addition x86/arm32 legacy codegen doesn't
11269 // expect long constants to show up as an operand of overflow cast operation.
11271 // TODO-CQ: Once fgMorphArgs() is fixed this restriction could be removed.
11272 #ifndef LEGACY_BACKEND
11273 if (!fgGlobalMorph)
11275 assert(tree->gtOverflow());
11278 #endif // !LEGACY_BACKEND
11280 op1 = gtNewIconNode(0);
11281 if (vnStore != nullptr)
11283 op1->gtVNPair.SetBoth(vnStore->VNZeroForType(TYP_INT));
11291 printf("\nFolding binary operator with constant nodes into a comma throw:\n");
11295 /* We will change the cast to a GT_COMMA and attach the exception helper as gtOp.gtOp1.
11296 * The constant expression zero becomes op2. */
11298 assert(tree->gtOverflow());
11299 assert(tree->gtOper == GT_ADD || tree->gtOper == GT_SUB ||
11300 tree->gtOper == GT_CAST || tree->gtOper == GT_MUL);
11304 op1 = gtNewHelperCallNode(CORINFO_HELP_OVERFLOW,
11307 gtNewArgList(gtNewIconNode(compCurBB->bbTryIndex)));
11309 if (vnStore != nullptr)
11311 op1->gtVNPair = vnStore->VNPWithExc(ValueNumPair(ValueNumStore::VNForVoid(), ValueNumStore::VNForVoid()), vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_OverflowExc)));
11314 tree = gtNewOperNode(GT_COMMA, tree->gtType, op1, op2);
11318 /*-------------------------------------------------------------------------
11319 * Fold constant LONG binary operator
11324 // No GC pointer types should be folded here...
11326 assert(!varTypeIsGC(op1->gtType) && !varTypeIsGC(op2->gtType));
11328 // op1 is known to be a TYP_LONG, op2 is normally a TYP_LONG, unless we have a shift operator in which case it is a TYP_INT
11330 assert((op2->gtType == TYP_LONG) || (op2->gtType == TYP_INT));
11332 assert(op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()));
11333 assert(op2->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()));
11335 lval1 = op1->gtIntConCommon.LngValue();
11337 // For the shift operators we can have a op2 that is a TYP_INT and thus will be GT_CNS_INT
11338 if (op2->OperGet() == GT_CNS_INT)
11339 lval2 = op2->gtIntConCommon.IconValue();
11341 lval2 = op2->gtIntConCommon.LngValue();
11343 switch (tree->gtOper)
11345 case GT_EQ : i1 = (lval1 == lval2); goto FOLD_COND;
11346 case GT_NE : i1 = (lval1 != lval2); goto FOLD_COND;
11349 if (tree->gtFlags & GTF_UNSIGNED)
11350 i1 = (UINT64(lval1) < UINT64(lval2));
11352 i1 = (lval1 < lval2);
11356 if (tree->gtFlags & GTF_UNSIGNED)
11357 i1 = (UINT64(lval1) <= UINT64(lval2));
11359 i1 = (lval1 <= lval2);
11363 if (tree->gtFlags & GTF_UNSIGNED)
11364 i1 = (UINT64(lval1) >= UINT64(lval2));
11366 i1 = (lval1 >= lval2);
11370 if (tree->gtFlags & GTF_UNSIGNED)
11371 i1 = (UINT64(lval1) > UINT64(lval2));
11373 i1 = (lval1 > lval2);
11377 ltemp = lval1 + lval2;
11380 /* For the SIGNED case - If there is one positive and one negative operand, there can be no overflow
11381 * If both are positive, the result has to be positive, and similary for negatives.
11383 * For the UNSIGNED case - If a UINT32 operand is bigger than the result then OVF */
11385 if (tree->gtOverflow())
11387 if (tree->gtFlags & GTF_UNSIGNED)
11389 if ( (UINT64(lval1) > UINT64(ltemp)) ||
11390 (UINT64(lval2) > UINT64(ltemp)) )
11394 if ( ((lval1<0) == (lval2<0)) && ((lval1<0) != (ltemp<0)) )
11397 lval1 = ltemp; break;
11400 ltemp = lval1 - lval2;
11401 if (tree->gtOverflow())
11403 if (tree->gtFlags & GTF_UNSIGNED)
11405 if (UINT64(lval2) > UINT64(lval1))
11410 /* If both operands are +ve or both are -ve, there can be no
11411 overflow. Else use the logic for : lval1 + (-lval2) */
11413 if ((lval1<0) != (lval2<0))
11415 if (lval2 == INT64_MIN) goto LNG_OVF;
11416 lval2 = -lval2; goto LNG_ADD_CHKOVF;
11420 lval1 = ltemp; break;
11423 ltemp = lval1 * lval2;
11425 if (tree->gtOverflow() && lval2 != 0)
11428 if (tree->gtFlags & GTF_UNSIGNED)
11430 UINT64 ultemp = ltemp;
11431 UINT64 ulval1 = lval1;
11432 UINT64 ulval2 = lval2;
11433 if ((ultemp/ulval2) != ulval1) goto LNG_OVF;
11437 //This does a multiply and then reverses it. This test works great except for MIN_INT *
11438 //-1. In that case we mess up the sign on ltmp. Make sure to double check the sign.
11439 //if either is 0, then no overflow
11440 if (lval1 != 0) //lval2 checked above.
11442 if (((lval1<0) == (lval2<0)) && (ltemp<0))
11446 if (((lval1<0) != (lval2<0)) && (ltemp>0))
11451 // TODO-Amd64-Unix: Remove the code that disables optimizations for this method when the clang
11452 // optimizer is fixed and/or the method implementation is refactored in a simpler code.
11453 // There is a bug in the clang-3.5 optimizer. The issue is that in release build the optimizer is mistyping
11454 // (or just wrongly decides to use 32 bit operation for a corner case of MIN_LONG) the args of the (ltemp / lval2)
11455 // to int (it does a 32 bit div operation instead of 64 bit.)
11456 // For the case of lval1 and lval2 equal to MIN_LONG (0x8000000000000000) this results in raising a SIGFPE.
11457 // Optimizations disabled for now. See compiler.h.
11458 if ((ltemp/lval2) != lval1) goto LNG_OVF;
11463 lval1 = ltemp; break;
11465 case GT_OR : lval1 |= lval2; break;
11466 case GT_XOR: lval1 ^= lval2; break;
11467 case GT_AND: lval1 &= lval2; break;
11469 case GT_LSH: lval1 <<= (lval2 & 0x3f); break;
11470 case GT_RSH: lval1 >>= (lval2 & 0x3f); break;
11472 /* logical shift -> make it unsigned to not propagate the sign bit */
11473 lval1 = UINT64(lval1) >> (lval2 & 0x3f);
11475 case GT_ROL: lval1 = (lval1 << (lval2 & 0x3f)) | (UINT64(lval1) >> ((64 - lval2) & 0x3f));
11477 case GT_ROR: lval1 = (lval1 << ((64 - lval2) & 0x3f)) | (UINT64(lval1) >> (lval2 & 0x3f));
11480 //Both DIV and IDIV on x86 raise an exception for min_int (and min_long) / -1. So we preserve
11481 //that behavior here.
11483 if (!lval2) return tree;
11485 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
11489 lval1 /= lval2; break;
11492 if (!lval2) return tree;
11493 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
11497 lval1 %= lval2; break;
11500 if (!lval2) return tree;
11501 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1)) return tree;
11502 lval1 = UINT64(lval1) / UINT64(lval2); break;
11505 if (!lval2) return tree;
11506 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1)) return tree;
11507 lval1 = UINT64(lval1) % UINT64(lval2); break;
11517 printf("\nFolding long operator with constant nodes into a constant:\n");
11521 assert ((GenTree::s_gtNodeSizes[GT_CNS_NATIVELONG] == TREE_NODE_SZ_SMALL) ||
11522 (tree->gtDebugFlags & GTF_DEBUG_NODE_LARGE) );
11524 tree->ChangeOperConst(GT_CNS_NATIVELONG);
11525 tree->gtIntConCommon.SetLngValue(lval1);
11526 if (vnStore != nullptr)
11528 fgValueNumberTreeConst(tree);
11534 printf("Bashed to long constant:\n");
11540 /*-------------------------------------------------------------------------
11541 * Fold constant FLOAT or DOUBLE binary operator
11547 if (tree->gtOverflowEx())
11550 assert(op1->gtOper == GT_CNS_DBL);
11551 d1 = op1->gtDblCon.gtDconVal;
11553 assert(varTypeIsFloating(op2->gtType));
11554 assert(op2->gtOper == GT_CNS_DBL);
11555 d2 = op2->gtDblCon.gtDconVal;
11557 /* Special case - check if we have NaN operands.
11558 * For comparisons if not an unordered operation always return 0.
11559 * For unordered operations (i.e. the GTF_RELOP_NAN_UN flag is set)
11560 * the result is always true - return 1. */
11562 if (_isnan(d1) || _isnan(d2))
11566 printf("Double operator(s) is NaN\n");
11568 if (tree->OperKind() & GTK_RELOP)
11570 if (tree->gtFlags & GTF_RELOP_NAN_UN)
11572 /* Unordered comparison with NaN always succeeds */
11573 i1 = 1; goto FOLD_COND;
11577 /* Normal comparison with NaN always fails */
11578 i1 = 0; goto FOLD_COND;
11583 switch (tree->gtOper)
11585 case GT_EQ : i1 = (d1 == d2); goto FOLD_COND;
11586 case GT_NE : i1 = (d1 != d2); goto FOLD_COND;
11588 case GT_LT : i1 = (d1 < d2); goto FOLD_COND;
11589 case GT_LE : i1 = (d1 <= d2); goto FOLD_COND;
11590 case GT_GE : i1 = (d1 >= d2); goto FOLD_COND;
11591 case GT_GT : i1 = (d1 > d2); goto FOLD_COND;
11593 #if FEATURE_STACK_FP_X87
11594 case GT_ADD: d1 += d2; break;
11595 case GT_SUB: d1 -= d2; break;
11596 case GT_MUL: d1 *= d2; break;
11597 case GT_DIV: if (!d2) return tree;
11599 #else //!FEATURE_STACK_FP_X87
11600 // non-x86 arch: floating point arithmetic should be done in declared
11601 // precision while doing constant folding. For this reason though TYP_FLOAT
11602 // constants are stored as double constants, while performing float arithmetic,
11603 // double constants should be converted to float. Here is an example case
11604 // where performing arithmetic in double precision would lead to incorrect
11608 // float a = float.MaxValue;
11609 // float b = a*a; This will produce +inf in single precision and 1.1579207543382391e+077 in double precision.
11610 // flaot c = b/b; This will produce NaN in single precision and 1 in double precision.
11612 if (op1->TypeGet() == TYP_FLOAT)
11614 f1 = forceCastToFloat(d1);
11615 f2 = forceCastToFloat(d2);
11625 if (op1->TypeGet() == TYP_FLOAT)
11627 f1 = forceCastToFloat(d1);
11628 f2 = forceCastToFloat(d2);
11638 if (op1->TypeGet() == TYP_FLOAT)
11640 f1 = forceCastToFloat(d1);
11641 f2 = forceCastToFloat(d2);
11651 if (!d2) return tree;
11652 if (op1->TypeGet() == TYP_FLOAT)
11654 f1 = forceCastToFloat(d1);
11655 f2 = forceCastToFloat(d2);
11663 #endif //!FEATURE_STACK_FP_X87
11674 printf("\nFolding fp operator with constant nodes into a fp constant:\n");
11679 assert ((GenTree::s_gtNodeSizes[GT_CNS_DBL] == TREE_NODE_SZ_SMALL) ||
11680 (tree->gtDebugFlags & GTF_DEBUG_NODE_LARGE) );
11682 tree->ChangeOperConst(GT_CNS_DBL);
11683 tree->gtDblCon.gtDconVal = d1;
11684 if (vnStore != nullptr)
11686 fgValueNumberTreeConst(tree);
11691 printf("Bashed to fp constant:\n");
11698 /* not a foldable typ */
11702 //-------------------------------------------------------------------------
11706 /* Make sure no side effect flags are set on this constant node */
11708 tree->gtFlags &= ~GTF_ALL_EFFECT;
11713 #pragma warning(pop)
11716 /*****************************************************************************
11718 * Create an assignment of the given value to a temp.
11721 GenTreePtr Compiler::gtNewTempAssign(unsigned tmp, GenTreePtr val)
11723 LclVarDsc * varDsc = lvaTable + tmp;
11725 if (varDsc->TypeGet() == TYP_I_IMPL && val->TypeGet() == TYP_BYREF)
11726 impBashVarAddrsToI(val);
11728 var_types valTyp = val->TypeGet();
11729 if (val->OperGet() == GT_LCL_VAR
11730 && lvaTable[val->gtLclVar.gtLclNum].lvNormalizeOnLoad())
11732 valTyp = lvaGetRealType(val->gtLclVar.gtLclNum);
11733 val = gtNewLclvNode(val->gtLclVar.gtLclNum, valTyp, val->gtLclVar.gtLclILoffs);
11735 var_types dstTyp = varDsc->TypeGet();
11737 /* If the variable's lvType is not yet set then set it here */
11738 if (dstTyp == TYP_UNDEF)
11740 varDsc->lvType = dstTyp = genActualType(valTyp);
11741 if (varTypeIsGC(dstTyp))
11743 varDsc->lvStructGcCount = 1;
11746 else if (varTypeIsSIMD(dstTyp))
11748 varDsc->lvSIMDType = 1;
11754 /* Make sure the actual types match */
11755 if (genActualType(valTyp) != genActualType(dstTyp))
11757 // Plus some other exceptions that are apparently legal:
11758 // 1) TYP_REF or BYREF = TYP_I_IMPL
11760 if (varTypeIsGC(dstTyp) && (valTyp == TYP_I_IMPL))
11764 // 2) TYP_DOUBLE = TYP_FLOAT or TYP_FLOAT = TYP_DOUBLE
11765 else if (varTypeIsFloating(dstTyp) && varTypeIsFloating(valTyp))
11773 assert(!"Incompatible types for gtNewTempAssign");
11778 // Floating Point assignments can be created during inlining
11779 // see "Zero init inlinee locals:" in fgInlinePrependStatements
11780 // thus we may need to set compFloatingPointUsed to true here.
11782 if (varTypeIsFloating(dstTyp) && (compFloatingPointUsed == false))
11784 compFloatingPointUsed = true;
11787 /* Create the assignment node */
11790 GenTreePtr dest = gtNewLclvNode(tmp, dstTyp);
11791 dest->gtFlags |= GTF_VAR_DEF;
11793 // With first-class structs, we should be propagating the class handle on all non-primitive
11794 // struct types. We don't have a convenient way to do that for all SIMD temps, since some
11795 // internal trees use SIMD types that are not used by the input IL. In this case, we allow
11796 // a null type handle and derive the necessary information about the type from its varType.
11797 CORINFO_CLASS_HANDLE structHnd = gtGetStructHandleIfPresent(val);
11798 if (varTypeIsStruct(valTyp) && ((structHnd != NO_CLASS_HANDLE) || (varTypeIsSIMD(valTyp))))
11800 // The GT_OBJ may be be a child of a GT_COMMA.
11801 GenTreePtr valx = val->gtEffectiveVal(/*commaOnly*/true);
11803 if (valx->gtOper == GT_OBJ)
11805 assert(structHnd != nullptr);
11806 lvaSetStruct(tmp, structHnd, false);
11808 dest->gtFlags |= GTF_DONT_CSE;
11809 valx->gtFlags |= GTF_DONT_CSE;
11810 asg = impAssignStruct(dest,
11813 (unsigned)CHECK_SPILL_NONE);
11817 asg = gtNewAssignNode(dest, val);
11820 #ifndef LEGACY_BACKEND
11821 if (fgOrder == FGOrderLinear)
11823 Rationalizer::MorphAsgIntoStoreLcl(nullptr, asg);
11825 #endif // !LEGACY_BACKEND
11830 /*****************************************************************************
11832 * Create a helper call to access a COM field (iff 'assg' is non-zero this is
11833 * an assignment and 'assg' is the new value).
11836 GenTreePtr Compiler::gtNewRefCOMfield(GenTreePtr objPtr,
11837 CORINFO_RESOLVED_TOKEN * pResolvedToken,
11838 CORINFO_ACCESS_FLAGS access,
11839 CORINFO_FIELD_INFO * pFieldInfo,
11841 CORINFO_CLASS_HANDLE structType,
11844 assert(pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER ||
11845 pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_ADDR_HELPER ||
11846 pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_ADDR_HELPER);
11848 /* If we can't access it directly, we need to call a helper function */
11849 GenTreeArgList* args = NULL;
11850 var_types helperType = TYP_BYREF;
11852 if (pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER)
11854 if (access & CORINFO_ACCESS_SET)
11857 // helper needs pointer to struct, not struct itself
11858 if (pFieldInfo->helper == CORINFO_HELP_SETFIELDSTRUCT)
11860 assert(structType != 0);
11861 assg = impGetStructAddr(assg, structType, (unsigned)CHECK_SPILL_ALL, true);
11863 else if (lclTyp == TYP_DOUBLE && assg->TypeGet() == TYP_FLOAT)
11864 assg = gtNewCastNode(TYP_DOUBLE, assg, TYP_DOUBLE);
11865 else if (lclTyp == TYP_FLOAT && assg->TypeGet() == TYP_DOUBLE)
11866 assg = gtNewCastNode(TYP_FLOAT, assg, TYP_FLOAT);
11868 args = gtNewArgList(assg);
11869 helperType = TYP_VOID;
11871 else if (access & CORINFO_ACCESS_GET)
11873 helperType = lclTyp;
11875 // The calling convention for the helper does not take into
11876 // account optimization of primitive structs.
11877 if ((pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT) && !varTypeIsStruct(lclTyp))
11879 helperType = TYP_STRUCT;
11884 if (pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT || pFieldInfo->helper == CORINFO_HELP_SETFIELDSTRUCT)
11886 assert(pFieldInfo->structType != NULL);
11887 args = gtNewListNode(gtNewIconEmbClsHndNode(pFieldInfo->structType), args);
11890 GenTreePtr fieldHnd = impTokenToHandle(pResolvedToken);
11891 if (fieldHnd == NULL) // compDonotInline()
11894 args = gtNewListNode(fieldHnd, args);
11896 // If it's a static field, we shouldn't have an object node
11897 // If it's an instance field, we have an object node
11898 assert( (pFieldInfo->fieldAccessor != CORINFO_FIELD_STATIC_ADDR_HELPER) ^ (objPtr == 0) );
11900 if (objPtr != NULL)
11901 args = gtNewListNode(objPtr, args);
11903 GenTreePtr tree = gtNewHelperCallNode(pFieldInfo->helper, genActualType(helperType), 0, args);
11905 if (pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER)
11907 if (access & CORINFO_ACCESS_GET)
11909 if (pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT)
11911 if (!varTypeIsStruct(lclTyp))
11913 // get the result as primitive type
11914 tree = impGetStructAddr(tree, structType, (unsigned)CHECK_SPILL_ALL, true);
11915 tree = gtNewOperNode(GT_IND, lclTyp, tree);
11918 else if (varTypeIsIntegral(lclTyp) && genTypeSize(lclTyp) < genTypeSize(TYP_INT))
11920 // The helper does not extend the small return types.
11921 tree = gtNewCastNode(genActualType(lclTyp), tree, lclTyp);
11927 // OK, now do the indirection
11928 if (access & CORINFO_ACCESS_GET)
11930 if (varTypeIsStruct(lclTyp))
11932 tree = gtNewObjNode(structType, tree);
11936 tree = gtNewOperNode(GT_IND, lclTyp, tree);
11938 tree->gtFlags |= (GTF_EXCEPT | GTF_GLOB_REF);
11940 else if (access & CORINFO_ACCESS_SET)
11942 if (varTypeIsStruct(lclTyp))
11943 tree = impAssignStructPtr(tree, assg, structType, (unsigned)CHECK_SPILL_ALL);
11946 tree = gtNewOperNode(GT_IND, lclTyp, tree);
11947 tree->gtFlags |= (GTF_EXCEPT | GTF_GLOB_REF | GTF_IND_TGTANYWHERE);
11948 tree = gtNewAssignNode(tree, assg);
11956 /*****************************************************************************
11958 * Return true if the given node (excluding children trees) contains side effects.
11959 * Note that it does not recurse, and children need to be handled separately.
11960 * It may return false even if the node has GTF_SIDE_EFFECT (because of its children).
11962 * Similar to OperMayThrow() (but handles GT_CALLs specially), but considers
11966 bool Compiler::gtNodeHasSideEffects(GenTreePtr tree, unsigned flags)
11968 if (flags & GTF_ASG)
11970 if ((tree->OperKind() & GTK_ASGOP) ||
11971 (tree->gtOper == GT_INITBLK ||
11972 tree->gtOper == GT_COPYBLK ||
11973 tree->gtOper == GT_COPYOBJ))
11979 // Are there only GTF_CALL side effects remaining? (and no other side effect kinds)
11980 if (flags & GTF_CALL)
11982 if (tree->OperGet() == GT_CALL)
11984 // Generally all GT_CALL nodes are considered to have side-effects.
11985 // But we may have a helper call that doesn't have any important side effects.
11987 if (tree->gtCall.gtCallType == CT_HELPER)
11989 // But if this tree is a helper call we may not care about the side-effects
11991 CorInfoHelpFunc helper = eeGetHelperNum(tree->AsCall()->gtCallMethHnd);
11993 // We definitely care about the side effects if MutatesHeap is true
11995 if (s_helperCallProperties.MutatesHeap(helper))
11998 // with GTF_PERSISTENT_SIDE_EFFECTS_IN_CSE we will CSE helper calls that can run cctors.
12000 if ((flags != GTF_PERSISTENT_SIDE_EFFECTS_IN_CSE) && (s_helperCallProperties.MayRunCctor(helper)))
12003 // If we also care about exceptions then check if the helper can throw
12005 if (((flags & GTF_EXCEPT) != 0) && !s_helperCallProperties.NoThrow(helper))
12008 // If this is a Pure helper call or an allocator (that will not need to run a finalizer)
12009 // then we don't need to preserve the side effects (of this call -- we may care about those of the arguments).
12010 if ( s_helperCallProperties.IsPure(helper)
12011 || (s_helperCallProperties.IsAllocator(helper) && !s_helperCallProperties.MayFinalize(helper)))
12013 GenTreeCall* call = tree->AsCall();
12014 for (GenTreeArgList* args = call->gtCallArgs; args != nullptr; args = args->Rest())
12016 if (gtTreeHasSideEffects(args->Current(), flags)) return true;
12018 // I'm a little worried that args that assign to temps that are late args will look like
12019 // side effects...but better to be conservative for now.
12020 for (GenTreeArgList* args = call->gtCallLateArgs; args != nullptr; args = args->Rest())
12022 if (gtTreeHasSideEffects(args->Current(), flags)) return true;
12029 // Otherwise the GT_CALL is considered to have side-effects.
12034 if (flags & GTF_EXCEPT)
12036 if (tree->OperMayThrow())
12040 // Expressions declared as CSE by (e.g.) hoisting code are considered to have relevant side
12041 // effects (if we care about GTF_MAKE_CSE).
12042 if ((flags & GTF_MAKE_CSE) && (tree->gtFlags & GTF_MAKE_CSE))
12048 /*****************************************************************************
12049 * Returns true if the expr tree has any side effects.
12052 bool Compiler::gtTreeHasSideEffects(GenTreePtr tree,
12053 unsigned flags /* = GTF_SIDE_EFFECT*/)
12055 // These are the side effect flags that we care about for this tree
12056 unsigned sideEffectFlags = tree->gtFlags & flags;
12058 // Does this tree have any Side-effect flags set that we care about?
12059 if (sideEffectFlags == 0)
12065 if (sideEffectFlags == GTF_CALL)
12067 if (tree->OperGet() == GT_CALL)
12069 // Generally all trees that contain GT_CALL nodes are considered to have side-effects.
12071 if (tree->gtCall.gtCallType == CT_HELPER)
12073 // If this node is a helper call we may not care about the side-effects.
12074 // Note that gtNodeHasSideEffects checks the side effects of the helper itself
12075 // as well as the side effects of its arguments.
12076 return gtNodeHasSideEffects(tree, flags);
12079 else if (tree->OperGet() == GT_INTRINSIC)
12081 if (gtNodeHasSideEffects(tree, flags))
12084 if (gtNodeHasSideEffects(tree->gtOp.gtOp1, flags))
12087 if ((tree->gtOp.gtOp2 != nullptr) && gtNodeHasSideEffects(tree->gtOp.gtOp2, flags))
12097 GenTreePtr Compiler::gtBuildCommaList(GenTreePtr list, GenTreePtr expr)
12099 // 'list' starts off as null,
12100 // and when it is null we haven't started the list yet.
12102 if (list != nullptr)
12104 // Create a GT_COMMA that appends 'expr' in front of the remaining set of expressions in (*list)
12105 GenTreePtr result = gtNewOperNode(GT_COMMA, TYP_VOID, expr, list);
12107 // Set the flags in the comma node
12108 result->gtFlags |= (list->gtFlags & GTF_ALL_EFFECT);
12109 result->gtFlags |= (expr->gtFlags & GTF_ALL_EFFECT);
12111 // 'list' and 'expr' should have valuenumbers defined for both or for neither one
12112 noway_assert(list->gtVNPair.BothDefined() == expr->gtVNPair.BothDefined());
12114 // Set the ValueNumber 'gtVNPair' for the new GT_COMMA node
12116 if (expr->gtVNPair.BothDefined())
12118 // The result of a GT_COMMA node is op2, the normal value number is op2vnp
12119 // But we also need to include the union of side effects from op1 and op2.
12120 // we compute this value into exceptions_vnp.
12121 ValueNumPair op1vnp;
12122 ValueNumPair op1Xvnp = ValueNumStore::VNPForEmptyExcSet();
12123 ValueNumPair op2vnp;
12124 ValueNumPair op2Xvnp = ValueNumStore::VNPForEmptyExcSet();
12126 vnStore->VNPUnpackExc(expr->gtVNPair, &op1vnp, &op1Xvnp);
12127 vnStore->VNPUnpackExc(list->gtVNPair, &op2vnp, &op2Xvnp);
12129 ValueNumPair exceptions_vnp = ValueNumStore::VNPForEmptyExcSet();
12131 exceptions_vnp = vnStore->VNPExcSetUnion(exceptions_vnp, op1Xvnp);
12132 exceptions_vnp = vnStore->VNPExcSetUnion(exceptions_vnp, op2Xvnp);
12134 result->gtVNPair = vnStore->VNPWithExc(op2vnp, exceptions_vnp);
12141 // The 'expr' will start the list of expressions
12147 /*****************************************************************************
12149 * Extracts side effects from the given expression
12150 * and appends them to a given list (actually a GT_COMMA list)
12151 * If ignore root is specified, the method doesn't treat the top
12152 * level tree node as having side-effect.
12155 void Compiler::gtExtractSideEffList(GenTreePtr expr, GenTreePtr * pList,
12156 unsigned flags /* = GTF_SIDE_EFFECT*/,
12157 bool ignoreRoot /* = false */)
12159 assert(expr); assert(expr->gtOper != GT_STMT);
12161 /* If no side effect in the expression return */
12163 if (!gtTreeHasSideEffects(expr, flags))
12166 genTreeOps oper = expr->OperGet();
12167 unsigned kind = expr->OperKind();
12169 // Look for any side effects that we care about
12171 if (!ignoreRoot && gtNodeHasSideEffects(expr, flags))
12173 // Add the side effect to the list and return
12175 *pList = gtBuildCommaList(*pList, expr);
12179 if (kind & GTK_LEAF)
12182 if (oper == GT_LOCKADD || oper == GT_XADD || oper == GT_XCHG || oper == GT_CMPXCHG)
12184 //XADD both adds to the memory location and also fetches the old value. If we only need the side
12185 //effect of this instruction, change it into a GT_LOCKADD node (the add only)
12186 if (oper == GT_XADD)
12188 expr->gtOper = GT_LOCKADD;
12189 expr->gtType = TYP_VOID;
12192 // These operations are kind of important to keep
12193 *pList = gtBuildCommaList(*pList, expr);
12197 if (kind & GTK_SMPOP)
12199 GenTreePtr op1 = expr->gtOp.gtOp1;
12200 GenTreePtr op2 = expr->gtGetOp2();
12202 if (flags & GTF_EXCEPT)
12204 // Special case - GT_ADDR of GT_IND nodes of TYP_STRUCT
12205 // have to be kept together
12207 if (oper == GT_ADDR && op1->OperIsIndir() && op1->gtType == TYP_STRUCT)
12209 *pList = gtBuildCommaList(*pList, expr);
12213 printf("Keep the GT_ADDR and GT_IND together:\n");
12219 /* Continue searching for side effects in the subtrees of the expression
12220 * NOTE: Be careful to preserve the right ordering - side effects are prepended
12223 /* Continue searching for side effects in the subtrees of the expression
12224 * NOTE: Be careful to preserve the right ordering
12225 * as side effects are prepended to the list */
12227 if (expr->gtFlags & GTF_REVERSE_OPS)
12229 assert(oper != GT_COMMA);
12230 if (op1) gtExtractSideEffList(op1, pList, flags);
12231 if (op2) gtExtractSideEffList(op2, pList, flags);
12235 if (op2) gtExtractSideEffList(op2, pList, flags);
12236 if (op1) gtExtractSideEffList(op1, pList, flags);
12240 if (expr->OperGet() == GT_CALL)
12242 // Generally all GT_CALL nodes are considered to have side-effects.
12243 // So if we get here it must be a Helper call that we decided does
12244 // not have side effects that we needed to keep
12246 assert(expr->gtCall.gtCallType == CT_HELPER);
12248 // We can remove this Helper call, but there still could be
12249 // side-effects in the arguments that we may need to keep
12252 for (args = expr->gtCall.gtCallArgs; args; args = args->gtOp.gtOp2)
12254 assert(args->IsList());
12255 gtExtractSideEffList(args->Current(), pList, flags);
12257 for (args = expr->gtCall.gtCallLateArgs; args; args = args->gtOp.gtOp2)
12259 assert(args->IsList());
12260 gtExtractSideEffList(args->Current(), pList, flags);
12264 if (expr->OperGet() == GT_ARR_BOUNDS_CHECK
12265 #ifdef FEATURE_SIMD
12266 || expr->OperGet() == GT_SIMD_CHK
12267 #endif // FEATURE_SIMD
12270 gtExtractSideEffList(expr->AsBoundsChk()->gtArrLen, pList, flags);
12271 gtExtractSideEffList(expr->AsBoundsChk()->gtIndex, pList, flags);
12276 /*****************************************************************************
12278 * For debugging only - displays a tree node list and makes sure all the
12279 * links are correctly set.
12284 void dispNodeList(GenTreePtr list, bool verbose)
12286 GenTreePtr last = 0;
12294 next = list->gtNext;
12297 printf("%08X -> %08X -> %08X\n", last, list, next);
12299 assert(!last || last->gtNext == list);
12301 assert(next == 0 || next->gtPrev == list);
12309 printf(""); // null string means flush
12312 /*****************************************************************************
12313 * Callback to assert that the nodes of a qmark-colon subtree are marked
12317 Compiler::fgWalkResult Compiler::gtAssertColonCond(GenTreePtr *pTree,
12320 assert(data->pCallbackData == NULL);
12322 assert((*pTree)->gtFlags & GTF_COLON_COND);
12324 return WALK_CONTINUE;
12328 /*****************************************************************************
12329 * Callback to mark the nodes of a qmark-colon subtree that are conditionally
12334 Compiler::fgWalkResult Compiler::gtMarkColonCond(GenTreePtr *pTree,
12337 assert(data->pCallbackData == NULL);
12339 (*pTree)->gtFlags |= GTF_COLON_COND;
12341 return WALK_CONTINUE;
12344 /*****************************************************************************
12345 * Callback to clear the conditionally executed flags of nodes that no longer
12346 will be conditionally executed. Note that when we find another colon we must
12347 stop, as the nodes below this one WILL be conditionally executed. This callback
12348 is called when folding a qmark condition (ie the condition is constant).
12352 Compiler::fgWalkResult Compiler::gtClearColonCond(GenTreePtr *pTree,
12355 GenTreePtr tree = *pTree;
12357 assert(data->pCallbackData == NULL);
12359 if (tree->OperGet()==GT_COLON)
12361 // Nodes below this will be conditionally executed.
12362 return WALK_SKIP_SUBTREES;
12365 tree->gtFlags &= ~GTF_COLON_COND;
12366 return WALK_CONTINUE;
12370 struct FindLinkData {
12371 GenTreePtr nodeToFind;
12372 GenTreePtr * result;
12375 /*****************************************************************************
12377 * Callback used by the tree walker to implement fgFindLink()
12379 static Compiler::fgWalkResult gtFindLinkCB(GenTreePtr * pTree,
12380 Compiler::fgWalkData * cbData)
12382 FindLinkData * data = (FindLinkData*) cbData->pCallbackData;
12383 if (*pTree == data->nodeToFind)
12385 data->result = pTree;
12386 return Compiler::WALK_ABORT;
12389 return Compiler::WALK_CONTINUE;
12392 GenTreePtr * Compiler::gtFindLink(GenTreePtr stmt, GenTreePtr node)
12394 assert(stmt->gtOper == GT_STMT);
12396 FindLinkData data = {node, NULL};
12398 fgWalkResult result = fgWalkTreePre(&stmt->gtStmt.gtStmtExpr, gtFindLinkCB, &data);
12400 if (result == WALK_ABORT)
12402 assert(data.nodeToFind == *data.result);
12403 return data.result;
12409 /*****************************************************************************
12411 * Callback that checks if a tree node has oper type GT_CATCH_ARG
12414 static Compiler::fgWalkResult gtFindCatchArg(GenTreePtr * pTree,
12415 Compiler::fgWalkData * /* data */)
12417 return ((*pTree)->OperGet() == GT_CATCH_ARG) ? Compiler::WALK_ABORT
12418 : Compiler::WALK_CONTINUE;
12421 /*****************************************************************************/
12422 bool Compiler::gtHasCatchArg(GenTreePtr tree)
12424 if (((tree->gtFlags & GTF_ORDER_SIDEEFF) != 0) &&
12425 (fgWalkTreePre(&tree, gtFindCatchArg) == WALK_ABORT))
12433 //------------------------------------------------------------------------
12434 // gtHasCallOnStack:
12437 // parentStack: a context (stack of parent nodes)
12440 // returns true if any of the parent nodes are a GT_CALL
12443 // We have a stack of parent nodes. This generally requires that
12444 // we are performing a recursive tree walk using struct fgWalkData
12446 //------------------------------------------------------------------------
12447 /* static */ bool Compiler::gtHasCallOnStack(GenTreeStack *parentStack)
12450 i < parentStack->Height();
12453 GenTree *node = parentStack->Index(i);
12454 if (node->OperGet() == GT_CALL)
12462 //------------------------------------------------------------------------
12463 // gtCheckQuirkAddrExposedLclVar:
12466 // tree: an address taken GenTree node that is a GT_LCL_VAR
12467 // parentStack: a context (stack of parent nodes)
12468 // The 'parentStack' is used to ensure that we are in an argument context.
12474 // When allocation size of this LclVar is 32-bits we will quirk the size to 64-bits
12475 // because some PInvoke signatures incorrectly specify a ByRef to an INT32
12476 // when they actually write a SIZE_T or INT64. There are cases where overwriting
12477 // these extra 4 bytes corrupts some data (such as a saved register) that leads to A/V
12478 // Wheras previously the JIT64 codegen did not lead to an A/V
12481 // 'tree' is known to be address taken and that we have a stack
12482 // of parent nodes. Both of these generally requires that
12483 // we are performing a recursive tree walk using struct fgWalkData
12484 //------------------------------------------------------------------------
12485 void Compiler::gtCheckQuirkAddrExposedLclVar(GenTreePtr tree, GenTreeStack* parentStack)
12487 // We only need to Quirk for _TARGET_64BIT_
12488 #ifdef _TARGET_64BIT_
12490 // Do we have a parent node that is a Call?
12491 if (!Compiler::gtHasCallOnStack(parentStack))
12493 // No, so we don't apply the Quirk
12496 noway_assert(tree->gtOper == GT_LCL_VAR);
12497 unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
12498 LclVarDsc * varDsc = &lvaTable[lclNum];
12499 var_types vartype = varDsc->TypeGet();
12501 if (varDsc->lvIsParam)
12503 // We can't Quirk the size of an incoming parameter
12507 // We may need to Quirk the storage size for this LCL_VAR
12508 if (genActualType(vartype) == TYP_INT)
12510 varDsc->lvQuirkToLong = true;
12514 printf("\nAdding a Quirk for the storage size of LvlVar V%02d:", lclNum);
12515 printf(" (%s ==> %s)\n", varTypeName(vartype), varTypeName(TYP_LONG));
12522 //Checks to see if we're allowed to optimize Type::op_Equality or Type::op_Inequality on this operand.
12523 //We're allowed to convert to GT_EQ/GT_NE if one of the operands is:
12524 // 1) The result of Object::GetType
12525 // 2) The result of typeof(...)
12526 // 3) a local variable of type RuntimeType.
12527 bool Compiler::gtCanOptimizeTypeEquality(GenTreePtr tree)
12529 if (tree->gtOper == GT_CALL)
12531 if (tree->gtCall.gtCallType == CT_HELPER)
12533 if (gtIsTypeHandleToRuntimeTypeHelper(tree))
12536 else if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC)
12538 if (info.compCompHnd->getIntrinsicID(tree->gtCall.gtCallMethHnd)
12539 == CORINFO_INTRINSIC_Object_GetType)
12545 else if ((tree->gtOper == GT_INTRINSIC) &&
12546 (tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType))
12550 else if (tree->gtOper == GT_LCL_VAR)
12552 LclVarDsc * lcl = &(lvaTable[tree->gtLclVarCommon.gtLclNum]);
12553 if (lcl->TypeGet() == TYP_REF)
12555 if (lcl->lvVerTypeInfo.GetClassHandle()
12556 == info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE))
12563 bool Compiler::gtIsTypeHandleToRuntimeTypeHelper(GenTreePtr tree)
12565 return tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE) ||
12566 tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL);
12569 bool Compiler::gtIsActiveCSE_Candidate(GenTreePtr tree)
12571 return (optValnumCSE_phase && IS_CSE_INDEX(tree->gtCSEnum));
12574 /*****************************************************************************/
12576 struct ComplexityStruct
12578 unsigned m_numNodes; unsigned m_nodeLimit;
12579 ComplexityStruct(unsigned nodeLimit) : m_numNodes(0), m_nodeLimit(nodeLimit) {}
12582 static Compiler::fgWalkResult ComplexityExceedsWalker(GenTreePtr* pTree, Compiler::fgWalkData* data)
12584 ComplexityStruct* pComplexity = (ComplexityStruct*)data->pCallbackData;
12585 if (++pComplexity->m_numNodes > pComplexity->m_nodeLimit) return Compiler::WALK_ABORT;
12586 else return Compiler::WALK_CONTINUE;
12589 bool Compiler::gtComplexityExceeds(GenTreePtr* tree, unsigned limit)
12591 ComplexityStruct complexity(limit);
12592 if (fgWalkTreePre(tree, &ComplexityExceedsWalker, &complexity) == WALK_ABORT) return true;
12597 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12598 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12602 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12603 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12607 #if MEASURE_BLOCK_SIZE
12609 size_t BasicBlock::s_Size;
12611 size_t BasicBlock::s_Count;
12612 #endif // MEASURE_BLOCK_SIZE
12615 // The max # of tree nodes in any BB
12617 unsigned BasicBlock::s_nMaxTrees;
12621 /*****************************************************************************
12623 * Allocate a basic block but don't append it to the current BB list.
12626 BasicBlock * Compiler::bbNewBasicBlock(BBjumpKinds jumpKind)
12628 BasicBlock * block;
12630 /* Allocate the block descriptor and zero it out */
12631 assert(fgSafeBasicBlockCreation);
12633 block = new (this, CMK_BasicBlock) BasicBlock;
12635 #if MEASURE_BLOCK_SIZE
12636 BasicBlock::s_Count += 1;
12637 BasicBlock::s_Size += sizeof(*block);
12641 // fgLookupBB() is invalid until fgInitBBLookup() is called again.
12642 fgBBs = (BasicBlock**)0xCDCD;
12645 // TODO-Throughput: The following memset is pretty expensive - do something else?
12646 // Note that some fields have to be initialized to 0 (like bbFPStateX87)
12647 memset(block, 0, sizeof(*block));
12649 // scopeInfo needs to be able to differentiate between blocks which
12650 // correspond to some instrs (and so may have some LocalVarInfo
12651 // boundaries), or have been inserted by the JIT
12652 block->bbCodeOffs = BAD_IL_OFFSET;
12653 block->bbCodeOffsEnd = BAD_IL_OFFSET;
12655 /* Give the block a number, set the ancestor count and weight */
12659 if (compIsForInlining())
12661 block->bbNum = ++impInlineInfo->InlinerCompiler->fgBBNumMax;
12665 block->bbNum = ++fgBBNumMax;
12669 block->bbWeight = BB_UNITY_WEIGHT;
12671 block->bbStkTempsIn = NO_BASE_TMP;
12672 block->bbStkTempsOut = NO_BASE_TMP;
12674 block->bbEntryState = NULL;
12676 /* Record the jump kind in the block */
12678 block->bbJumpKind = jumpKind;
12680 if (jumpKind == BBJ_THROW)
12681 block->bbSetRunRarely();
12685 printf("New Basic Block BB%02u [%p] created.\n", block->bbNum, dspPtr(block));
12688 // We will give all the blocks var sets after the number of tracked variables
12689 // is determined and frozen. After that, if we dynamically create a basic block,
12690 // we will initialize its var sets.
12691 if (fgBBVarSetsInited)
12693 VarSetOps::AssignNoCopy(this, block->bbVarUse, VarSetOps::MakeEmpty(this));
12694 VarSetOps::AssignNoCopy(this, block->bbVarDef, VarSetOps::MakeEmpty(this));
12695 VarSetOps::AssignNoCopy(this, block->bbVarTmp, VarSetOps::MakeEmpty(this));
12696 VarSetOps::AssignNoCopy(this, block->bbLiveIn, VarSetOps::MakeEmpty(this));
12697 VarSetOps::AssignNoCopy(this, block->bbLiveOut, VarSetOps::MakeEmpty(this));
12698 VarSetOps::AssignNoCopy(this, block->bbScope, VarSetOps::MakeEmpty(this));
12702 VarSetOps::AssignNoCopy(this, block->bbVarUse, VarSetOps::UninitVal());
12703 VarSetOps::AssignNoCopy(this, block->bbVarDef, VarSetOps::UninitVal());
12704 VarSetOps::AssignNoCopy(this, block->bbVarTmp, VarSetOps::UninitVal());
12705 VarSetOps::AssignNoCopy(this, block->bbLiveIn, VarSetOps::UninitVal());
12706 VarSetOps::AssignNoCopy(this, block->bbLiveOut, VarSetOps::UninitVal());
12707 VarSetOps::AssignNoCopy(this, block->bbScope, VarSetOps::UninitVal());
12710 block->bbHeapUse = false;
12711 block->bbHeapDef = false;
12712 block->bbHeapLiveIn = false;
12713 block->bbHeapLiveOut = false;
12715 block->bbHeapSsaPhiFunc = NULL;
12716 block->bbHeapSsaNumIn = 0;
12717 block->bbHeapSsaNumOut = 0;
12719 // Make sure we reserve a NOT_IN_LOOP value that isn't a legal table index.
12720 static_assert_no_msg(MAX_LOOP_NUM < BasicBlock::NOT_IN_LOOP);
12722 block->bbNatLoopNum = BasicBlock::NOT_IN_LOOP;
12728 //------------------------------------------------------------------------------
12729 // containsStatement - return true if the block contains the given statement
12730 //------------------------------------------------------------------------------
12732 bool BasicBlock::containsStatement(GenTree *statement)
12734 assert(statement->gtOper == GT_STMT);
12736 GenTree *curr = bbTreeList;
12739 if (curr == statement)
12741 curr = curr->gtNext;
12744 return curr != NULL;
12747 GenTreeStmt* BasicBlock::FirstNonPhiDef()
12749 GenTreePtr stmt = bbTreeList;
12750 if (stmt == nullptr) return nullptr;
12751 GenTreePtr tree = stmt->gtStmt.gtStmtExpr;
12752 while ((tree->OperGet() == GT_ASG && tree->gtOp.gtOp2->OperGet() == GT_PHI)
12753 || (tree->OperGet() == GT_STORE_LCL_VAR && tree->gtOp.gtOp1->OperGet() == GT_PHI))
12755 stmt = stmt->gtNext;
12756 if (stmt == nullptr) return nullptr;
12757 tree = stmt->gtStmt.gtStmtExpr;
12759 return stmt->AsStmt();
12762 GenTreePtr BasicBlock::FirstNonPhiDefOrCatchArgAsg()
12764 GenTreePtr stmt = FirstNonPhiDef();
12765 if (stmt == nullptr) return nullptr;
12766 GenTreePtr tree = stmt->gtStmt.gtStmtExpr;
12767 if ((tree->OperGet() == GT_ASG && tree->gtOp.gtOp2->OperGet() == GT_CATCH_ARG)
12768 || (tree->OperGet() == GT_STORE_LCL_VAR && tree->gtOp.gtOp1->OperGet() == GT_CATCH_ARG))
12770 stmt = stmt->gtNext;
12775 /*****************************************************************************
12777 * Mark a block as rarely run, we also don't want to have a loop in a
12778 * rarely run block, and we set it's weight to zero.
12781 void BasicBlock::bbSetRunRarely()
12783 setBBWeight(BB_ZERO_WEIGHT);
12784 if (bbWeight == BB_ZERO_WEIGHT)
12786 bbFlags |= BBF_RUN_RARELY; // This block is never/rarely run
12790 /*****************************************************************************
12792 * Can a BasicBlock be inserted after this without altering the flowgraph
12795 bool BasicBlock::bbFallsThrough()
12797 switch (bbJumpKind)
12801 case BBJ_EHFINALLYRET:
12802 case BBJ_EHFILTERRET:
12803 case BBJ_EHCATCHRET:
12814 case BBJ_CALLFINALLY:
12815 return ((bbFlags & BBF_RETLESS_CALL) == 0);
12818 assert(!"Unknown bbJumpKind in bbFallsThrough()");
12823 unsigned BasicBlock::NumSucc(Compiler * comp)
12825 // As described in the spec comment of NumSucc at its declaration, whether "comp" is null determines
12826 // whether NumSucc and GetSucc yield successors of finally blocks.
12828 switch (bbJumpKind)
12835 case BBJ_EHFILTERRET:
12841 case BBJ_EHFINALLYRET:
12849 // The first block of the handler is labelled with the catch type.
12850 BasicBlock* hndBeg = comp->fgFirstBlockOfHandler(this);
12851 if (hndBeg->bbCatchTyp == BBCT_FINALLY)
12853 return comp->fgNSuccsOfFinallyRet(this);
12857 assert(hndBeg->bbCatchTyp == BBCT_FAULT); // We can only BBJ_EHFINALLYRET from FINALLY and FAULT.
12858 // A FAULT block has no successors.
12863 case BBJ_CALLFINALLY:
12865 case BBJ_EHCATCHRET:
12870 if (bbJumpDest == bbNext)
12881 return bbJumpSwt->bbsCount;
12884 Compiler::SwitchUniqueSuccSet sd = comp->GetDescriptorForSwitch(this);
12885 return sd.numDistinctSuccs;
12894 BasicBlock* BasicBlock::GetSucc(unsigned i, Compiler * comp)
12896 // As described in the spec comment of GetSucc at its declaration, whether "comp" is null determines
12897 // whether NumSucc and GetSucc yield successors of finally blocks.
12899 assert(i < NumSucc(comp)); // Index bounds check.
12900 //printf("bbjk=%d\n", bbJumpKind);
12901 switch (bbJumpKind)
12906 unreached(); // Should have been covered by assert above.
12908 case BBJ_EHFILTERRET:
12910 assert(comp != NULL); // Or else we're not looking for successors.
12911 BasicBlock* result = comp->fgFirstBlockOfHandler(this);
12912 noway_assert(result == bbJumpDest);
12913 // Handler is the (sole) normal successor of the filter.
12917 case BBJ_EHFINALLYRET:
12918 return comp->fgSuccOfFinallyRet(this, i);
12920 case BBJ_CALLFINALLY:
12922 case BBJ_EHCATCHRET:
12941 assert(i < bbJumpSwt->bbsCount); // Range check.
12942 return bbJumpSwt->bbsDstTab[i];
12946 // Remove duplicates.
12947 Compiler::SwitchUniqueSuccSet sd = comp->GetDescriptorForSwitch(this);
12948 assert(i < sd.numDistinctSuccs); // Range check.
12949 return sd.nonDuplicates[i];
12957 // -------------------------------------------------------------------------
12958 // IsRegOptional: Returns true if this gentree node is marked by lowering to
12959 // indicate that codegen can still generate code even if it wasn't allocated
12961 bool GenTree::IsRegOptional() const
12963 #ifdef LEGACY_BACKEND
12966 return gtLsraInfo.regOptional;
12970 bool GenTree::IsPhiDefn()
12973 OperGet() == GT_ASG
12974 && gtOp.gtOp2 != NULL
12975 && gtOp.gtOp2->OperGet() == GT_PHI;
12976 assert(!res || gtOp.gtOp1->OperGet() == GT_LCL_VAR);
12980 bool GenTree::IsPhiDefnStmt()
12982 if (OperGet() != GT_STMT) return false;
12983 GenTreePtr asg = gtStmt.gtStmtExpr;
12984 return asg->IsPhiDefn();
12987 // IsPartialLclFld: Check for a GT_LCL_FLD whose type is a different size than the lclVar.
12990 // comp - the Compiler object.
12993 // Returns "true" iff 'this' is a GT_LCL_FLD or GT_STORE_LCL_FLD on which the type
12994 // is not the same size as the type of the GT_LCL_VAR
12996 bool GenTree::IsPartialLclFld(Compiler* comp)
12998 return ((gtOper == GT_LCL_FLD) &&
12999 (comp->lvaTable[this->gtLclVarCommon.gtLclNum].lvExactSize != genTypeSize(gtType)));
13002 bool GenTree::DefinesLocal(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, bool* pIsEntire)
13004 if (OperIsAssignment())
13006 if (gtOp.gtOp1->IsLocal())
13008 GenTreeLclVarCommon* lclVarTree = gtOp.gtOp1->AsLclVarCommon();
13009 *pLclVarTree = lclVarTree;
13010 if (pIsEntire != nullptr)
13012 if (lclVarTree->IsPartialLclFld(comp))
13014 *pIsEntire = false;
13023 else if (gtOp.gtOp1->OperGet() == GT_IND)
13025 GenTreePtr indArg = gtOp.gtOp1->gtOp.gtOp1;
13026 return indArg->DefinesLocalAddr(comp, genTypeSize(gtOp.gtOp1->TypeGet()), pLclVarTree, pIsEntire);
13029 else if (OperIsBlkOp())
13031 GenTreePtr destAddr = gtOp.gtOp1->gtOp.gtOp1;
13032 unsigned width = 0;
13033 // Do we care about whether this assigns the entire variable?
13034 if (pIsEntire != NULL)
13036 GenTreePtr blockWidth = gtOp.gtOp2;
13037 if (blockWidth->IsCnsIntOrI())
13039 if (blockWidth->IsIconHandle())
13041 // If it's a handle, it must be a class handle. We only create such block operations
13042 // for initialization of struct types, so the type of the argument(s) will match this
13043 // type, by construction, and be "entire".
13044 assert(blockWidth->IsIconHandle(GTF_ICON_CLASS_HDL));
13045 width = comp->info.compCompHnd->getClassSize(CORINFO_CLASS_HANDLE(blockWidth->gtIntConCommon.IconValue()));
13049 ssize_t swidth = blockWidth->AsIntConCommon()->IconValue();
13050 assert(swidth >= 0);
13051 // cpblk of size zero exists in the wild (in yacc-generated code in SQL) and is valid IL.
13054 width = unsigned(swidth);
13058 return destAddr->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
13064 // Returns true if this GenTree defines a result which is based on the address of a local.
13065 bool GenTree::DefinesLocalAddr(Compiler* comp, unsigned width, GenTreeLclVarCommon** pLclVarTree, bool* pIsEntire)
13067 if (OperGet() == GT_ADDR || OperGet() == GT_LCL_VAR_ADDR)
13069 GenTreePtr addrArg = this;
13070 if (OperGet() == GT_ADDR)
13072 addrArg = gtOp.gtOp1;
13075 if (addrArg->IsLocal() || addrArg->OperIsLocalAddr())
13077 GenTreeLclVarCommon* addrArgLcl = addrArg->AsLclVarCommon();
13078 *pLclVarTree = addrArgLcl;
13079 if (pIsEntire != NULL)
13081 unsigned lclNum = addrArgLcl->GetLclNum();
13082 unsigned varWidth = comp->lvaLclExactSize(lclNum);
13083 if (comp->lvaTable[lclNum].lvNormalizeOnStore())
13085 // It's normalize on store, so use the full storage width -- writing to low bytes won't
13086 // necessarily yield a normalized value.
13087 varWidth = genTypeStSz(var_types(comp->lvaTable[lclNum].lvType)) * sizeof(int);
13089 *pIsEntire = (varWidth == width);
13093 else if (addrArg->OperGet() == GT_IND)
13095 // A GT_ADDR of a GT_IND can both be optimized away, recurse using the child of the GT_IND
13096 return addrArg->gtOp.gtOp1->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
13099 else if (OperGet() == GT_ADD)
13101 if (gtOp.gtOp1->IsCnsIntOrI())
13103 // If we just adding a zero then we allow an IsEntire match against width
13104 // otherwise we change width to zero to disallow an IsEntire Match
13105 return gtOp.gtOp2->DefinesLocalAddr(comp, gtOp.gtOp1->IsIntegralConst(0) ? width : 0, pLclVarTree, pIsEntire);
13107 else if (gtOp.gtOp2->IsCnsIntOrI())
13109 // If we just adding a zero then we allow an IsEntire match against width
13110 // otherwise we change width to zero to disallow an IsEntire Match
13111 return gtOp.gtOp1->DefinesLocalAddr(comp, gtOp.gtOp2->IsIntegralConst(0) ? width : 0, pLclVarTree, pIsEntire);
13114 // Post rationalization we could have GT_IND(GT_LEA(..)) trees.
13115 else if (OperGet() == GT_LEA)
13117 // This method gets invoked during liveness computation and therefore it is critical
13118 // that we don't miss 'use' of any local. The below logic is making the assumption
13119 // that in case of LEA(base, index, offset) - only base can be a GT_LCL_VAR_ADDR
13120 // and index is not.
13122 GenTreePtr index = gtOp.gtOp2;
13123 if (index != nullptr)
13125 assert(!index->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire));
13130 GenTreePtr base = gtOp.gtOp1;
13131 if (base != nullptr)
13133 // Lea could have an Indir as its base.
13134 if (base->OperGet() == GT_IND)
13136 base = base->gtOp.gtOp1->gtEffectiveVal(/*commas only*/ true);
13138 return base->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
13145 //------------------------------------------------------------------------
13146 // IsLocalExpr: Determine if this is a LclVarCommon node and return some
13147 // additional info about it in the two out parameters.
13150 // comp - The Compiler instance
13151 // pLclVarTree - An "out" argument that returns the local tree as a
13152 // LclVarCommon, if it is indeed local.
13153 // pFldSeq - An "out" argument that returns the value numbering field
13154 // sequence for the node, if any.
13157 // Returns true, and sets the out arguments accordingly, if this is
13158 // a LclVarCommon node.
13160 bool GenTree::IsLocalExpr(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, FieldSeqNode** pFldSeq)
13162 if (IsLocal()) // Note that this covers "GT_LCL_FLD."
13164 *pLclVarTree = AsLclVarCommon();
13165 if (OperGet() == GT_LCL_FLD)
13167 // Otherwise, prepend this field to whatever we've already accumulated outside in.
13168 *pFldSeq = comp->GetFieldSeqStore()->Append(AsLclFld()->gtFieldSeq, *pFldSeq);
13178 // If this tree evaluates some sum of a local address and some constants,
13179 // return the node for the local being addressed
13181 GenTreeLclVarCommon* GenTree::IsLocalAddrExpr()
13183 if (OperGet() == GT_ADDR)
13185 return gtOp.gtOp1->IsLocal() ? gtOp.gtOp1->AsLclVarCommon() : nullptr;
13187 else if (OperIsLocalAddr())
13189 return this->AsLclVarCommon();
13191 else if (OperGet() == GT_ADD)
13193 if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
13195 return gtOp.gtOp2->IsLocalAddrExpr();
13197 else if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
13199 return gtOp.gtOp1->IsLocalAddrExpr();
13207 bool GenTree::IsLocalAddrExpr(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, FieldSeqNode** pFldSeq)
13209 if (OperGet() == GT_ADDR)
13211 assert(!comp->compRationalIRForm);
13212 GenTreePtr addrArg = gtOp.gtOp1;
13213 if (addrArg->IsLocal()) // Note that this covers "GT_LCL_FLD."
13215 *pLclVarTree = addrArg->AsLclVarCommon();
13216 if (addrArg->OperGet() == GT_LCL_FLD)
13218 // Otherwise, prepend this field to whatever we've already accumulated outside in.
13219 *pFldSeq = comp->GetFieldSeqStore()->Append(addrArg->AsLclFld()->gtFieldSeq, *pFldSeq);
13228 else if (OperIsLocalAddr())
13230 *pLclVarTree = this->AsLclVarCommon();
13231 if (this->OperGet() == GT_LCL_FLD_ADDR)
13233 *pFldSeq = comp->GetFieldSeqStore()->Append(this->AsLclFld()->gtFieldSeq, *pFldSeq);
13237 else if (OperGet() == GT_ADD)
13239 if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
13241 if (gtOp.gtOp1->AsIntCon()->gtFieldSeq == NULL)
13243 // Otherwise, prepend this field to whatever we've already accumulated outside in.
13244 *pFldSeq = comp->GetFieldSeqStore()->Append(gtOp.gtOp1->AsIntCon()->gtFieldSeq, *pFldSeq);
13245 return gtOp.gtOp2->IsLocalAddrExpr(comp, pLclVarTree, pFldSeq);
13247 else if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
13249 if (gtOp.gtOp2->AsIntCon()->gtFieldSeq == NULL)
13251 // Otherwise, prepend this field to whatever we've already accumulated outside in.
13252 *pFldSeq = comp->GetFieldSeqStore()->Append(gtOp.gtOp2->AsIntCon()->gtFieldSeq, *pFldSeq);
13253 return gtOp.gtOp1->IsLocalAddrExpr(comp, pLclVarTree, pFldSeq);
13260 //------------------------------------------------------------------------
13261 // IsLclVarUpdateTree: Determine whether this is an assignment tree of the
13262 // form Vn = Vn 'oper' 'otherTree' where Vn is a lclVar
13265 // pOtherTree - An "out" argument in which 'otherTree' will be returned.
13266 // pOper - An "out" argument in which 'oper' will be returned.
13269 // If the tree is of the above form, the lclNum of the variable being
13270 // updated is returned, and 'pOtherTree' and 'pOper' are set.
13271 // Otherwise, returns BAD_VAR_NUM.
13274 // 'otherTree' can have any shape.
13275 // We avoid worrying about whether the op is commutative by only considering the
13276 // first operand of the rhs. It is expected that most trees of this form will
13277 // already have the lclVar on the lhs.
13278 // TODO-CQ: Evaluate whether there are missed opportunities due to this, or
13279 // whether gtSetEvalOrder will already have put the lclVar on the lhs in
13280 // the cases of interest.
13283 GenTree::IsLclVarUpdateTree(GenTree** pOtherTree, genTreeOps *pOper)
13285 unsigned lclNum = BAD_VAR_NUM;
13286 if (OperIsAssignment())
13288 GenTree* lhs = gtOp.gtOp1;
13289 if (lhs->OperGet() == GT_LCL_VAR)
13291 unsigned lhsLclNum = lhs->AsLclVarCommon()->gtLclNum;
13292 if (gtOper == GT_ASG)
13294 GenTree* rhs = gtOp.gtOp2;
13295 if (rhs->OperIsBinary() &&
13296 (rhs->gtOp.gtOp1->gtOper == GT_LCL_VAR) &&
13297 (rhs->gtOp.gtOp1->AsLclVarCommon()->gtLclNum == lhsLclNum))
13299 lclNum = lhsLclNum;
13300 *pOtherTree = rhs->gtOp.gtOp2;
13301 *pOper = rhs->gtOper;
13306 lclNum = lhsLclNum;
13307 *pOper = GenTree::OpAsgToOper(gtOper);
13308 *pOtherTree = gtOp.gtOp2;
13315 // return true if this tree node is a subcomponent of parent for codegen purposes
13316 // (essentially, will be rolled into the same instruction)
13317 // Note that this method relies upon the value of gtRegNum field to determine
13318 // if the treenode is contained or not. Therefore you can not call this method
13319 // until after the LSRA phase has allocated physical registers to the treenodes.
13320 bool GenTree::isContained() const
13322 if (isContainedSpillTemp())
13332 // these actually produce a register (the flags reg, we just don't model it)
13333 // and are a separate instruction from the branch that consumes the result
13334 if (OperKind() & GTK_RELOP)
13339 // TODO-Cleanup : this is not clean, would be nice to have some way of marking this.
13345 case GT_STORE_LCL_FLD:
13346 case GT_STORE_LCL_VAR:
13347 case GT_ARR_BOUNDS_CHECK:
13351 case GT_START_NONGC:
13353 case GT_RETURNTRAP:
13355 case GT_PINVOKE_PROLOG:
13356 case GT_PHYSREGDST:
13357 case GT_PUTARG_STK:
13358 case GT_MEMORYBARRIER:
13364 case GT_SWITCH_TABLE:
13369 #ifdef FEATURE_SIMD
13371 #endif // FEATURE_SIMD
13373 #if !FEATURE_EH_FUNCLETS
13378 #if !defined(LEGACY_BACKEND) && !defined(_TARGET_64BIT_)
13380 // GT_LONG nodes are normally contained. The only exception is when the result
13381 // of a TYP_LONG operation is not used and this can only happen if the GT_LONG
13382 // is the last node in the statement (in linear order).
13383 return gtNext != nullptr;
13387 // Note: if you hit this assert you are probably calling isContained()
13388 // before the LSRA phase has allocated physical register to the tree nodes
13390 assert(gtType == TYP_VOID);
13393 if (gtType == TYP_VOID)
13394 return false; // endfinally case
13399 // if it's contained it better have a parent
13400 assert(gtNext || OperIsLocal());
13405 // return true if node is contained and an indir
13406 bool GenTree::isContainedIndir() const
13408 return isContained() && isIndir();
13411 bool GenTree::isIndirAddrMode()
13413 return isIndir() && AsIndir()->Addr()->OperIsAddrMode() && AsIndir()->Addr()->isContained();
13416 bool GenTree::isIndir() const
13418 return OperGet() == GT_IND || OperGet() == GT_STOREIND;
13421 bool GenTreeIndir::HasBase()
13423 return Base() != nullptr;
13426 bool GenTreeIndir::HasIndex()
13428 return Index() != nullptr;
13431 GenTreePtr GenTreeIndir::Base()
13433 GenTreePtr addr = Addr();
13435 if (isIndirAddrMode())
13437 GenTree* result = addr->AsAddrMode()->Base();
13438 if (result != nullptr)
13440 result = result->gtEffectiveVal();
13446 return addr; // TODO: why do we return 'addr' here, but we return 'nullptr' in the equivalent Index() case?
13450 GenTree* GenTreeIndir::Index()
13452 if (isIndirAddrMode())
13454 GenTree* result = Addr()->AsAddrMode()->Index();
13455 if (result != nullptr)
13457 result = result->gtEffectiveVal();
13467 unsigned GenTreeIndir::Scale()
13470 return Addr()->AsAddrMode()->gtScale;
13475 size_t GenTreeIndir::Offset()
13477 if (isIndirAddrMode())
13478 return Addr()->AsAddrMode()->gtOffset;
13479 else if (Addr()->gtOper == GT_CLS_VAR_ADDR)
13480 return (size_t) Addr()->gtClsVar.gtClsVarHnd;
13481 else if (Addr()->IsCnsIntOrI() && Addr()->isContained())
13482 return Addr()->AsIntConCommon()->IconValue();
13487 //------------------------------------------------------------------------
13488 // GenTreeIntConCommon::ImmedValNeedsReloc: does this immediate value needs recording a relocation with the VM?
13491 // comp - Compiler instance
13494 // True if this immediate value needs recording a relocation with the VM; false otherwise.
13496 bool GenTreeIntConCommon::ImmedValNeedsReloc(Compiler* comp)
13498 #ifdef RELOC_SUPPORT
13499 return comp->opts.compReloc && (gtOper == GT_CNS_INT) && IsIconHandle();
13505 //------------------------------------------------------------------------
13506 // ImmedValCanBeFolded: can this immediate value be folded for op?
13509 // comp - Compiler instance
13510 // op - Tree operator
13513 // True if this immediate value can be folded for op; false otherwise.
13515 bool GenTreeIntConCommon::ImmedValCanBeFolded(Compiler* comp, genTreeOps op)
13517 // In general, immediate values that need relocations can't be folded.
13518 // There are cases where we do want to allow folding of handle comparisons
13519 // (e.g., typeof(T) == typeof(int)).
13520 return !ImmedValNeedsReloc(comp) || (op == GT_EQ) || (op == GT_NE);
13523 #ifdef _TARGET_AMD64_
13524 // Returns true if this absolute address fits within the base of an addr mode.
13525 // On Amd64 this effectively means, whether an absolute indirect address can
13526 // be encoded as 32-bit offset relative to IP or zero.
13527 bool GenTreeIntConCommon::FitsInAddrBase(Compiler* comp)
13529 #ifndef LEGACY_BACKEND
13531 // Early out if PC-rel encoding of absolute addr is disabled.
13532 if (!comp->opts.compEnablePCRelAddr)
13537 #endif //!LEGACY_BACKEND
13539 if (comp->opts.compReloc)
13541 // During Ngen JIT is always asked to generate relocatable code.
13542 // Hence JIT will try to encode only icon handles as pc-relative offsets.
13543 return IsIconHandle() && (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void *)IconValue()));
13547 // During Jitting, we are allowed to generate non-relocatable code.
13548 // On Amd64 we can encode an absolute indirect addr as an offset relative to zero or RIP.
13549 // An absolute indir addr that can fit within 32-bits can ben encoded as an offset relative
13550 // to zero. All other absolute indir addr could be attempted to be encoded as RIP relative
13551 // based on reloc hint provided by VM. RIP relative encoding is preferred over relative
13552 // to zero, because the former is one byte smaller than the latter. For this reason
13553 // we check for reloc hint first and then whether addr fits in 32-bits next.
13555 // VM starts off with an initial state to allow both data and code address to be encoded as
13556 // pc-relative offsets. Hence JIT will attempt to encode all absolute addresses as pc-relative
13557 // offsets. It is possible while jitting a method, an address could not be encoded as a
13558 // pc-relative offset. In that case VM will note the overflow and will trigger re-jitting
13559 // of the method with reloc hints turned off for all future methods. Second time around
13560 // jitting will succeed since JIT will not attempt to encode data addresses as pc-relative
13561 // offsets. Note that JIT will always attempt to relocate code addresses (.e.g call addr).
13562 // After an overflow, VM will assume any relocation recorded is for a code address and will
13563 // emit jump thunk if it cannot be encoded as pc-relative offset.
13564 return (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void *)IconValue())) || FitsInI32();
13568 // Returns true if this icon value is encoded as addr needs recording a relocation with VM
13569 bool GenTreeIntConCommon::AddrNeedsReloc(Compiler* comp)
13571 if (comp->opts.compReloc)
13573 // During Ngen JIT is always asked to generate relocatable code.
13574 // Hence JIT will try to encode only icon handles as pc-relative offsets.
13575 return IsIconHandle() && (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void *)IconValue()));
13579 return IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void *)IconValue());
13583 #elif defined(_TARGET_X86_)
13584 // Returns true if this absolute address fits within the base of an addr mode.
13585 // On x86 all addresses are 4-bytes and can be directly encoded in an addr mode.
13586 bool GenTreeIntConCommon::FitsInAddrBase(Compiler* comp)
13588 #ifndef LEGACY_BACKEND
13590 // Early out if PC-rel encoding of absolute addr is disabled.
13591 if (!comp->opts.compEnablePCRelAddr)
13596 #endif //!LEGACY_BACKEND
13598 //TODO-x86 - TLS field handles are excluded for now as they are accessed relative to FS segment.
13599 //Handling of TLS field handles is a NYI and this needs to be relooked after implementing it.
13600 return IsCnsIntOrI() && !IsIconHandle(GTF_ICON_TLS_HDL);
13603 // Returns true if this icon value is encoded as addr needs recording a relocation with VM
13604 bool GenTreeIntConCommon::AddrNeedsReloc(Compiler* comp)
13606 //If generating relocatable code, icons should be reported for recording relocatons.
13607 return comp->opts.compReloc && IsIconHandle();
13609 #endif //_TARGET_X86_
13611 bool GenTree::IsFieldAddr(Compiler* comp, GenTreePtr* pObj, GenTreePtr* pStatic, FieldSeqNode** pFldSeq)
13613 FieldSeqNode* newFldSeq = nullptr;
13614 GenTreePtr baseAddr = nullptr;
13615 bool mustBeStatic = false;
13617 FieldSeqNode* statStructFldSeq = nullptr;
13618 if (TypeGet() == TYP_REF)
13620 // Recognize struct static field patterns...
13621 if (OperGet() == GT_IND)
13623 GenTreePtr addr = gtOp.gtOp1;
13624 GenTreeIntCon* icon = nullptr;
13625 if (addr->OperGet() == GT_CNS_INT)
13627 icon = addr->AsIntCon();
13629 else if (addr->OperGet() == GT_ADD)
13631 // op1 should never be a field sequence (or any other kind of handle)
13632 assert((addr->gtOp.gtOp1->gtOper != GT_CNS_INT) || !addr->gtOp.gtOp1->IsIconHandle());
13633 if (addr->gtOp.gtOp2->OperGet() == GT_CNS_INT)
13635 icon = addr->gtOp.gtOp2->AsIntCon();
13638 if ( icon != nullptr
13639 && !icon->IsIconHandle(GTF_ICON_STR_HDL) // String handles are a source of TYP_REFs.
13640 && icon->gtFieldSeq != nullptr
13641 && icon->gtFieldSeq->m_next == nullptr // A static field should be a singleton
13642 // TODO-Review: A pseudoField here indicates an issue - this requires investigation
13643 // See test case src\ddsuites\src\clr\x86\CoreMangLib\Dev\Globalization\CalendarRegressions.exe
13644 && !(FieldSeqStore::IsPseudoField(icon->gtFieldSeq->m_fieldHnd))
13645 && icon->gtFieldSeq != FieldSeqStore::NotAField()) // Ignore non-fields.
13647 statStructFldSeq = icon->gtFieldSeq;
13651 addr = addr->gtEffectiveVal();
13653 // Perhaps it's a direct indirection of a helper call or a cse with a zero offset annotation.
13654 if ((addr->OperGet() == GT_CALL) || (addr->OperGet() == GT_LCL_VAR))
13656 FieldSeqNode* zeroFieldSeq = nullptr;
13657 if (comp->GetZeroOffsetFieldMap()->Lookup(addr, &zeroFieldSeq))
13659 if (zeroFieldSeq->m_next == nullptr)
13660 statStructFldSeq = zeroFieldSeq;
13665 else if (OperGet() == GT_CLS_VAR)
13667 GenTreeClsVar* clsVar = AsClsVar();
13668 if (clsVar->gtFieldSeq != nullptr && clsVar->gtFieldSeq->m_next == nullptr)
13670 statStructFldSeq = clsVar->gtFieldSeq;
13673 else if (OperIsLocal())
13675 // If we have a GT_LCL_VAR, it can be result of a CSE substitution
13676 // If it is then the CSE assignment will have a ValueNum that
13677 // describes the RHS of the CSE assignment.
13679 // The CSE could be a pointer to a boxed struct
13681 GenTreeLclVarCommon* lclVar = AsLclVarCommon();
13682 ValueNum vn = gtVNPair.GetLiberal();
13683 if (vn != ValueNumStore::NoVN)
13685 // Is the ValueNum a MapSelect involving a SharedStatic helper?
13686 VNFuncApp funcApp1;
13687 if (comp->vnStore->GetVNFunc(vn, &funcApp1) &&
13688 (funcApp1.m_func == VNF_MapSelect) &&
13689 (comp->vnStore->IsSharedStatic(funcApp1.m_args[1])))
13691 ValueNum mapVN = funcApp1.m_args[0];
13692 // Is this new 'mapVN' ValueNum, a MapSelect involving a handle?
13693 VNFuncApp funcApp2;
13694 if (comp->vnStore->GetVNFunc(mapVN, &funcApp2) &&
13695 (funcApp2.m_func == VNF_MapSelect) &&
13696 (comp->vnStore->IsVNHandle(funcApp2.m_args[1])))
13698 ValueNum fldHndVN = funcApp2.m_args[1];
13699 // Is this new 'fldHndVN' VNhandle a FieldHandle?
13700 unsigned flags = comp->vnStore->GetHandleFlags(fldHndVN);
13701 if (flags == GTF_ICON_FIELD_HDL)
13703 CORINFO_FIELD_HANDLE fieldHnd = CORINFO_FIELD_HANDLE(comp->vnStore->ConstantValue<ssize_t>(fldHndVN));
13705 // Record this field sequence in 'statStructFldSeq' as it is likely to be a Boxed Struct field access.
13706 statStructFldSeq = comp->GetFieldSeqStore()->CreateSingleton(fieldHnd);
13713 if (statStructFldSeq != nullptr)
13715 assert(statStructFldSeq->m_next == nullptr);
13716 // Is this a pointer to a boxed struct?
13717 if (comp->gtIsStaticFieldPtrToBoxedStruct(TYP_REF, statStructFldSeq->m_fieldHnd))
13719 *pFldSeq = comp->GetFieldSeqStore()->Append(statStructFldSeq, *pFldSeq);
13728 *pStatic = nullptr;
13731 else if (OperGet() == GT_ADD)
13733 // op1 should never be a field sequence (or any other kind of handle)
13734 assert((gtOp.gtOp1->gtOper != GT_CNS_INT) || !gtOp.gtOp1->IsIconHandle());
13735 if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
13737 newFldSeq = gtOp.gtOp2->AsIntCon()->gtFieldSeq;
13738 baseAddr = gtOp.gtOp1;
13743 // Check if "this" has a zero-offset annotation.
13744 if (!comp->GetZeroOffsetFieldMap()->Lookup(this, &newFldSeq))
13746 // If not, this is not a field address.
13752 mustBeStatic = true;
13756 // If not we don't have a field seq, it's not a field address.
13757 if (newFldSeq == nullptr || newFldSeq == FieldSeqStore::NotAField())
13760 // Prepend this field to whatever we've already accumulated (outside-in).
13761 *pFldSeq = comp->GetFieldSeqStore()->Append(newFldSeq, *pFldSeq);
13763 // Is it a static or instance field?
13764 if (!FieldSeqStore::IsPseudoField(newFldSeq->m_fieldHnd) &&
13765 comp->info.compCompHnd->isFieldStatic(newFldSeq->m_fieldHnd))
13767 // It is a static field. We're done.
13769 *pStatic = baseAddr;
13772 else if ((baseAddr != nullptr) && !mustBeStatic)
13774 // It's an instance field...but it must be for a struct field, since we've not yet encountered
13775 // a "TYP_REF" address. Analyze the reset of the address.
13776 return baseAddr->gtEffectiveVal()->IsFieldAddr(comp, pObj, pStatic, pFldSeq);
13783 bool Compiler::gtIsStaticFieldPtrToBoxedStruct(var_types fieldNodeType, CORINFO_FIELD_HANDLE fldHnd)
13785 if (fieldNodeType != TYP_REF) return false;
13786 CORINFO_CLASS_HANDLE fldCls = nullptr;
13787 noway_assert(fldHnd != nullptr);
13788 CorInfoType cit = info.compCompHnd->getFieldType(fldHnd, &fldCls);
13789 var_types fieldTyp = JITtype2varType(cit);
13790 return fieldTyp != TYP_REF;
13793 CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleIfPresent(GenTree* tree)
13795 CORINFO_CLASS_HANDLE structHnd = NO_CLASS_HANDLE;
13796 tree = tree->gtEffectiveVal();
13797 if (varTypeIsStruct(tree->gtType))
13799 switch(tree->gtOper)
13803 case GT_MKREFANY: structHnd = impGetRefAnyClass(); break;
13804 case GT_OBJ: structHnd = tree->gtObj.gtClass; break;
13805 case GT_CALL: structHnd = tree->gtCall.gtRetClsHnd; break;
13806 case GT_RET_EXPR: structHnd = tree->gtRetExpr.gtRetClsHnd; break;
13807 case GT_ARGPLACE: structHnd = tree->gtArgPlace.gtArgPlaceClsHnd; break;
13808 case GT_INDEX: structHnd = tree->gtIndex.gtStructElemClass; break;
13809 case GT_FIELD: info.compCompHnd->getFieldType(tree->gtField.gtFldHnd, &structHnd); break;
13811 structHnd = gtGetStructHandle(tree->gtGetOp1());
13815 structHnd = lvaTable[tree->AsLclVarCommon()->gtLclNum].lvVerTypeInfo.GetClassHandle();
13818 structHnd = gtGetStructHandleIfPresent(tree->gtOp.gtOp1);
13821 #ifdef FEATURE_SIMD
13822 if (varTypeIsSIMD(tree))
13824 structHnd = gtGetStructHandleForSIMD(tree->gtType, TYP_FLOAT);
13828 if (tree->gtFlags & GTF_IND_ARR_INDEX)
13831 bool b = GetArrayInfoMap()->Lookup(tree, &arrInfo);
13833 structHnd = EncodeElemType(arrInfo.m_elemType, arrInfo.m_elemStructType);
13836 #ifdef FEATURE_SIMD
13838 structHnd = gtGetStructHandleForSIMD(tree->gtType, tree->AsSIMD()->gtSIMDBaseType);
13839 #endif // FEATURE_SIMD
13846 CORINFO_CLASS_HANDLE Compiler::gtGetStructHandle(GenTree* tree)
13848 CORINFO_CLASS_HANDLE structHnd = gtGetStructHandleIfPresent(tree);
13849 assert(structHnd != NO_CLASS_HANDLE);
13853 void GenTree::ParseArrayAddress(Compiler* comp, ArrayInfo* arrayInfo, GenTreePtr* pArr, ValueNum* pInxVN, FieldSeqNode** pFldSeq)
13856 ValueNum inxVN = ValueNumStore::NoVN;
13857 ssize_t offset = 0;
13858 FieldSeqNode* fldSeq = nullptr;
13860 ParseArrayAddressWork(comp, 1, pArr, &inxVN, &offset, &fldSeq);
13862 // If we didn't find an array reference (perhaps it is the constant null?) we will give up.
13863 if (*pArr == nullptr) return;
13865 // OK, new we have to figure out if any part of the "offset" is a constant contribution to the index.
13866 // First, sum the offsets of any fields in fldSeq.
13867 unsigned fieldOffsets = 0;
13868 FieldSeqNode* fldSeqIter = fldSeq;
13869 // Also, find the first non-pseudo field...
13870 assert(*pFldSeq == nullptr);
13871 while (fldSeqIter != nullptr)
13873 if (fldSeqIter == FieldSeqStore::NotAField())
13875 // TODO-Review: A NotAField here indicates a failure to properly maintain the field sequence
13876 // See test case self_host_tests_x86\jit\regression\CLR-x86-JIT\v1-m12-beta2\ b70992\ b70992.exe
13877 // Safest thing to do here is to drop back to MinOpts
13878 noway_assert(!"fldSeqIter is NotAField() in ParseArrayAddress");
13881 if (!FieldSeqStore::IsPseudoField(fldSeqIter->m_fieldHnd))
13883 if (*pFldSeq == nullptr)
13884 *pFldSeq = fldSeqIter;
13885 CORINFO_CLASS_HANDLE fldCls = nullptr;
13886 noway_assert(fldSeqIter->m_fieldHnd != nullptr);
13887 CorInfoType cit = comp->info.compCompHnd->getFieldType(fldSeqIter->m_fieldHnd, &fldCls);
13888 fieldOffsets += comp->compGetTypeSize(cit, fldCls);
13890 fldSeqIter = fldSeqIter->m_next;
13893 // Is there some portion of the "offset" beyond the first-elem offset and the struct field suffix we just computed?
13894 if ( !FitsIn<ssize_t>(fieldOffsets + arrayInfo->m_elemOffset)
13895 || !FitsIn<ssize_t>(arrayInfo->m_elemSize))
13897 // This seems unlikely, but no harm in being safe...
13898 *pInxVN = comp->GetValueNumStore()->VNForExpr(TYP_INT);
13902 ssize_t offsetAccountedFor = static_cast<ssize_t>(fieldOffsets + arrayInfo->m_elemOffset);
13903 ssize_t elemSize = static_cast<ssize_t>(arrayInfo->m_elemSize);
13905 ssize_t constIndOffset = offset - offsetAccountedFor;
13906 // This should be divisible by the element size...
13907 assert((constIndOffset % elemSize) == 0);
13908 ssize_t constInd = constIndOffset / elemSize;
13910 ValueNumStore* vnStore = comp->GetValueNumStore();
13912 if (inxVN == ValueNumStore::NoVN)
13914 // Must be a constant index.
13915 *pInxVN = vnStore->VNForPtrSizeIntCon(constInd);
13920 // Perform ((inxVN / elemSizeVN) + vnForConstInd)
13923 // The value associated with the index value number (inxVN) is the offset into the array,
13924 // which has been scaled by element size. We need to recover the array index from that offset
13925 if (vnStore->IsVNConstant(inxVN))
13927 ssize_t index = vnStore->CoercedConstantValue<ssize_t>(inxVN);
13928 noway_assert(elemSize > 0 && ((index % elemSize) == 0));
13929 *pInxVN = vnStore->VNForPtrSizeIntCon((index / elemSize) + constInd);
13933 bool canFoldDiv = false;
13935 // If the index VN is a MUL by elemSize, see if we can eliminate it instead of adding
13936 // the division by elemSize.
13938 if (vnStore->GetVNFunc(inxVN, &funcApp) && funcApp.m_func == (VNFunc) GT_MUL)
13940 ValueNum vnForElemSize = vnStore->VNForLongCon(elemSize);
13942 // One of the multiply operand is elemSize, so the resulting
13943 // index VN should simply be the other operand.
13944 if (funcApp.m_args[1] == vnForElemSize)
13946 *pInxVN = funcApp.m_args[0];
13949 else if (funcApp.m_args[0] == vnForElemSize)
13951 *pInxVN = funcApp.m_args[1];
13956 // Perform ((inxVN / elemSizeVN) + vnForConstInd)
13959 ValueNum vnForElemSize = vnStore->VNForPtrSizeIntCon(elemSize);
13960 ValueNum vnForScaledInx = vnStore->VNForFunc(TYP_I_IMPL, GetVNFuncForOper(GT_DIV, false), inxVN, vnForElemSize);
13961 *pInxVN = vnForScaledInx;
13966 ValueNum vnForConstInd = comp->GetValueNumStore()->VNForPtrSizeIntCon(constInd);
13967 *pInxVN = comp->GetValueNumStore()->VNForFunc(TYP_I_IMPL, GetVNFuncForOper(GT_ADD, (gtFlags & GTF_UNSIGNED) != 0), *pInxVN, vnForConstInd);
13973 void GenTree::ParseArrayAddressWork(Compiler* comp, ssize_t inputMul, GenTreePtr* pArr, ValueNum* pInxVN, ssize_t* pOffset, FieldSeqNode** pFldSeq)
13975 if (TypeGet() == TYP_REF)
13977 // This must be the array pointer.
13979 assert(inputMul == 1); // Can't multiply the array pointer by anything.
13986 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, gtIntCon.gtFieldSeq);
13987 *pOffset += (inputMul * gtIntCon.gtIconVal);
13992 gtOp.gtOp1->ParseArrayAddressWork(comp, inputMul, pArr, pInxVN, pOffset, pFldSeq);
13993 if (OperGet() == GT_SUB)
13994 inputMul = -inputMul;
13995 gtOp.gtOp2->ParseArrayAddressWork(comp, inputMul, pArr, pInxVN, pOffset, pFldSeq);
14000 // If one op is a constant, continue parsing down.
14001 ssize_t subMul = 0;
14002 GenTreePtr nonConst = nullptr;
14003 if (gtOp.gtOp1->IsCnsIntOrI())
14005 // If the other arg is an int constant, and is a "not-a-field", choose
14006 // that as the multiplier, thus preserving constant index offsets...
14007 if (gtOp.gtOp2->OperGet() == GT_CNS_INT && gtOp.gtOp2->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField())
14009 subMul = gtOp.gtOp2->gtIntConCommon.IconValue();
14010 nonConst = gtOp.gtOp1;
14014 subMul = gtOp.gtOp1->gtIntConCommon.IconValue();
14015 nonConst = gtOp.gtOp2;
14018 else if (gtOp.gtOp2->IsCnsIntOrI())
14020 subMul = gtOp.gtOp2->gtIntConCommon.IconValue();
14021 nonConst = gtOp.gtOp1;
14023 if (nonConst != NULL)
14025 nonConst->ParseArrayAddressWork(comp, inputMul * subMul, pArr, pInxVN, pOffset, pFldSeq);
14028 // Otherwise, exit the switch, treat as a contribution to the index.
14033 // If one op is a constant, continue parsing down.
14034 if (gtOp.gtOp2->IsCnsIntOrI())
14036 ssize_t subMul = 1 << gtOp.gtOp2->gtIntConCommon.IconValue();
14037 gtOp.gtOp1->ParseArrayAddressWork(comp, inputMul * subMul, pArr, pInxVN, pOffset, pFldSeq);
14040 // Otherwise, exit the switch, treat as a contribution to the index.
14046 // If we didn't return above, must be a constribution to the non-constant part of the index VN.
14047 ValueNum vn = comp->GetValueNumStore()->VNNormVal(gtVNPair.GetLiberal()); // We don't care about exceptions for this purpose.
14050 ValueNum mulVN = comp->GetValueNumStore()->VNForLongCon(inputMul);
14051 vn = comp->GetValueNumStore()->VNForFunc(TypeGet(), GetVNFuncForOper(GT_MUL, false), mulVN, vn);
14053 if (*pInxVN == ValueNumStore::NoVN)
14059 *pInxVN = comp->GetValueNumStore()->VNForFunc(TypeGet(), GetVNFuncForOper(GT_ADD, false), *pInxVN, vn);
14064 bool GenTree::ParseArrayElemForm(Compiler* comp, ArrayInfo* arrayInfo, FieldSeqNode** pFldSeq)
14068 if (gtFlags & GTF_IND_ARR_INDEX)
14070 bool b = comp->GetArrayInfoMap()->Lookup(this, arrayInfo);
14076 GenTreePtr addr = AsIndir()->Addr();
14077 return addr->ParseArrayElemAddrForm(comp, arrayInfo, pFldSeq);
14085 bool GenTree::ParseArrayElemAddrForm(Compiler* comp, ArrayInfo* arrayInfo, FieldSeqNode** pFldSeq)
14091 GenTreePtr arrAddr = nullptr;
14092 GenTreePtr offset = nullptr;
14093 if (gtOp.gtOp1->TypeGet() == TYP_BYREF)
14095 arrAddr = gtOp.gtOp1;
14096 offset = gtOp.gtOp2;
14098 else if (gtOp.gtOp2->TypeGet() == TYP_BYREF)
14100 arrAddr = gtOp.gtOp2;
14101 offset = gtOp.gtOp1;
14107 if (!offset->ParseOffsetForm(comp, pFldSeq)) return false;
14108 return arrAddr->ParseArrayElemAddrForm(comp, arrayInfo, pFldSeq);
14114 GenTreePtr addrArg = gtOp.gtOp1;
14115 if (addrArg->OperGet() != GT_IND)
14121 // The "Addr" node might be annotated with a zero-offset field sequence.
14122 FieldSeqNode* zeroOffsetFldSeq = nullptr;
14123 if (comp->GetZeroOffsetFieldMap()->Lookup(this, &zeroOffsetFldSeq))
14125 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, zeroOffsetFldSeq);
14127 return addrArg->ParseArrayElemForm(comp, arrayInfo, pFldSeq);
14136 bool GenTree::ParseOffsetForm(Compiler* comp, FieldSeqNode** pFldSeq)
14142 GenTreeIntCon* icon = AsIntCon();
14143 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, icon->gtFieldSeq);
14148 if (!gtOp.gtOp1->ParseOffsetForm(comp, pFldSeq)) return false;
14149 return gtOp.gtOp2->ParseOffsetForm(comp, pFldSeq);
14156 void GenTree::LabelIndex(Compiler* comp, bool isConst)
14161 // If we got here, this is a contribution to the constant part of the index.
14163 gtIntCon.gtFieldSeq = comp->GetFieldSeqStore()->CreateSingleton(FieldSeqStore::ConstantIndexPseudoField);
14167 gtFlags |= GTF_VAR_ARR_INDEX;
14172 gtOp.gtOp1->LabelIndex(comp, isConst);
14173 gtOp.gtOp2->LabelIndex(comp, isConst);
14177 gtOp.gtOp1->LabelIndex(comp, isConst);
14181 // For all other operators, peel off one constant; and then label the other if it's also a constant.
14182 if (OperIsArithmetic() || OperIsCompare())
14184 if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
14186 gtOp.gtOp1->LabelIndex(comp, isConst);
14189 else if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
14191 gtOp.gtOp2->LabelIndex(comp, isConst);
14194 // Otherwise continue downward on both, labeling vars.
14195 gtOp.gtOp1->LabelIndex(comp, false);
14196 gtOp.gtOp2->LabelIndex(comp, false);
14203 FieldSeqNode FieldSeqStore::s_notAField(NULL, NULL); // Value doesn't matter; exists only to provide a distinguished address.
14205 // FieldSeqStore methods.
14206 FieldSeqStore::FieldSeqStore(IAllocator* alloc) : m_alloc(alloc), m_canonMap(new (alloc) FieldSeqNodeCanonMap(alloc))
14209 FieldSeqNode* FieldSeqStore::CreateSingleton(CORINFO_FIELD_HANDLE fieldHnd)
14211 FieldSeqNode fsn(fieldHnd, NULL);
14212 FieldSeqNode* res = NULL;
14213 if (m_canonMap->Lookup(fsn, &res))
14219 res = reinterpret_cast<FieldSeqNode*>(m_alloc->Alloc(sizeof(FieldSeqNode)));
14221 m_canonMap->Set(fsn, res);
14226 FieldSeqNode* FieldSeqStore::Append(FieldSeqNode* a, FieldSeqNode* b)
14230 else if (a == NotAField())
14231 return NotAField();
14232 else if (b == NULL)
14234 else if (b == NotAField())
14235 return NotAField();
14236 // Extremely special case for ConstantIndex pseudo-fields -- appending consecutive such
14237 // together collapse to one.
14238 else if ( a->m_next == nullptr
14239 && a->m_fieldHnd == ConstantIndexPseudoField
14240 && b->m_fieldHnd == ConstantIndexPseudoField)
14246 FieldSeqNode* tmp = Append(a->m_next, b);
14247 FieldSeqNode fsn(a->m_fieldHnd, tmp);
14248 FieldSeqNode* res = NULL;
14249 if (m_canonMap->Lookup(fsn, &res))
14255 res = reinterpret_cast<FieldSeqNode*>(m_alloc->Alloc(sizeof(FieldSeqNode)));
14257 m_canonMap->Set(fsn, res);
14264 int FieldSeqStore::FirstElemPseudoFieldStruct;
14265 int FieldSeqStore::ConstantIndexPseudoFieldStruct;
14267 CORINFO_FIELD_HANDLE FieldSeqStore::FirstElemPseudoField = (CORINFO_FIELD_HANDLE)&FieldSeqStore::FirstElemPseudoFieldStruct;
14268 CORINFO_FIELD_HANDLE FieldSeqStore::ConstantIndexPseudoField = (CORINFO_FIELD_HANDLE)&FieldSeqStore::ConstantIndexPseudoFieldStruct;
14270 bool FieldSeqNode::IsFirstElemFieldSeq()
14272 // this must be non-null per ISO C++
14273 return m_fieldHnd == FieldSeqStore::FirstElemPseudoField;
14276 bool FieldSeqNode::IsConstantIndexFieldSeq()
14278 // this must be non-null per ISO C++
14279 return m_fieldHnd == FieldSeqStore::ConstantIndexPseudoField;
14282 bool FieldSeqNode::IsPseudoField()
14284 if (this == nullptr)
14286 return m_fieldHnd == FieldSeqStore::FirstElemPseudoField || m_fieldHnd == FieldSeqStore::ConstantIndexPseudoField;
14289 #ifdef FEATURE_SIMD
14290 GenTreeSIMD* Compiler::gtNewSIMDNode(var_types type, GenTreePtr op1, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size)
14292 assert(op1 != nullptr);
14293 if (op1->OperGet() == GT_LCL_VAR)
14295 unsigned lclNum = op1->AsLclVarCommon()->GetLclNum();
14296 LclVarDsc* lclVarDsc = &lvaTable[lclNum];
14297 lclVarDsc->lvUsedInSIMDIntrinsic = true;
14300 return new (this, GT_SIMD) GenTreeSIMD(type, op1, simdIntrinsicID, baseType, size);
14303 GenTreeSIMD* Compiler::gtNewSIMDNode(var_types type, GenTreePtr op1, GenTreePtr op2, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size)
14305 assert(op1 != nullptr);
14306 if (op1->OperIsLocal())
14308 unsigned lclNum = op1->AsLclVarCommon()->GetLclNum();
14309 LclVarDsc* lclVarDsc = &lvaTable[lclNum];
14310 lclVarDsc->lvUsedInSIMDIntrinsic = true;
14313 if (op2 != nullptr && op2->OperIsLocal())
14315 unsigned lclNum = op2->AsLclVarCommon()->GetLclNum();
14316 LclVarDsc* lclVarDsc = &lvaTable[lclNum];
14317 lclVarDsc->lvUsedInSIMDIntrinsic = true;
14320 return new (this, GT_SIMD) GenTreeSIMD(type, op1, op2, simdIntrinsicID, baseType, size);
14323 bool GenTree::isCommutativeSIMDIntrinsic()
14325 assert(gtOper == GT_SIMD);
14326 switch (AsSIMD()->gtSIMDIntrinsicID)
14328 case SIMDIntrinsicAdd:
14329 case SIMDIntrinsicBitwiseAnd:
14330 case SIMDIntrinsicBitwiseOr:
14331 case SIMDIntrinsicBitwiseXor:
14332 case SIMDIntrinsicEqual:
14333 case SIMDIntrinsicMax:
14334 case SIMDIntrinsicMin:
14335 case SIMDIntrinsicMul:
14336 case SIMDIntrinsicOpEquality:
14337 case SIMDIntrinsicOpInEquality:
14343 #endif //FEATURE_SIMD
14345 //-------------------------------------------------------------------------
14346 // Initialize: Return Type Descriptor given type handle.
14349 // comp - Compiler Instance
14350 // retClsHnd - VM handle to the type returned
14355 void ReturnTypeDesc::InitializeReturnType(Compiler* comp, CORINFO_CLASS_HANDLE retClsHnd)
14359 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
14360 assert(retClsHnd != NO_CLASS_HANDLE);
14362 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
14363 comp->eeGetSystemVAmd64PassStructInRegisterDescriptor(retClsHnd, &structDesc);
14365 if (structDesc.passedInRegisters)
14367 for (int i=0; i<structDesc.eightByteCount; i++)
14369 assert(i < MAX_RET_REG_COUNT);
14370 m_regType[i] = comp->GetEightByteType(structDesc, i);
14374 #elif defined(_TARGET_X86_)
14375 // TODO-X86: Assumes we are only using ReturnTypeDesc for longs on x86.
14376 // Will need to be updated in the future to handle other return types
14377 assert(MAX_RET_REG_COUNT == 2);
14378 m_regType[0] = TYP_INT;
14379 m_regType[1] = TYP_INT;
14380 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
14387 //-------------------------------------------------------------------
14388 // GetABIReturnReg: Return ith return register as per target ABI
14391 // idx - Index of the return register.
14392 // The first return register has an index of 0 and so on.
14395 // Returns ith return register as per target ABI.
14398 // Right now this is implemented only for x64 Unix
14399 // and yet to be implemented for other multi-reg return
14400 // targets (Arm64/Arm32/x86).
14402 // TODO-ARM: Implement this routine to support HFA returns.
14403 // TODO-ARM64: Implement this routine to support HFA returns.
14404 // TODO-X86: Implement this routine to support long returns.
14405 regNumber ReturnTypeDesc::GetABIReturnReg(unsigned idx)
14407 unsigned count = GetReturnRegCount();
14408 assert(idx < count);
14410 regNumber resultReg = REG_NA;
14412 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
14413 var_types regType0 = GetReturnRegType(0);
14417 if (varTypeIsIntegralOrI(regType0))
14419 resultReg = REG_INTRET;
14422 noway_assert(varTypeIsFloating(regType0));
14423 resultReg = REG_FLOATRET;
14428 var_types regType1 = GetReturnRegType(1);
14430 if (varTypeIsIntegralOrI(regType1))
14432 if (varTypeIsIntegralOrI(regType0))
14434 resultReg = REG_INTRET_1;
14438 resultReg = REG_INTRET;
14443 noway_assert(varTypeIsFloating(regType1));
14445 if (varTypeIsFloating(regType0))
14447 resultReg = REG_FLOATRET_1;
14451 resultReg = REG_FLOATRET;
14456 #elif defined(_TARGET_X86_)
14459 resultReg = REG_LNGRET_LO;
14463 resultReg = REG_LNGRET_HI;
14465 #endif //FEATURE_UNIX_AMD64_STRUCT_PASSING
14467 assert(resultReg != REG_NA);
14471 //--------------------------------------------------------------------------------
14472 // GetABIReturnRegs: get the mask of return registers as per target arch ABI.
14478 // reg mask of return registers in which the return type is returned.
14481 // For now this is implemented only for x64 Unix and yet to be implemented
14482 // for other multi-reg return targets (Arm64/Arm32x86).
14484 // This routine can be used when the caller is not particular about the order
14485 // of return registers and wants to know the set of return registers.
14487 // TODO-ARM: Implement this routine to support HFA returns.
14488 // TODO-ARM64: Implement this routine to support HFA returns.
14489 // TODO-X86: Implement this routine to support long returns.
14492 regMaskTP ReturnTypeDesc::GetABIReturnRegs()
14494 regMaskTP resultMask = RBM_NONE;
14496 unsigned count = GetReturnRegCount();
14497 for (unsigned i = 0; i < count; ++i)
14499 resultMask |= genRegMask(GetABIReturnReg(i));