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
15 #include "hwintrinsic.h"
22 /*****************************************************************************/
24 const unsigned short GenTree::gtOperKindTable[] = {
25 #define GTNODE(en, st, cm, ok) ok + GTK_COMMUTE *cm,
29 /*****************************************************************************
31 * The types of different GenTree nodes
38 //--------------------------------------------
40 // IndentStack: This struct is used, along with its related enums and strings,
41 // to control both the indendtation and the printing of arcs.
44 // The mode of printing is set in the Constructor, using its 'compiler' argument.
45 // Currently it only prints arcs when fgOrder == fgOrderLinear.
46 // The type of arc to print is specified by the IndentInfo enum, and is controlled
47 // by the caller of the Push() method.
63 // Sets of strings for different dumping options vert bot top mid dash embedded terminal error
64 static const char* emptyIndents[IndentCharCount] = { " ", " ", " ", " ", " ", "{", "", "?" };
65 static const char* asciiIndents[IndentCharCount] = { "|", "\\", "/", "+", "-", "{", "*", "?" };
66 static const char* unicodeIndents[IndentCharCount] = { "\xe2\x94\x82", "\xe2\x94\x94", "\xe2\x94\x8c", "\xe2\x94\x9c", "\xe2\x94\x80", "{", "\xe2\x96\x8c", "?" };
69 typedef ArrayStack<Compiler::IndentInfo> IndentInfoStack;
72 IndentInfoStack stack;
75 // Constructor for IndentStack. Uses 'compiler' to determine the mode of printing.
76 IndentStack(Compiler* compiler) : stack(compiler->getAllocator(CMK_DebugOnly))
78 if (compiler->asciiTrees)
80 indents = asciiIndents;
84 indents = unicodeIndents;
88 // Return the depth of the current indentation.
91 return stack.Height();
94 // Push a new indentation onto the stack, of the given type.
95 void Push(Compiler::IndentInfo info)
100 // Pop the most recent indentation type off the stack.
101 Compiler::IndentInfo Pop()
106 // Print the current indentation and arcs.
109 unsigned indentCount = Depth();
110 for (unsigned i = 0; i < indentCount; i++)
112 unsigned index = indentCount - 1 - i;
113 switch (stack.Index(index))
115 case Compiler::IndentInfo::IINone:
118 case Compiler::IndentInfo::IIEmbedded:
119 printf("%s ", indents[ICEmbedded]);
121 case Compiler::IndentInfo::IIArc:
124 printf("%s%s%s", indents[ICMiddle], indents[ICDash], indents[ICDash]);
128 printf("%s ", indents[ICVertical]);
131 case Compiler::IndentInfo::IIArcBottom:
132 printf("%s%s%s", indents[ICBottom], indents[ICDash], indents[ICDash]);
134 case Compiler::IndentInfo::IIArcTop:
135 printf("%s%s%s", indents[ICTop], indents[ICDash], indents[ICDash]);
137 case Compiler::IndentInfo::IIError:
138 printf("%s%s%s", indents[ICError], indents[ICDash], indents[ICDash]);
144 printf("%s", indents[ICTerminal]);
148 //------------------------------------------------------------------------
149 // printIndent: This is a static method which simply invokes the 'print'
150 // method on its 'indentStack' argument.
153 // indentStack - specifies the information for the indentation & arcs to be printed
156 // This method exists to localize the checking for the case where indentStack is null.
158 static void printIndent(IndentStack* indentStack)
160 if (indentStack == nullptr)
164 indentStack->print();
169 #if defined(DEBUG) || NODEBASH_STATS || MEASURE_NODE_SIZE || COUNT_AST_OPERS
171 static const char* opNames[] = {
172 #define GTNODE(en, st, cm, ok) #en,
176 const char* GenTree::OpName(genTreeOps op)
178 assert((unsigned)op < _countof(opNames));
185 #if MEASURE_NODE_SIZE && SMALL_TREE_NODES
187 static const char* opStructNames[] = {
188 #define GTNODE(en, st, cm, ok) #st,
192 const char* GenTree::OpStructName(genTreeOps op)
194 assert((unsigned)op < _countof(opStructNames));
196 return opStructNames[op];
201 /*****************************************************************************
203 * When 'SMALL_TREE_NODES' is enabled, we allocate tree nodes in 2 different
204 * sizes: 'TREE_NODE_SZ_SMALL' for most nodes and 'TREE_NODE_SZ_LARGE' for the
205 * few nodes (such as calls) that have more fields and take up a lot more space.
210 /* GT_COUNT'th oper is overloaded as 'undefined oper', so allocate storage for GT_COUNT'th oper also */
212 unsigned char GenTree::s_gtNodeSizes[GT_COUNT + 1];
214 #if NODEBASH_STATS || MEASURE_NODE_SIZE || COUNT_AST_OPERS
216 unsigned char GenTree::s_gtTrueSizes[GT_COUNT + 1]{
217 #define GTNODE(en, st, cm, ok) sizeof(st),
221 #endif // NODEBASH_STATS || MEASURE_NODE_SIZE || COUNT_AST_OPERS
224 LONG GenTree::s_gtNodeCounts[GT_COUNT + 1] = {0};
225 #endif // COUNT_AST_OPERS
228 void GenTree::InitNodeSize()
230 /* Set all sizes to 'small' first */
232 for (unsigned op = 0; op <= GT_COUNT; op++)
234 GenTree::s_gtNodeSizes[op] = TREE_NODE_SZ_SMALL;
237 // Now set all of the appropriate entries to 'large'
238 CLANG_FORMAT_COMMENT_ANCHOR;
241 #if defined(FEATURE_HFA) || defined(UNIX_AMD64_ABI)
242 // On ARM32, ARM64 and System V for struct returning
243 // there is code that does GT_ASG-tree.CopyObj call.
244 // CopyObj is a large node and the GT_ASG is small, which triggers an exception.
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(UNIX_AMD64_ABI)
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_INDEX_ADDR] = TREE_NODE_SZ_LARGE;
255 GenTree::s_gtNodeSizes[GT_ARR_BOUNDS_CHECK] = TREE_NODE_SZ_LARGE;
257 GenTree::s_gtNodeSizes[GT_SIMD_CHK] = TREE_NODE_SZ_LARGE;
258 #endif // FEATURE_SIMD
259 #ifdef FEATURE_HW_INTRINSICS
260 GenTree::s_gtNodeSizes[GT_HW_INTRINSIC_CHK] = TREE_NODE_SZ_LARGE;
261 #endif // FEATURE_HW_INTRINSICS
263 GenTree::s_gtNodeSizes[GT_ARR_ELEM] = TREE_NODE_SZ_LARGE;
264 GenTree::s_gtNodeSizes[GT_ARR_INDEX] = TREE_NODE_SZ_LARGE;
265 GenTree::s_gtNodeSizes[GT_ARR_OFFSET] = TREE_NODE_SZ_LARGE;
266 GenTree::s_gtNodeSizes[GT_RET_EXPR] = TREE_NODE_SZ_LARGE;
267 GenTree::s_gtNodeSizes[GT_OBJ] = TREE_NODE_SZ_LARGE;
268 GenTree::s_gtNodeSizes[GT_FIELD] = TREE_NODE_SZ_LARGE;
269 GenTree::s_gtNodeSizes[GT_STMT] = TREE_NODE_SZ_LARGE;
270 GenTree::s_gtNodeSizes[GT_CMPXCHG] = TREE_NODE_SZ_LARGE;
271 GenTree::s_gtNodeSizes[GT_QMARK] = TREE_NODE_SZ_LARGE;
272 GenTree::s_gtNodeSizes[GT_LEA] = TREE_NODE_SZ_LARGE;
273 GenTree::s_gtNodeSizes[GT_STORE_OBJ] = TREE_NODE_SZ_LARGE;
274 GenTree::s_gtNodeSizes[GT_DYN_BLK] = TREE_NODE_SZ_LARGE;
275 GenTree::s_gtNodeSizes[GT_STORE_DYN_BLK] = TREE_NODE_SZ_LARGE;
276 GenTree::s_gtNodeSizes[GT_INTRINSIC] = TREE_NODE_SZ_LARGE;
277 GenTree::s_gtNodeSizes[GT_ALLOCOBJ] = TREE_NODE_SZ_LARGE;
278 #if USE_HELPERS_FOR_INT_DIV
279 GenTree::s_gtNodeSizes[GT_DIV] = TREE_NODE_SZ_LARGE;
280 GenTree::s_gtNodeSizes[GT_UDIV] = TREE_NODE_SZ_LARGE;
281 GenTree::s_gtNodeSizes[GT_MOD] = TREE_NODE_SZ_LARGE;
282 GenTree::s_gtNodeSizes[GT_UMOD] = TREE_NODE_SZ_LARGE;
284 #ifdef FEATURE_PUT_STRUCT_ARG_STK
285 // TODO-Throughput: This should not need to be a large node. The object info should be
286 // obtained from the child node.
287 GenTree::s_gtNodeSizes[GT_PUTARG_STK] = TREE_NODE_SZ_LARGE;
288 #if FEATURE_ARG_SPLIT
289 GenTree::s_gtNodeSizes[GT_PUTARG_SPLIT] = TREE_NODE_SZ_LARGE;
290 #endif // FEATURE_ARG_SPLIT
291 #endif // FEATURE_PUT_STRUCT_ARG_STK
293 assert(GenTree::s_gtNodeSizes[GT_RETURN] == GenTree::s_gtNodeSizes[GT_ASG]);
295 // This list of assertions should come to contain all GenTree subtypes that are declared
297 assert(sizeof(GenTreeLclFld) <= GenTree::s_gtNodeSizes[GT_LCL_FLD]);
298 assert(sizeof(GenTreeLclVar) <= GenTree::s_gtNodeSizes[GT_LCL_VAR]);
300 static_assert_no_msg(sizeof(GenTree) <= TREE_NODE_SZ_SMALL);
301 static_assert_no_msg(sizeof(GenTreeUnOp) <= TREE_NODE_SZ_SMALL);
302 static_assert_no_msg(sizeof(GenTreeOp) <= TREE_NODE_SZ_SMALL);
303 static_assert_no_msg(sizeof(GenTreeVal) <= TREE_NODE_SZ_SMALL);
304 static_assert_no_msg(sizeof(GenTreeIntConCommon) <= TREE_NODE_SZ_SMALL);
305 static_assert_no_msg(sizeof(GenTreePhysReg) <= TREE_NODE_SZ_SMALL);
306 static_assert_no_msg(sizeof(GenTreeJumpTable) <= TREE_NODE_SZ_SMALL);
307 static_assert_no_msg(sizeof(GenTreeIntCon) <= TREE_NODE_SZ_SMALL);
308 static_assert_no_msg(sizeof(GenTreeLngCon) <= TREE_NODE_SZ_SMALL);
309 static_assert_no_msg(sizeof(GenTreeDblCon) <= TREE_NODE_SZ_SMALL);
310 static_assert_no_msg(sizeof(GenTreeStrCon) <= TREE_NODE_SZ_SMALL);
311 static_assert_no_msg(sizeof(GenTreeLclVarCommon) <= TREE_NODE_SZ_SMALL);
312 static_assert_no_msg(sizeof(GenTreeLclVar) <= TREE_NODE_SZ_SMALL);
313 static_assert_no_msg(sizeof(GenTreeLclFld) <= TREE_NODE_SZ_SMALL);
314 static_assert_no_msg(sizeof(GenTreeCC) <= TREE_NODE_SZ_SMALL);
315 static_assert_no_msg(sizeof(GenTreeCast) <= TREE_NODE_SZ_LARGE); // *** large node
316 static_assert_no_msg(sizeof(GenTreeBox) <= TREE_NODE_SZ_LARGE); // *** large node
317 static_assert_no_msg(sizeof(GenTreeField) <= TREE_NODE_SZ_LARGE); // *** large node
318 static_assert_no_msg(sizeof(GenTreeArgList) <= TREE_NODE_SZ_SMALL);
319 static_assert_no_msg(sizeof(GenTreeFieldList) <= TREE_NODE_SZ_SMALL);
320 static_assert_no_msg(sizeof(GenTreeColon) <= TREE_NODE_SZ_SMALL);
321 static_assert_no_msg(sizeof(GenTreeCall) <= TREE_NODE_SZ_LARGE); // *** large node
322 static_assert_no_msg(sizeof(GenTreeCmpXchg) <= TREE_NODE_SZ_LARGE); // *** large node
323 static_assert_no_msg(sizeof(GenTreeFptrVal) <= TREE_NODE_SZ_LARGE); // *** large node
324 static_assert_no_msg(sizeof(GenTreeQmark) <= TREE_NODE_SZ_LARGE); // *** large node
325 static_assert_no_msg(sizeof(GenTreeIntrinsic) <= TREE_NODE_SZ_LARGE); // *** large node
326 static_assert_no_msg(sizeof(GenTreeIndex) <= TREE_NODE_SZ_LARGE); // *** large node
327 static_assert_no_msg(sizeof(GenTreeArrLen) <= TREE_NODE_SZ_LARGE); // *** large node
328 static_assert_no_msg(sizeof(GenTreeBoundsChk) <= TREE_NODE_SZ_LARGE); // *** large node
329 static_assert_no_msg(sizeof(GenTreeArrElem) <= TREE_NODE_SZ_LARGE); // *** large node
330 static_assert_no_msg(sizeof(GenTreeArrIndex) <= TREE_NODE_SZ_LARGE); // *** large node
331 static_assert_no_msg(sizeof(GenTreeArrOffs) <= TREE_NODE_SZ_LARGE); // *** large node
332 static_assert_no_msg(sizeof(GenTreeIndir) <= TREE_NODE_SZ_SMALL);
333 static_assert_no_msg(sizeof(GenTreeStoreInd) <= TREE_NODE_SZ_SMALL);
334 static_assert_no_msg(sizeof(GenTreeAddrMode) <= TREE_NODE_SZ_SMALL);
335 static_assert_no_msg(sizeof(GenTreeObj) <= TREE_NODE_SZ_LARGE); // *** large node
336 static_assert_no_msg(sizeof(GenTreeBlk) <= TREE_NODE_SZ_SMALL);
337 static_assert_no_msg(sizeof(GenTreeRetExpr) <= TREE_NODE_SZ_LARGE); // *** large node
338 static_assert_no_msg(sizeof(GenTreeStmt) <= TREE_NODE_SZ_LARGE); // *** large node
339 static_assert_no_msg(sizeof(GenTreeClsVar) <= TREE_NODE_SZ_SMALL);
340 static_assert_no_msg(sizeof(GenTreeArgPlace) <= TREE_NODE_SZ_SMALL);
341 static_assert_no_msg(sizeof(GenTreeLabel) <= TREE_NODE_SZ_SMALL);
342 static_assert_no_msg(sizeof(GenTreePhiArg) <= TREE_NODE_SZ_SMALL);
343 static_assert_no_msg(sizeof(GenTreeAllocObj) <= TREE_NODE_SZ_LARGE); // *** large node
344 #ifndef FEATURE_PUT_STRUCT_ARG_STK
345 static_assert_no_msg(sizeof(GenTreePutArgStk) <= TREE_NODE_SZ_SMALL);
346 #else // FEATURE_PUT_STRUCT_ARG_STK
347 // TODO-Throughput: This should not need to be a large node. The object info should be
348 // obtained from the child node.
349 static_assert_no_msg(sizeof(GenTreePutArgStk) <= TREE_NODE_SZ_LARGE);
350 #if FEATURE_ARG_SPLIT
351 static_assert_no_msg(sizeof(GenTreePutArgSplit) <= TREE_NODE_SZ_LARGE);
352 #endif // FEATURE_ARG_SPLIT
353 #endif // FEATURE_PUT_STRUCT_ARG_STK
356 static_assert_no_msg(sizeof(GenTreeSIMD) <= TREE_NODE_SZ_SMALL);
357 #endif // FEATURE_SIMD
359 #ifdef FEATURE_HW_INTRINSICS
360 static_assert_no_msg(sizeof(GenTreeHWIntrinsic) <= TREE_NODE_SZ_SMALL);
361 #endif // FEATURE_HW_INTRINSICS
365 size_t GenTree::GetNodeSize() const
367 return GenTree::s_gtNodeSizes[gtOper];
371 bool GenTree::IsNodeProperlySized() const
375 if (gtDebugFlags & GTF_DEBUG_NODE_SMALL)
377 size = TREE_NODE_SZ_SMALL;
381 assert(gtDebugFlags & GTF_DEBUG_NODE_LARGE);
382 size = TREE_NODE_SZ_LARGE;
385 return GenTree::s_gtNodeSizes[gtOper] <= size;
390 //------------------------------------------------------------------------
391 // ReplaceWith: replace this with the src node. The source must be an isolated node
392 // and cannot be used after the replacement.
395 // src - source tree, that replaces this.
396 // comp - the compiler instance to transfer annotations for arrays.
398 void GenTree::ReplaceWith(GenTree* src, Compiler* comp)
400 // The source may be big only if the target is also a big node
401 assert((gtDebugFlags & GTF_DEBUG_NODE_LARGE) || GenTree::s_gtNodeSizes[src->gtOper] == TREE_NODE_SZ_SMALL);
403 // The check is effective only if nodes have been already threaded.
404 assert((src->gtPrev == nullptr) && (src->gtNext == nullptr));
406 RecordOperBashing(OperGet(), src->OperGet()); // nop unless NODEBASH_STATS is enabled
408 GenTree* prev = gtPrev;
409 GenTree* next = gtNext;
410 // The VTable pointer is copied intentionally here
411 memcpy((void*)this, (void*)src, src->GetNodeSize());
418 // Transfer any annotations.
419 if (src->OperGet() == GT_IND && src->gtFlags & GTF_IND_ARR_INDEX)
422 bool b = comp->GetArrayInfoMap()->Lookup(src, &arrInfo);
424 comp->GetArrayInfoMap()->Set(this, arrInfo);
426 DEBUG_DESTROY_NODE(src);
431 /*****************************************************************************
433 * When 'NODEBASH_STATS' is enabled in "jit.h" we record all instances of
434 * an existing GenTree node having its operator changed. This can be useful
435 * for two (related) things - to see what is being bashed (and what isn't),
436 * and to verify that the existing choices for what nodes are marked 'large'
437 * are reasonable (to minimize "wasted" space).
439 * And yes, the hash function / logic is simplistic, but it is conflict-free
440 * and transparent for what we need.
445 #define BASH_HASH_SIZE 211
447 inline unsigned hashme(genTreeOps op1, genTreeOps op2)
449 return ((op1 * 104729) ^ (op2 * 56569)) % BASH_HASH_SIZE;
454 unsigned __int32 bhFullHash; // the hash value (unique for all old->new pairs)
455 unsigned __int32 bhCount; // the same old->new bashings seen so far
456 unsigned __int8 bhOperOld; // original gtOper
457 unsigned __int8 bhOperNew; // new gtOper
460 static BashHashDsc BashHash[BASH_HASH_SIZE];
462 void GenTree::RecordOperBashing(genTreeOps operOld, genTreeOps operNew)
464 unsigned hash = hashme(operOld, operNew);
465 BashHashDsc* desc = BashHash + hash;
467 if (desc->bhFullHash != hash)
469 noway_assert(desc->bhCount == 0); // if this ever fires, need fix the hash fn
470 desc->bhFullHash = hash;
474 desc->bhOperOld = operOld;
475 desc->bhOperNew = operNew;
478 void GenTree::ReportOperBashing(FILE* f)
485 fprintf(f, "Bashed gtOper stats:\n");
487 fprintf(f, " Old operator New operator #bytes old->new Count\n");
488 fprintf(f, " ---------------------------------------------------------------\n");
490 for (unsigned h = 0; h < BASH_HASH_SIZE; h++)
492 unsigned count = BashHash[h].bhCount;
496 unsigned opOld = BashHash[h].bhOperOld;
497 unsigned opNew = BashHash[h].bhOperNew;
499 fprintf(f, " GT_%-13s -> GT_%-13s [size: %3u->%3u] %c %7u\n", OpName((genTreeOps)opOld),
500 OpName((genTreeOps)opNew), s_gtTrueSizes[opOld], s_gtTrueSizes[opNew],
501 (s_gtTrueSizes[opOld] < s_gtTrueSizes[opNew]) ? 'X' : ' ', count);
505 fprintf(f, "Total bashings: %u\n", total);
511 #endif // NODEBASH_STATS
513 #else // SMALL_TREE_NODES
516 bool GenTree::IsNodeProperlySized() const
522 #endif // SMALL_TREE_NODES
524 /*****************************************************************************/
526 #if MEASURE_NODE_SIZE
528 void GenTree::DumpNodeSizes(FILE* fp)
530 // Dump the sizes of the various GenTree flavors
533 fprintf(fp, "Small tree node size = %3u bytes\n", TREE_NODE_SZ_SMALL);
535 fprintf(fp, "Large tree node size = %3u bytes\n", TREE_NODE_SZ_LARGE);
540 // Verify that node sizes are set kosherly and dump sizes
541 for (unsigned op = GT_NONE + 1; op < GT_COUNT; op++)
543 unsigned needSize = s_gtTrueSizes[op];
544 unsigned nodeSize = s_gtNodeSizes[op];
546 const char* structNm = OpStructName((genTreeOps)op);
547 const char* operName = OpName((genTreeOps)op);
549 bool repeated = false;
551 // Have we seen this struct flavor before?
552 for (unsigned mop = GT_NONE + 1; mop < op; mop++)
554 if (strcmp(structNm, OpStructName((genTreeOps)mop)) == 0)
561 // Don't repeat the same GenTree flavor unless we have an error
562 if (!repeated || needSize > nodeSize)
564 unsigned sizeChar = '?';
566 if (nodeSize == TREE_NODE_SZ_SMALL)
568 else if (nodeSize == TREE_NODE_SZ_LARGE)
571 fprintf(fp, "GT_%-16s ... %-19s = %3u bytes (%c)", operName, structNm, needSize, sizeChar);
572 if (needSize > nodeSize)
574 fprintf(fp, " -- ERROR -- allocation is only %u bytes!", nodeSize);
576 else if (needSize <= TREE_NODE_SZ_SMALL && nodeSize == TREE_NODE_SZ_LARGE)
578 fprintf(fp, " ... could be small");
588 #endif // MEASURE_NODE_SIZE
590 /*****************************************************************************
592 * Walk all basic blocks and call the given function pointer for all tree
593 * nodes contained therein.
596 void Compiler::fgWalkAllTreesPre(fgWalkPreFn* visitor, void* pCallBackData)
600 for (block = fgFirstBB; block; block = block->bbNext)
604 for (tree = block->bbTreeList; tree; tree = tree->gtNext)
606 assert(tree->gtOper == GT_STMT);
608 fgWalkTreePre(&tree->gtStmt.gtStmtExpr, visitor, pCallBackData);
613 //-----------------------------------------------------------
614 // CopyReg: Copy the _gtRegNum/gtRegTag fields.
617 // from - GenTree node from which to copy
621 void GenTree::CopyReg(GenTree* from)
623 _gtRegNum = from->_gtRegNum;
624 INDEBUG(gtRegTag = from->gtRegTag;)
626 // Also copy multi-reg state if this is a call node
629 assert(from->IsCall());
630 this->AsCall()->CopyOtherRegs(from->AsCall());
632 else if (IsCopyOrReload())
634 this->AsCopyOrReload()->CopyOtherRegs(from->AsCopyOrReload());
638 //------------------------------------------------------------------
639 // gtHasReg: Whether node beeen assigned a register by LSRA
645 // Returns true if the node was assigned a register.
647 // In case of multi-reg call nodes, it is considered
648 // having a reg if regs are allocated for all its
651 // In case of GT_COPY or GT_RELOAD of a multi-reg call,
652 // GT_COPY/GT_RELOAD is considered having a reg if it
653 // has a reg assigned to any of its positions.
656 // In order for this to work properly, gtClearReg must be called
657 // prior to setting the register value.
659 bool GenTree::gtHasReg() const
663 if (IsMultiRegCall())
665 // Have to cast away const-ness because GetReturnTypeDesc() is a non-const method
666 GenTree* tree = const_cast<GenTree*>(this);
667 GenTreeCall* call = tree->AsCall();
668 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
671 // A Multi-reg call node is said to have regs, if it has
672 // reg assigned to each of its result registers.
673 for (unsigned i = 0; i < regCount; ++i)
675 hasReg = (call->GetRegNumByIdx(i) != REG_NA);
682 else if (IsCopyOrReloadOfMultiRegCall())
684 GenTree* tree = const_cast<GenTree*>(this);
685 GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
686 GenTreeCall* call = copyOrReload->gtGetOp1()->AsCall();
687 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
690 // A Multi-reg copy or reload node is said to have regs,
691 // if it has valid regs in any of the positions.
692 for (unsigned i = 0; i < regCount; ++i)
694 hasReg = (copyOrReload->GetRegNumByIdx(i) != REG_NA);
703 hasReg = (gtRegNum != REG_NA);
709 //-----------------------------------------------------------------------------
710 // GetRegisterDstCount: Get the number of registers defined by the node.
716 // The number of registers that this node defines.
719 // This should not be called on a contained node.
720 // This does not look at the actual register assignments, if any, and so
721 // is valid after Lowering.
723 int GenTree::GetRegisterDstCount() const
725 assert(!isContained());
726 if (!IsMultiRegNode())
728 return (IsValue()) ? 1 : 0;
730 else if (IsMultiRegCall())
732 // temporarily cast away const-ness as AsCall() method is not declared const
733 GenTree* temp = const_cast<GenTree*>(this);
734 return temp->AsCall()->GetReturnTypeDesc()->GetReturnRegCount();
736 else if (IsCopyOrReload())
738 return gtGetOp1()->GetRegisterDstCount();
740 #if FEATURE_ARG_SPLIT
741 else if (OperIsPutArgSplit())
743 return (const_cast<GenTree*>(this))->AsPutArgSplit()->gtNumRegs;
746 #if !defined(_TARGET_64BIT_)
747 else if (OperIsMultiRegOp())
749 // A MultiRegOp is a GT_MUL_LONG, GT_PUTARG_REG, or GT_BITCAST.
750 // For the latter two (ARM-only), they only have multiple registers if they produce a long value
751 // (GT_MUL_LONG always produces a long value).
752 CLANG_FORMAT_COMMENT_ANCHOR;
754 return (TypeGet() == TYP_LONG) ? 2 : 1;
756 assert(OperIs(GT_MUL_LONG));
761 assert(!"Unexpected multi-reg node");
765 //---------------------------------------------------------------
766 // gtGetRegMask: Get the reg mask of the node.
772 // Reg Mask of GenTree node.
774 regMaskTP GenTree::gtGetRegMask() const
776 regMaskTP resultMask;
778 if (IsMultiRegCall())
780 // temporarily cast away const-ness as AsCall() method is not declared const
781 resultMask = genRegMask(gtRegNum);
782 GenTree* temp = const_cast<GenTree*>(this);
783 resultMask |= temp->AsCall()->GetOtherRegMask();
785 else if (IsCopyOrReloadOfMultiRegCall())
787 // A multi-reg copy or reload, will have valid regs for only those
788 // positions that need to be copied or reloaded. Hence we need
789 // to consider only those registers for computing reg mask.
791 GenTree* tree = const_cast<GenTree*>(this);
792 GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
793 GenTreeCall* call = copyOrReload->gtGetOp1()->AsCall();
794 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
796 resultMask = RBM_NONE;
797 for (unsigned i = 0; i < regCount; ++i)
799 regNumber reg = copyOrReload->GetRegNumByIdx(i);
802 resultMask |= genRegMask(reg);
806 #if FEATURE_ARG_SPLIT
807 else if (OperIsPutArgSplit())
809 GenTree* tree = const_cast<GenTree*>(this);
810 GenTreePutArgSplit* splitArg = tree->AsPutArgSplit();
811 unsigned regCount = splitArg->gtNumRegs;
813 resultMask = RBM_NONE;
814 for (unsigned i = 0; i < regCount; ++i)
816 regNumber reg = splitArg->GetRegNumByIdx(i);
817 assert(reg != REG_NA);
818 resultMask |= genRegMask(reg);
821 #endif // FEATURE_ARG_SPLIT
824 resultMask = genRegMask(gtRegNum);
830 //---------------------------------------------------------------
831 // GetOtherRegMask: Get the reg mask of gtOtherRegs of call node
837 // Reg mask of gtOtherRegs of call node.
839 regMaskTP GenTreeCall::GetOtherRegMask() const
841 regMaskTP resultMask = RBM_NONE;
843 #if FEATURE_MULTIREG_RET
844 for (unsigned i = 0; i < MAX_RET_REG_COUNT - 1; ++i)
846 if (gtOtherRegs[i] != REG_NA)
848 resultMask |= genRegMask((regNumber)gtOtherRegs[i]);
858 //-------------------------------------------------------------------------
860 // Returns true if this call is pure. For now, this uses the same
861 // definition of "pure" that is that used by HelperCallProperties: a
862 // pure call does not read or write any aliased (e.g. heap) memory or
863 // have other global side effects (e.g. class constructors, finalizers),
864 // but is allowed to throw an exception.
866 // NOTE: this call currently only returns true if the call target is a
867 // helper method that is known to be pure. No other analysis is
871 // Copiler - the compiler context.
874 // True if the call is pure; false otherwise.
876 bool GenTreeCall::IsPure(Compiler* compiler) const
878 return (gtCallType == CT_HELPER) &&
879 compiler->s_helperCallProperties.IsPure(compiler->eeGetHelperNum(gtCallMethHnd));
882 //-------------------------------------------------------------------------
884 // Returns true if this call has any side effects. All non-helpers are considered to have side-effects. Only helpers
885 // that do not mutate the heap, do not run constructors, may not throw, and are either a) pure or b) non-finalizing
886 // allocation functions are considered side-effect-free.
889 // compiler - the compiler instance
890 // ignoreExceptions - when `true`, ignores exception side effects
891 // ignoreCctors - when `true`, ignores class constructor side effects
894 // true if this call has any side-effects; false otherwise.
895 bool GenTreeCall::HasSideEffects(Compiler* compiler, bool ignoreExceptions, bool ignoreCctors) const
897 // Generally all GT_CALL nodes are considered to have side-effects, but we may have extra information about helper
898 // calls that can prove them side-effect-free.
899 if (gtCallType != CT_HELPER)
904 CorInfoHelpFunc helper = compiler->eeGetHelperNum(gtCallMethHnd);
905 HelperCallProperties& helperProperties = compiler->s_helperCallProperties;
907 // We definitely care about the side effects if MutatesHeap is true
908 if (helperProperties.MutatesHeap(helper))
913 // Unless we have been instructed to ignore cctors (CSE, for example, ignores cctors), consider them side effects.
914 if (!ignoreCctors && helperProperties.MayRunCctor(helper))
919 // If we also care about exceptions then check if the helper can throw
920 if (!ignoreExceptions && !helperProperties.NoThrow(helper))
925 // If this is not a Pure helper call or an allocator (that will not need to run a finalizer)
926 // then this call has side effects.
927 return !helperProperties.IsPure(helper) &&
928 (!helperProperties.IsAllocator(helper) || helperProperties.MayFinalize(helper));
931 //-------------------------------------------------------------------------
932 // HasNonStandardAddedArgs: Return true if the method has non-standard args added to the call
933 // argument list during argument morphing (fgMorphArgs), e.g., passed in R10 or R11 on AMD64.
934 // See also GetNonStandardAddedArgCount().
937 // compiler - the compiler instance
940 // true if there are any such args, false otherwise.
942 bool GenTreeCall::HasNonStandardAddedArgs(Compiler* compiler) const
944 return GetNonStandardAddedArgCount(compiler) != 0;
947 //-------------------------------------------------------------------------
948 // GetNonStandardAddedArgCount: Get the count of non-standard arguments that have been added
949 // during call argument morphing (fgMorphArgs). Do not count non-standard args that are already
950 // counted in the argument list prior to morphing.
952 // This function is used to help map the caller and callee arguments during tail call setup.
955 // compiler - the compiler instance
958 // The count of args, as described.
961 // It would be more general to have fgMorphArgs set a bit on the call node when such
962 // args are added to a call, and a bit on each such arg, and then have this code loop
963 // over the call args when the special call bit is set, counting the args with the special
964 // arg bit. This seems pretty heavyweight, though. Instead, this logic needs to be kept
965 // in sync with fgMorphArgs.
967 int GenTreeCall::GetNonStandardAddedArgCount(Compiler* compiler) const
969 if (IsUnmanaged() && !compiler->opts.ShouldUsePInvokeHelpers())
971 // R11 = PInvoke cookie param
974 else if (IsVirtualStub())
976 // R11 = Virtual stub param
979 else if ((gtCallType == CT_INDIRECT) && (gtCallCookie != nullptr))
981 // R10 = PInvoke target param
982 // R11 = PInvoke cookie param
988 //-------------------------------------------------------------------------
989 // TreatAsHasRetBufArg:
992 // compiler, the compiler instance so that we can call eeGetHelperNum
995 // Returns true if we treat the call as if it has a retBuf argument
996 // This method may actually have a retBuf argument
997 // or it could be a JIT helper that we are still transforming during
998 // the importer phase.
1001 // On ARM64 marking the method with the GTF_CALL_M_RETBUFFARG flag
1002 // will make HasRetBufArg() return true, but will also force the
1003 // use of register x8 to pass the RetBuf argument.
1005 // These two Jit Helpers that we handle here by returning true
1006 // aren't actually defined to return a struct, so they don't expect
1007 // their RetBuf to be passed in x8, instead they expect it in x0.
1009 bool GenTreeCall::TreatAsHasRetBufArg(Compiler* compiler) const
1017 // If we see a Jit helper call that returns a TYP_STRUCT we will
1018 // transform it as if it has a Return Buffer Argument
1020 if (IsHelperCall() && (gtReturnType == TYP_STRUCT))
1022 // There are two possible helper calls that use this path:
1023 // CORINFO_HELP_GETFIELDSTRUCT and CORINFO_HELP_UNBOX_NULLABLE
1025 CorInfoHelpFunc helpFunc = compiler->eeGetHelperNum(gtCallMethHnd);
1027 if (helpFunc == CORINFO_HELP_GETFIELDSTRUCT)
1031 else if (helpFunc == CORINFO_HELP_UNBOX_NULLABLE)
1037 assert(!"Unexpected JIT helper in TreatAsHasRetBufArg");
1044 //-------------------------------------------------------------------------
1045 // IsHelperCall: Determine if this GT_CALL node is a specific helper call.
1048 // compiler - the compiler instance so that we can call eeFindHelper
1051 // Returns true if this GT_CALL node is a call to the specified helper.
1053 bool GenTreeCall::IsHelperCall(Compiler* compiler, unsigned helper) const
1055 return IsHelperCall(compiler->eeFindHelper(helper));
1058 //------------------------------------------------------------------------
1059 // GenTreeCall::ReplaceCallOperand:
1060 // Replaces a given operand to a call node and updates the call
1061 // argument table if necessary.
1064 // useEdge - the use edge that points to the operand to be replaced.
1065 // replacement - the replacement node.
1067 void GenTreeCall::ReplaceCallOperand(GenTree** useEdge, GenTree* replacement)
1069 assert(useEdge != nullptr);
1070 assert(replacement != nullptr);
1071 assert(TryGetUse(*useEdge, &useEdge));
1073 GenTree* originalOperand = *useEdge;
1074 *useEdge = replacement;
1076 const bool isArgument =
1077 (replacement != gtControlExpr) &&
1078 ((gtCallType != CT_INDIRECT) || ((replacement != gtCallCookie) && (replacement != gtCallAddr)));
1082 if ((originalOperand->gtFlags & GTF_LATE_ARG) != 0)
1084 replacement->gtFlags |= GTF_LATE_ARG;
1088 assert((replacement->gtFlags & GTF_LATE_ARG) == 0);
1090 fgArgTabEntry* fp = Compiler::gtArgEntryByNode(this, originalOperand);
1091 assert(fp->node == originalOperand);
1092 fp->node = replacement;
1097 //-------------------------------------------------------------------------
1098 // AreArgsComplete: Determine if this GT_CALL node's arguments have been processed.
1101 // Returns true if fgMorphArgs has processed the arguments.
1103 bool GenTreeCall::AreArgsComplete() const
1105 if (fgArgInfo == nullptr)
1109 if (fgArgInfo->AreArgsComplete())
1111 assert((gtCallLateArgs != nullptr) || !fgArgInfo->HasRegArgs());
1114 assert(gtCallArgs == nullptr);
1118 #if !defined(FEATURE_PUT_STRUCT_ARG_STK)
1119 unsigned GenTreePutArgStk::getArgSize()
1121 return genTypeSize(genActualType(gtOp1->gtType));
1123 #endif // !defined(FEATURE_PUT_STRUCT_ARG_STK)
1125 /*****************************************************************************
1127 * Returns non-zero if the two trees are identical.
1130 bool GenTree::Compare(GenTree* op1, GenTree* op2, bool swapOK)
1135 // printf("tree1:\n"); gtDispTree(op1);
1136 // printf("tree2:\n"); gtDispTree(op2);
1142 return (op2 == nullptr);
1153 assert(op1->gtOper != GT_STMT);
1154 assert(op2->gtOper != GT_STMT);
1156 oper = op1->OperGet();
1158 /* The operators must be equal */
1160 if (oper != op2->gtOper)
1165 /* The types must be equal */
1167 if (op1->gtType != op2->gtType)
1172 /* Overflow must be equal */
1173 if (op1->gtOverflowEx() != op2->gtOverflowEx())
1178 /* Sensible flags must be equal */
1179 if ((op1->gtFlags & (GTF_UNSIGNED)) != (op2->gtFlags & (GTF_UNSIGNED)))
1184 /* Figure out what kind of nodes we're comparing */
1186 kind = op1->OperKind();
1188 /* Is this a constant node? */
1190 if (kind & GTK_CONST)
1195 if (op1->gtIntCon.gtIconVal == op2->gtIntCon.gtIconVal)
1201 // TODO-CQ: Enable this in the future
1203 if (op1->gtLngCon.gtLconVal == op2->gtLngCon.gtLconVal)
1208 if (op1->gtDblCon.gtDconVal == op2->gtDblCon.gtDconVal)
1219 /* Is this a leaf node? */
1221 if (kind & GTK_LEAF)
1226 if (op1->gtLclVarCommon.gtLclNum != op2->gtLclVarCommon.gtLclNum)
1234 if (op1->gtLclFld.gtLclNum != op2->gtLclFld.gtLclNum ||
1235 op1->gtLclFld.gtLclOffs != op2->gtLclFld.gtLclOffs)
1243 if (op1->gtClsVar.gtClsVarHnd != op2->gtClsVar.gtClsVarHnd)
1254 if ((op1->gtType == TYP_STRUCT) &&
1255 (op1->gtArgPlace.gtArgPlaceClsHnd != op2->gtArgPlace.gtArgPlaceClsHnd))
1268 /* Is it a 'simple' unary/binary operator? */
1270 if (kind & GTK_UNOP)
1274 // ExOp operators extend unary operator with extra, non-GenTree* members. In many cases,
1275 // these should be included in the comparison.
1279 if (op1->gtArrLen.ArrLenOffset() != op2->gtArrLen.ArrLenOffset())
1285 if (op1->gtCast.gtCastType != op2->gtCast.gtCastType)
1291 if (op1->AsObj()->gtClass != op2->AsObj()->gtClass)
1297 // For the ones below no extra argument matters for comparison.
1299 case GT_RUNTIMELOOKUP:
1303 assert(!"unexpected unary ExOp operator");
1306 return Compare(op1->gtOp.gtOp1, op2->gtOp.gtOp1);
1309 if (kind & GTK_BINOP)
1313 // ExOp operators extend unary operator with extra, non-GenTree* members. In many cases,
1314 // these should be included in the hash code.
1318 if (op1->gtIntrinsic.gtIntrinsicId != op2->gtIntrinsic.gtIntrinsicId)
1324 if (op1->gtAddrMode.gtScale != op2->gtAddrMode.gtScale)
1328 if (op1->gtAddrMode.Offset() != op2->gtAddrMode.Offset())
1334 if (op1->gtIndex.gtIndElemSize != op2->gtIndex.gtIndElemSize)
1340 if (op1->AsIndexAddr()->gtElemSize != op2->AsIndexAddr()->gtElemSize)
1347 if ((op1->AsSIMD()->gtSIMDIntrinsicID != op2->AsSIMD()->gtSIMDIntrinsicID) ||
1348 (op1->AsSIMD()->gtSIMDBaseType != op2->AsSIMD()->gtSIMDBaseType) ||
1349 (op1->AsSIMD()->gtSIMDSize != op2->AsSIMD()->gtSIMDSize))
1354 #endif // FEATURE_SIMD
1356 #ifdef FEATURE_HW_INTRINSICS
1357 case GT_HWIntrinsic:
1358 if ((op1->AsHWIntrinsic()->gtHWIntrinsicId != op2->AsHWIntrinsic()->gtHWIntrinsicId) ||
1359 (op1->AsHWIntrinsic()->gtSIMDBaseType != op2->AsHWIntrinsic()->gtSIMDBaseType) ||
1360 (op1->AsHWIntrinsic()->gtSIMDSize != op2->AsHWIntrinsic()->gtSIMDSize) ||
1361 (op1->AsHWIntrinsic()->gtIndexBaseType != op2->AsHWIntrinsic()->gtIndexBaseType))
1368 // For the ones below no extra argument matters for comparison.
1373 assert(!"unexpected binary ExOp operator");
1377 if (op1->gtOp.gtOp2)
1379 if (!Compare(op1->gtOp.gtOp1, op2->gtOp.gtOp1, swapOK))
1381 if (swapOK && OperIsCommutative(oper) &&
1382 ((op1->gtOp.gtOp1->gtFlags | op1->gtOp.gtOp2->gtFlags | op2->gtOp.gtOp1->gtFlags |
1383 op2->gtOp.gtOp2->gtFlags) &
1384 GTF_ALL_EFFECT) == 0)
1386 if (Compare(op1->gtOp.gtOp1, op2->gtOp.gtOp2, swapOK))
1388 op1 = op1->gtOp.gtOp2;
1389 op2 = op2->gtOp.gtOp1;
1397 op1 = op1->gtOp.gtOp2;
1398 op2 = op2->gtOp.gtOp2;
1405 op1 = op1->gtOp.gtOp1;
1406 op2 = op2->gtOp.gtOp1;
1410 return (op2 == nullptr);
1421 /* See what kind of a special operator we have here */
1426 if (op1->gtField.gtFldHnd != op2->gtField.gtFldHnd)
1431 op1 = op1->gtField.gtFldObj;
1432 op2 = op2->gtField.gtFldObj;
1446 if (op1->gtCall.gtCallType != op2->gtCall.gtCallType)
1451 if (op1->gtCall.gtCallType != CT_INDIRECT)
1453 if (op1->gtCall.gtCallMethHnd != op2->gtCall.gtCallMethHnd)
1458 #ifdef FEATURE_READYTORUN_COMPILER
1459 if (op1->gtCall.gtEntryPoint.addr != op2->gtCall.gtEntryPoint.addr)
1467 if (!Compare(op1->gtCall.gtCallAddr, op2->gtCall.gtCallAddr))
1473 if (Compare(op1->gtCall.gtCallLateArgs, op2->gtCall.gtCallLateArgs) &&
1474 Compare(op1->gtCall.gtCallArgs, op2->gtCall.gtCallArgs) &&
1475 Compare(op1->gtCall.gtControlExpr, op2->gtCall.gtControlExpr) &&
1476 Compare(op1->gtCall.gtCallObjp, op2->gtCall.gtCallObjp))
1484 if (op1->gtArrElem.gtArrRank != op2->gtArrElem.gtArrRank)
1489 // NOTE: gtArrElemSize may need to be handled
1492 for (dim = 0; dim < op1->gtArrElem.gtArrRank; dim++)
1494 if (!Compare(op1->gtArrElem.gtArrInds[dim], op2->gtArrElem.gtArrInds[dim]))
1500 op1 = op1->gtArrElem.gtArrObj;
1501 op2 = op2->gtArrElem.gtArrObj;
1505 if (op1->gtArrOffs.gtCurrDim != op2->gtArrOffs.gtCurrDim ||
1506 op1->gtArrOffs.gtArrRank != op2->gtArrOffs.gtArrRank)
1510 return (Compare(op1->gtArrOffs.gtOffset, op2->gtArrOffs.gtOffset) &&
1511 Compare(op1->gtArrOffs.gtIndex, op2->gtArrOffs.gtIndex) &&
1512 Compare(op1->gtArrOffs.gtArrObj, op2->gtArrOffs.gtArrObj));
1515 return Compare(op1->gtCmpXchg.gtOpLocation, op2->gtCmpXchg.gtOpLocation) &&
1516 Compare(op1->gtCmpXchg.gtOpValue, op2->gtCmpXchg.gtOpValue) &&
1517 Compare(op1->gtCmpXchg.gtOpComparand, op2->gtCmpXchg.gtOpComparand);
1519 case GT_ARR_BOUNDS_CHECK:
1522 #endif // FEATURE_SIMD
1523 #ifdef FEATURE_HW_INTRINSICS
1524 case GT_HW_INTRINSIC_CHK:
1525 #endif // FEATURE_HW_INTRINSICS
1526 return Compare(op1->gtBoundsChk.gtIndex, op2->gtBoundsChk.gtIndex) &&
1527 Compare(op1->gtBoundsChk.gtArrLen, op2->gtBoundsChk.gtArrLen) &&
1528 (op1->gtBoundsChk.gtThrowKind == op2->gtBoundsChk.gtThrowKind);
1530 case GT_STORE_DYN_BLK:
1532 return Compare(op1->gtDynBlk.Addr(), op2->gtDynBlk.Addr()) &&
1533 Compare(op1->gtDynBlk.Data(), op2->gtDynBlk.Data()) &&
1534 Compare(op1->gtDynBlk.gtDynamicSize, op2->gtDynBlk.gtDynamicSize);
1537 assert(!"unexpected operator");
1543 /*****************************************************************************
1545 * Returns non-zero if the given tree contains a use of a local #lclNum.
1548 bool Compiler::gtHasRef(GenTree* tree, ssize_t lclNum, bool defOnly)
1557 oper = tree->OperGet();
1558 kind = tree->OperKind();
1560 assert(oper != GT_STMT);
1562 /* Is this a constant node? */
1564 if (kind & GTK_CONST)
1569 /* Is this a leaf node? */
1571 if (kind & GTK_LEAF)
1573 if (oper == GT_LCL_VAR)
1575 if (tree->gtLclVarCommon.gtLclNum == (unsigned)lclNum)
1583 else if (oper == GT_RET_EXPR)
1585 return gtHasRef(tree->gtRetExpr.gtInlineCandidate, lclNum, defOnly);
1591 /* Is it a 'simple' unary/binary operator? */
1593 if (kind & GTK_SMPOP)
1595 if (tree->gtGetOp2IfPresent())
1597 if (gtHasRef(tree->gtOp.gtOp1, lclNum, defOnly))
1602 tree = tree->gtOp.gtOp2;
1607 tree = tree->gtOp.gtOp1;
1616 // 'tree' is the gtOp1 of an assignment node. So we can handle
1617 // the case where defOnly is either true or false.
1619 if (tree->gtOper == GT_LCL_VAR && tree->gtLclVarCommon.gtLclNum == (unsigned)lclNum)
1623 else if (tree->gtOper == GT_FIELD && lclNum == (ssize_t)tree->gtField.gtFldHnd)
1633 /* See what kind of a special operator we have here */
1638 if (lclNum == (ssize_t)tree->gtField.gtFldHnd)
1646 tree = tree->gtField.gtFldObj;
1655 if (tree->gtCall.gtCallObjp)
1657 if (gtHasRef(tree->gtCall.gtCallObjp, lclNum, defOnly))
1663 if (tree->gtCall.gtCallArgs)
1665 if (gtHasRef(tree->gtCall.gtCallArgs, lclNum, defOnly))
1671 if (tree->gtCall.gtCallLateArgs)
1673 if (gtHasRef(tree->gtCall.gtCallLateArgs, lclNum, defOnly))
1679 if (tree->gtCall.gtControlExpr)
1681 if (gtHasRef(tree->gtCall.gtControlExpr, lclNum, defOnly))
1687 if (tree->gtCall.gtCallType == CT_INDIRECT)
1689 // pinvoke-calli cookie is a constant, or constant indirection
1690 assert(tree->gtCall.gtCallCookie == nullptr || tree->gtCall.gtCallCookie->gtOper == GT_CNS_INT ||
1691 tree->gtCall.gtCallCookie->gtOper == GT_IND);
1693 tree = tree->gtCall.gtCallAddr;
1708 if (gtHasRef(tree->gtArrElem.gtArrObj, lclNum, defOnly))
1714 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
1716 if (gtHasRef(tree->gtArrElem.gtArrInds[dim], lclNum, defOnly))
1725 if (gtHasRef(tree->gtArrOffs.gtOffset, lclNum, defOnly) ||
1726 gtHasRef(tree->gtArrOffs.gtIndex, lclNum, defOnly) ||
1727 gtHasRef(tree->gtArrOffs.gtArrObj, lclNum, defOnly))
1734 if (gtHasRef(tree->gtCmpXchg.gtOpLocation, lclNum, defOnly))
1738 if (gtHasRef(tree->gtCmpXchg.gtOpValue, lclNum, defOnly))
1742 if (gtHasRef(tree->gtCmpXchg.gtOpComparand, lclNum, defOnly))
1748 case GT_ARR_BOUNDS_CHECK:
1751 #endif // FEATURE_SIMD
1752 #ifdef FEATURE_HW_INTRINSICS
1753 case GT_HW_INTRINSIC_CHK:
1754 #endif // FEATURE_HW_INTRINSICS
1755 if (gtHasRef(tree->gtBoundsChk.gtIndex, lclNum, defOnly))
1759 if (gtHasRef(tree->gtBoundsChk.gtArrLen, lclNum, defOnly))
1765 case GT_STORE_DYN_BLK:
1766 if (gtHasRef(tree->gtDynBlk.Data(), lclNum, defOnly))
1772 if (gtHasRef(tree->gtDynBlk.Addr(), lclNum, defOnly))
1776 if (gtHasRef(tree->gtDynBlk.gtDynamicSize, lclNum, defOnly))
1786 assert(!"unexpected operator");
1795 bool hasAddrTakenLcl;
1799 Compiler::fgWalkResult Compiler::gtHasLocalsWithAddrOpCB(GenTree** pTree, fgWalkData* data)
1801 GenTree* tree = *pTree;
1802 Compiler* comp = data->compiler;
1804 if (tree->gtOper == GT_LCL_VAR)
1806 unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
1807 LclVarDsc* varDsc = &comp->lvaTable[lclNum];
1809 if (varDsc->lvHasLdAddrOp || varDsc->lvAddrExposed)
1811 ((AddrTakenDsc*)data->pCallbackData)->hasAddrTakenLcl = true;
1816 return WALK_CONTINUE;
1819 /*****************************************************************************
1821 * Return true if this tree contains locals with lvHasLdAddrOp or lvAddrExposed
1825 bool Compiler::gtHasLocalsWithAddrOp(GenTree* tree)
1830 desc.hasAddrTakenLcl = false;
1832 fgWalkTreePre(&tree, gtHasLocalsWithAddrOpCB, &desc);
1834 return desc.hasAddrTakenLcl;
1839 /*****************************************************************************
1841 * Helper used to compute hash values for trees.
1844 inline unsigned genTreeHashAdd(unsigned old, unsigned add)
1846 return (old + old / 2) ^ add;
1849 inline unsigned genTreeHashAdd(unsigned old, void* add)
1851 return genTreeHashAdd(old, (unsigned)(size_t)add);
1854 /*****************************************************************************
1856 * Given an arbitrary expression tree, compute a hash value for it.
1859 unsigned Compiler::gtHashValue(GenTree* tree)
1870 assert(tree->gtOper != GT_STMT);
1872 /* Figure out what kind of a node we have */
1874 oper = tree->OperGet();
1875 kind = tree->OperKind();
1877 /* Include the operator value in the hash */
1879 hash = genTreeHashAdd(hash, oper);
1881 /* Is this a constant or leaf node? */
1883 if (kind & (GTK_CONST | GTK_LEAF))
1891 add = tree->gtLclVar.gtLclNum;
1894 hash = genTreeHashAdd(hash, tree->gtLclFld.gtLclNum);
1895 add = tree->gtLclFld.gtLclOffs;
1899 add = tree->gtIntCon.gtIconVal;
1902 bits = (UINT64)tree->gtLngCon.gtLconVal;
1905 #else // 32-bit host
1906 add = genTreeHashAdd(uhi32(bits), ulo32(bits));
1910 bits = *(UINT64*)(&tree->gtDblCon.gtDconVal);
1913 #else // 32-bit host
1914 add = genTreeHashAdd(uhi32(bits), ulo32(bits));
1918 add = tree->gtStrCon.gtSconCPX;
1922 add = tree->gtVal.gtVal1;
1931 // narrow 'add' into a 32-bit 'val'
1934 val = genTreeHashAdd(uhi32(add), ulo32(add));
1935 #else // 32-bit host
1940 hash = genTreeHashAdd(hash, val);
1944 /* Is it a 'simple' unary/binary operator? */
1948 if (kind & GTK_UNOP)
1950 op1 = tree->gtOp.gtOp1;
1951 /* Special case: no sub-operand at all */
1953 if (GenTree::IsExOp(kind))
1955 // ExOp operators extend operators with extra, non-GenTree* members. In many cases,
1956 // these should be included in the hash code.
1960 hash += tree->gtArrLen.ArrLenOffset();
1963 hash ^= tree->gtCast.gtCastType;
1966 hash += tree->gtIndex.gtIndElemSize;
1969 hash += tree->AsIndexAddr()->gtElemSize;
1972 hash = genTreeHashAdd(hash, static_cast<unsigned>(
1973 reinterpret_cast<uintptr_t>(tree->gtAllocObj.gtAllocObjClsHnd)));
1974 hash = genTreeHashAdd(hash, tree->gtAllocObj.gtNewHelper);
1976 case GT_RUNTIMELOOKUP:
1978 genTreeHashAdd(hash,
1979 static_cast<unsigned>(reinterpret_cast<uintptr_t>(tree->gtRuntimeLookup.gtHnd)));
1984 genTreeHashAdd(hash, static_cast<unsigned>(reinterpret_cast<uintptr_t>(tree->gtObj.gtClass)));
1986 // For the ones below no extra argument matters for comparison.
1991 assert(!"unexpected unary ExOp operator");
2004 if (kind & GTK_BINOP)
2006 if (GenTree::IsExOp(kind))
2008 // ExOp operators extend operators with extra, non-GenTree* members. In many cases,
2009 // these should be included in the hash code.
2013 hash += tree->gtIntrinsic.gtIntrinsicId;
2016 hash += static_cast<unsigned>(tree->gtAddrMode.Offset() << 3) + tree->gtAddrMode.gtScale;
2021 hash += tree->gtBlk.gtBlkSize;
2026 hash ^= PtrToUlong(tree->AsObj()->gtClass);
2030 case GT_STORE_DYN_BLK:
2031 hash += gtHashValue(tree->AsDynBlk()->gtDynamicSize);
2034 // For the ones below no extra argument matters for comparison.
2043 hash += tree->gtSIMD.gtSIMDIntrinsicID;
2044 hash += tree->gtSIMD.gtSIMDBaseType;
2045 hash += tree->gtSIMD.gtSIMDSize;
2047 #endif // FEATURE_SIMD
2049 #ifdef FEATURE_HW_INTRINSICS
2050 case GT_HWIntrinsic:
2051 hash += tree->gtHWIntrinsic.gtHWIntrinsicId;
2052 hash += tree->gtHWIntrinsic.gtSIMDBaseType;
2053 hash += tree->gtHWIntrinsic.gtSIMDSize;
2054 hash += tree->gtHWIntrinsic.gtIndexBaseType;
2056 #endif // FEATURE_HW_INTRINSICS
2059 assert(!"unexpected binary ExOp operator");
2063 op1 = tree->gtOp.gtOp1;
2064 GenTree* op2 = tree->gtOp.gtOp2;
2066 /* Is there a second sub-operand? */
2070 /* Special case: no sub-operands at all */
2077 /* This is a unary operator */
2083 /* This is a binary operator */
2085 unsigned hsh1 = gtHashValue(op1);
2087 /* Add op1's hash to the running value and continue with op2 */
2089 hash = genTreeHashAdd(hash, hsh1);
2095 /* See what kind of a special operator we have here */
2096 switch (tree->gtOper)
2099 if (tree->gtField.gtFldObj)
2101 temp = tree->gtField.gtFldObj;
2103 hash = genTreeHashAdd(hash, gtHashValue(temp));
2108 temp = tree->gtStmt.gtStmtExpr;
2110 hash = genTreeHashAdd(hash, gtHashValue(temp));
2115 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrElem.gtArrObj));
2118 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
2120 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrElem.gtArrInds[dim]));
2126 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrOffs.gtOffset));
2127 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrOffs.gtIndex));
2128 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrOffs.gtArrObj));
2133 if (tree->gtCall.gtCallObjp && tree->gtCall.gtCallObjp->gtOper != GT_NOP)
2135 temp = tree->gtCall.gtCallObjp;
2137 hash = genTreeHashAdd(hash, gtHashValue(temp));
2140 if (tree->gtCall.gtCallArgs)
2142 temp = tree->gtCall.gtCallArgs;
2144 hash = genTreeHashAdd(hash, gtHashValue(temp));
2147 if (tree->gtCall.gtCallType == CT_INDIRECT)
2149 temp = tree->gtCall.gtCallAddr;
2151 hash = genTreeHashAdd(hash, gtHashValue(temp));
2155 hash = genTreeHashAdd(hash, tree->gtCall.gtCallMethHnd);
2158 if (tree->gtCall.gtCallLateArgs)
2160 temp = tree->gtCall.gtCallLateArgs;
2162 hash = genTreeHashAdd(hash, gtHashValue(temp));
2167 hash = genTreeHashAdd(hash, gtHashValue(tree->gtCmpXchg.gtOpLocation));
2168 hash = genTreeHashAdd(hash, gtHashValue(tree->gtCmpXchg.gtOpValue));
2169 hash = genTreeHashAdd(hash, gtHashValue(tree->gtCmpXchg.gtOpComparand));
2172 case GT_ARR_BOUNDS_CHECK:
2175 #endif // FEATURE_SIMD
2176 #ifdef FEATURE_HW_INTRINSICS
2177 case GT_HW_INTRINSIC_CHK:
2178 #endif // FEATURE_HW_INTRINSICS
2179 hash = genTreeHashAdd(hash, gtHashValue(tree->gtBoundsChk.gtIndex));
2180 hash = genTreeHashAdd(hash, gtHashValue(tree->gtBoundsChk.gtArrLen));
2181 hash = genTreeHashAdd(hash, tree->gtBoundsChk.gtThrowKind);
2184 case GT_STORE_DYN_BLK:
2185 hash = genTreeHashAdd(hash, gtHashValue(tree->gtDynBlk.Data()));
2188 hash = genTreeHashAdd(hash, gtHashValue(tree->gtDynBlk.Addr()));
2189 hash = genTreeHashAdd(hash, gtHashValue(tree->gtDynBlk.gtDynamicSize));
2196 assert(!"unexpected operator");
2207 /*****************************************************************************
2209 * Return a relational operator that is the reverse of the given one.
2213 genTreeOps GenTree::ReverseRelop(genTreeOps relop)
2215 static const genTreeOps reverseOps[] = {
2222 GT_TEST_NE, // GT_TEST_EQ
2223 GT_TEST_EQ, // GT_TEST_NE
2226 assert(reverseOps[GT_EQ - GT_EQ] == GT_NE);
2227 assert(reverseOps[GT_NE - GT_EQ] == GT_EQ);
2229 assert(reverseOps[GT_LT - GT_EQ] == GT_GE);
2230 assert(reverseOps[GT_LE - GT_EQ] == GT_GT);
2231 assert(reverseOps[GT_GE - GT_EQ] == GT_LT);
2232 assert(reverseOps[GT_GT - GT_EQ] == GT_LE);
2234 assert(reverseOps[GT_TEST_EQ - GT_EQ] == GT_TEST_NE);
2235 assert(reverseOps[GT_TEST_NE - GT_EQ] == GT_TEST_EQ);
2237 assert(OperIsCompare(relop));
2238 assert(relop >= GT_EQ && (unsigned)(relop - GT_EQ) < sizeof(reverseOps));
2240 return reverseOps[relop - GT_EQ];
2243 /*****************************************************************************
2245 * Return a relational operator that will work for swapped operands.
2249 genTreeOps GenTree::SwapRelop(genTreeOps relop)
2251 static const genTreeOps swapOps[] = {
2258 GT_TEST_EQ, // GT_TEST_EQ
2259 GT_TEST_NE, // GT_TEST_NE
2262 assert(swapOps[GT_EQ - GT_EQ] == GT_EQ);
2263 assert(swapOps[GT_NE - GT_EQ] == GT_NE);
2265 assert(swapOps[GT_LT - GT_EQ] == GT_GT);
2266 assert(swapOps[GT_LE - GT_EQ] == GT_GE);
2267 assert(swapOps[GT_GE - GT_EQ] == GT_LE);
2268 assert(swapOps[GT_GT - GT_EQ] == GT_LT);
2270 assert(swapOps[GT_TEST_EQ - GT_EQ] == GT_TEST_EQ);
2271 assert(swapOps[GT_TEST_NE - GT_EQ] == GT_TEST_NE);
2273 assert(OperIsCompare(relop));
2274 assert(relop >= GT_EQ && (unsigned)(relop - GT_EQ) < sizeof(swapOps));
2276 return swapOps[relop - GT_EQ];
2279 /*****************************************************************************
2281 * Reverse the meaning of the given test condition.
2284 GenTree* Compiler::gtReverseCond(GenTree* tree)
2286 if (tree->OperIsCompare())
2288 tree->SetOper(GenTree::ReverseRelop(tree->OperGet()));
2290 // Flip the GTF_RELOP_NAN_UN bit
2291 // a ord b === (a != NaN && b != NaN)
2292 // a unord b === (a == NaN || b == NaN)
2293 // => !(a ord b) === (a unord b)
2294 if (varTypeIsFloating(tree->gtOp.gtOp1->TypeGet()))
2296 tree->gtFlags ^= GTF_RELOP_NAN_UN;
2299 else if (tree->OperIs(GT_JCC, GT_SETCC))
2301 GenTreeCC* cc = tree->AsCC();
2302 cc->gtCondition = GenTree::ReverseRelop(cc->gtCondition);
2304 else if (tree->OperIs(GT_JCMP))
2306 // Flip the GTF_JCMP_EQ
2308 // This causes switching
2311 tree->gtFlags ^= GTF_JCMP_EQ;
2315 tree = gtNewOperNode(GT_NOT, TYP_INT, tree);
2321 /*****************************************************************************/
2325 bool GenTree::gtIsValid64RsltMul()
2327 if ((gtOper != GT_MUL) || !(gtFlags & GTF_MUL_64RSLT))
2332 GenTree* op1 = gtOp.gtOp1;
2333 GenTree* op2 = gtOp.gtOp2;
2335 if (TypeGet() != TYP_LONG || op1->TypeGet() != TYP_LONG || op2->TypeGet() != TYP_LONG)
2345 // op1 has to be conv.i8(i4Expr)
2346 if ((op1->gtOper != GT_CAST) || (genActualType(op1->CastFromType()) != TYP_INT))
2351 // op2 has to be conv.i8(i4Expr)
2352 if ((op2->gtOper != GT_CAST) || (genActualType(op2->CastFromType()) != TYP_INT))
2357 // The signedness of both casts must be the same
2358 if (((op1->gtFlags & GTF_UNSIGNED) != 0) != ((op2->gtFlags & GTF_UNSIGNED) != 0))
2363 // Do unsigned mul iff both the casts are unsigned
2364 if (((op1->gtFlags & GTF_UNSIGNED) != 0) != ((gtFlags & GTF_UNSIGNED) != 0))
2374 //------------------------------------------------------------------------------
2375 // gtSetListOrder : Figure out the evaluation order for a list of values.
2379 // list - List to figure out the evaluation order for
2380 // isListCallArgs - True iff the list is a list of call arguments
2381 // callArgsInRegs - True iff the list is a list of call arguments and they are passed in registers
2384 // True if the operation can be a root of a bitwise rotation tree; false otherwise.
2386 unsigned Compiler::gtSetListOrder(GenTree* list, bool isListCallArgs, bool callArgsInRegs)
2388 assert((list != nullptr) && list->OperIsAnyList());
2389 assert(!callArgsInRegs || isListCallArgs);
2391 ArrayStack<GenTree*> listNodes(getAllocator(CMK_ArrayStack));
2395 listNodes.Push(list);
2396 list = list->gtOp.gtOp2;
2397 } while ((list != nullptr) && (list->OperIsAnyList()));
2399 unsigned nxtlvl = (list == nullptr) ? 0 : gtSetEvalOrder(list);
2400 while (listNodes.Height() > 0)
2402 list = listNodes.Pop();
2403 assert(list && list->OperIsAnyList());
2404 GenTree* next = list->gtOp.gtOp2;
2408 // TODO: Do we have to compute costs differently for argument lists and
2410 // https://github.com/dotnet/coreclr/issues/7095
2411 unsigned costSz = (isListCallArgs || (next == nullptr)) ? 0 : 1;
2412 unsigned costEx = (isListCallArgs || (next == nullptr)) ? 0 : 1;
2414 if (next != nullptr)
2423 costEx += next->gtCostEx;
2424 costSz += next->gtCostSz;
2427 GenTree* op1 = list->gtOp.gtOp1;
2428 unsigned lvl = gtSetEvalOrder(op1);
2430 // Swap the level counts
2431 if (list->gtFlags & GTF_REVERSE_OPS)
2440 // TODO: Do we have to compute levels differently for argument lists and
2442 // https://github.com/dotnet/coreclr/issues/7095
2456 else if (lvl == nxtlvl)
2466 if (op1->gtCostEx != 0)
2468 costEx += op1->gtCostEx;
2469 costEx += (callArgsInRegs || !isListCallArgs) ? 0 : IND_COST_EX;
2472 if (op1->gtCostSz != 0)
2474 costSz += op1->gtCostSz;
2475 #ifdef _TARGET_XARCH_
2476 if (callArgsInRegs) // push is smaller than mov to reg
2483 list->SetCosts(costEx, costSz);
2491 //-----------------------------------------------------------------------------
2492 // gtWalkOp: Traverse and mark an address expression
2495 // op1WB - An out parameter which is either the address expression, or one
2497 // op2WB - An out parameter which starts as either null or one of the operands
2498 // of the address expression.
2499 // base - The base address of the addressing mode, or null if 'constOnly' is false
2500 // constOnly - True if we will only traverse into ADDs with constant op2.
2502 // This routine is a helper routine for gtSetEvalOrder() and is used to identify the
2503 // base and index nodes, which will be validated against those identified by
2504 // genCreateAddrMode().
2505 // It also marks the ADD nodes involved in the address expression with the
2506 // GTF_ADDRMODE_NO_CSE flag which prevents them from being considered for CSE's.
2508 // Its two output parameters are modified under the following conditions:
2510 // It is called once with the original address expression as 'op1WB', and
2511 // with 'constOnly' set to false. On this first invocation, *op1WB is always
2512 // an ADD node, and it will consider the operands of the ADD even if its op2 is
2513 // not a constant. However, when it encounters a non-constant or the base in the
2514 // op2 position, it stops iterating. That operand is returned in the 'op2WB' out
2515 // parameter, and will be considered on the third invocation of this method if
2518 // It is called the second time with the two operands of the original expression, in
2519 // the original order, and the third time in reverse order. For these invocations
2520 // 'constOnly' is true, so it will only traverse cascaded ADD nodes if they have a
2523 // The result, after three invocations, is that the values of the two out parameters
2524 // correspond to the base and index in some fashion. This method doesn't attempt
2525 // to determine or validate the scale or offset, if any.
2527 // Assumptions (presumed to be ensured by genCreateAddrMode()):
2528 // If an ADD has a constant operand, it is in the op2 position.
2531 // This method, and its invocation sequence, are quite confusing, and since they
2532 // were not originally well-documented, this specification is a possibly-imperfect
2534 // The motivation for the handling of the NOP case is unclear.
2535 // Note that 'op2WB' is only modified in the initial (!constOnly) case,
2536 // or if a NOP is encountered in the op1 position.
2538 void Compiler::gtWalkOp(GenTree** op1WB, GenTree** op2WB, GenTree* base, bool constOnly)
2540 GenTree* op1 = *op1WB;
2541 GenTree* op2 = *op2WB;
2543 op1 = op1->gtEffectiveVal();
2545 // Now we look for op1's with non-overflow GT_ADDs [of constants]
2546 while ((op1->gtOper == GT_ADD) && (!op1->gtOverflow()) && (!constOnly || (op1->gtOp.gtOp2->IsCnsIntOrI())))
2548 // mark it with GTF_ADDRMODE_NO_CSE
2549 op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
2553 op2 = op1->gtOp.gtOp2;
2555 op1 = op1->gtOp.gtOp1;
2557 // If op1 is a GT_NOP then swap op1 and op2.
2558 // (Why? Also, presumably op2 is not a GT_NOP in this case?)
2559 if (op1->gtOper == GT_NOP)
2568 if (!constOnly && ((op2 == base) || (!op2->IsCnsIntOrI())))
2573 op1 = op1->gtEffectiveVal();
2581 /*****************************************************************************
2582 * This is a workaround. It is to help implement an assert in gtSetEvalOrder() that the values
2583 * gtWalkOp() leaves in op1 and op2 correspond with the values of adr, idx, mul, and cns
2584 * that are returned by genCreateAddrMode(). It's essentially impossible to determine
2585 * what gtWalkOp() *should* return for all possible trees. This simply loosens one assert
2586 * to handle the following case:
2589 const(h) int 4 field
2591 lclVar byref V00 this <-- op2
2592 comma byref <-- adr (base)
2594 lclVar byref V00 this
2596 const int 2 <-- mul == 4
2598 lclVar int V01 arg1 <-- idx
2600 * Here, we are planning to generate the address mode [edx+4*eax], where eax = idx and edx = the GT_COMMA expression.
2601 * To check adr equivalence with op2, we need to walk down the GT_ADD tree just like gtWalkOp() does.
2603 GenTree* Compiler::gtWalkOpEffectiveVal(GenTree* op)
2607 op = op->gtEffectiveVal();
2609 if ((op->gtOper != GT_ADD) || op->gtOverflow() || !op->gtOp.gtOp2->IsCnsIntOrI())
2614 op = op->gtOp.gtOp1;
2621 /*****************************************************************************
2623 * Given a tree, set the gtCostEx and gtCostSz fields which
2624 * are used to measure the relative costs of the codegen of the tree
2628 void Compiler::gtPrepareCost(GenTree* tree)
2630 gtSetEvalOrder(tree);
2633 bool Compiler::gtIsLikelyRegVar(GenTree* tree)
2635 if (tree->gtOper != GT_LCL_VAR)
2640 assert(tree->gtLclVar.gtLclNum < lvaTableCnt);
2641 LclVarDsc* varDsc = lvaTable + tree->gtLclVar.gtLclNum;
2643 if (varDsc->lvDoNotEnregister)
2648 // Be pessimistic if ref counts are not yet set up.
2650 // Perhaps we should be optimistic though.
2651 // See notes in GitHub issue 18969.
2652 if (!lvaLocalVarRefCounted())
2657 if (varDsc->lvRefCntWtd() < (BB_UNITY_WEIGHT * 3))
2663 if (varTypeIsFloating(tree->TypeGet()))
2665 if (varTypeIsLong(tree->TypeGet()))
2672 //------------------------------------------------------------------------
2673 // gtCanSwapOrder: Returns true iff the secondNode can be swapped with firstNode.
2676 // firstNode - An operand of a tree that can have GTF_REVERSE_OPS set.
2677 // secondNode - The other operand of the tree.
2680 // Returns a boolean indicating whether it is safe to reverse the execution
2681 // order of the two trees, considering any exception, global effects, or
2682 // ordering constraints.
2684 bool Compiler::gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode)
2686 // Relative of order of global / side effects can't be swapped.
2688 bool canSwap = true;
2690 if (optValnumCSE_phase)
2692 canSwap = optCSE_canSwap(firstNode, secondNode);
2695 // We cannot swap in the presence of special side effects such as GT_CATCH_ARG.
2697 if (canSwap && (firstNode->gtFlags & GTF_ORDER_SIDEEFF))
2702 // When strict side effect order is disabled we allow GTF_REVERSE_OPS to be set
2703 // when one or both sides contains a GTF_CALL or GTF_EXCEPT.
2704 // Currently only the C and C++ languages allow non strict side effect order.
2706 unsigned strictEffects = GTF_GLOB_EFFECT;
2708 if (canSwap && (firstNode->gtFlags & strictEffects))
2710 // op1 has side efects that can't be reordered.
2711 // Check for some special cases where we still may be able to swap.
2713 if (secondNode->gtFlags & strictEffects)
2715 // op2 has also has non reorderable side effects - can't swap.
2720 // No side effects in op2 - we can swap iff op1 has no way of modifying op2,
2721 // i.e. through byref assignments or calls or op2 is a constant.
2723 if (firstNode->gtFlags & strictEffects & GTF_PERSISTENT_SIDE_EFFECTS)
2725 // We have to be conservative - can swap iff op2 is constant.
2726 if (!secondNode->OperIsConst())
2736 /*****************************************************************************
2738 * Given a tree, figure out the order in which its sub-operands should be
2739 * evaluated. If the second operand of a binary operator is more expensive
2740 * than the first operand, then try to swap the operand trees. Updates the
2741 * GTF_REVERSE_OPS bit if necessary in this case.
2743 * Returns the Sethi 'complexity' estimate for this tree (the higher
2744 * the number, the higher is the tree's resources requirement).
2746 * This function sets:
2747 * 1. gtCostEx to the execution complexity estimate
2748 * 2. gtCostSz to the code size estimate
2749 * 3. Sometimes sets GTF_ADDRMODE_NO_CSE on nodes in the tree.
2750 * 4. DEBUG-only: clears GTF_DEBUG_NODE_MORPHED.
2754 #pragma warning(push)
2755 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
2757 unsigned Compiler::gtSetEvalOrder(GenTree* tree)
2760 assert(tree->gtOper != GT_STMT);
2763 /* Clear the GTF_DEBUG_NODE_MORPHED flag as well */
2764 tree->gtDebugFlags &= ~GTF_DEBUG_NODE_MORPHED;
2767 /* Is this a FP value? */
2769 bool isflt = varTypeIsFloating(tree->TypeGet());
2771 /* Figure out what kind of a node we have */
2773 const genTreeOps oper = tree->OperGet();
2774 const unsigned kind = tree->OperKind();
2776 /* Assume no fixed registers will be trashed */
2787 /* Is this a constant or a leaf node? */
2789 if (kind & (GTK_LEAF | GTK_CONST))
2807 // If the constant is a handle then it will need to have a relocation
2809 // Any constant that requires a reloc must use the movw/movt sequence
2811 GenTreeIntConCommon* con = tree->AsIntConCommon();
2813 if (con->ImmedValNeedsReloc(this) ||
2814 !codeGen->validImmForInstr(INS_mov, (target_ssize_t)tree->gtIntCon.gtIconVal))
2820 else if (((unsigned)tree->gtIntCon.gtIconVal) <= 0x00ff)
2835 #elif defined _TARGET_XARCH_
2849 // If the constant is a handle then it will need to have a relocation
2852 GenTreeIntConCommon* con = tree->AsIntConCommon();
2854 bool iconNeedsReloc = con->ImmedValNeedsReloc(this);
2856 if (!iconNeedsReloc && con->FitsInI8())
2861 #if defined(_TARGET_AMD64_)
2862 else if (iconNeedsReloc || !con->FitsInI32())
2867 #endif // _TARGET_AMD64_
2876 #elif defined(_TARGET_ARM64_)
2880 // TODO-ARM64-NYI: Need cost estimates.
2889 #error "Unknown _TARGET_"
2894 Note that some code below depends on constants always getting
2895 moved to be the second operand of a binary operator. This is
2896 easily accomplished by giving constants a level of 0, which
2897 we do on the next line. If you ever decide to change this, be
2898 aware that unless you make other arrangements for integer
2899 constants to be moved, stuff will break.
2907 /* We use fldz and fld1 to load 0.0 and 1.0, but all other */
2908 /* floating point constants are loaded using an indirection */
2909 if ((*((__int64*)&(tree->gtDblCon.gtDconVal)) == 0) ||
2910 (*((__int64*)&(tree->gtDblCon.gtDconVal)) == I64(0x3ff0000000000000)))
2917 costEx = IND_COST_EX;
2924 if (gtIsLikelyRegVar(tree))
2928 /* Sign-extend and zero-extend are more expensive to load */
2929 if (lvaTable[tree->gtLclVar.gtLclNum].lvNormalizeOnLoad())
2937 costEx = IND_COST_EX;
2939 /* Sign-extend and zero-extend are more expensive to load */
2940 if (varTypeIsSmall(tree->TypeGet()))
2946 #if defined(_TARGET_AMD64_)
2947 // increase costSz for floating point locals
2951 if (!gtIsLikelyRegVar(tree))
2961 // We generate movw/movt/ldr
2963 costEx = 3 + IND_COST_EX; // 6
2964 costSz = 4 + 4 + 2; // 10
2969 costEx = IND_COST_EX;
2971 if (varTypeIsSmall(tree->TypeGet()))
2994 /* Is it a 'simple' unary/binary operator? */
2996 if (kind & GTK_SMPOP)
2998 int lvlb; // preference for op2
2999 unsigned lvl2; // scratch variable
3001 GenTree* op1 = tree->gtOp.gtOp1;
3002 GenTree* op2 = tree->gtGetOp2IfPresent();
3007 if (tree->OperIsAddrMode())
3016 /* Check for a nilary operator */
3020 assert(op2 == nullptr);
3027 /* Is this a unary operator? */
3031 /* Process the operand of the operator */
3033 /* Most Unary ops have costEx of 1 */
3037 level = gtSetEvalOrder(op1);
3039 /* Special handling for some operators */
3054 #if defined(_TARGET_ARM_)
3057 if (isflt || varTypeIsFloating(op1->TypeGet()))
3062 #elif defined(_TARGET_ARM64_)
3065 if (isflt || varTypeIsFloating(op1->TypeGet()))
3070 #elif defined(_TARGET_XARCH_)
3074 if (isflt || varTypeIsFloating(op1->TypeGet()))
3076 /* cast involving floats always go through memory */
3077 costEx = IND_COST_EX * 2;
3081 #error "Unknown _TARGET_"
3084 /* Overflow casts are a lot more expensive */
3085 if (tree->gtOverflow())
3101 // GT_INTRINSIC intrinsics Sin, Cos, Sqrt, Abs ... have higher costs.
3102 // TODO: tune these costs target specific as some of these are
3103 // target intrinsics and would cost less to generate code.
3104 switch (tree->gtIntrinsic.gtIntrinsicId)
3107 assert(!"missing case for gtIntrinsicId");
3112 case CORINFO_INTRINSIC_Sin:
3113 case CORINFO_INTRINSIC_Cos:
3114 case CORINFO_INTRINSIC_Sqrt:
3115 case CORINFO_INTRINSIC_Cbrt:
3116 case CORINFO_INTRINSIC_Cosh:
3117 case CORINFO_INTRINSIC_Sinh:
3118 case CORINFO_INTRINSIC_Tan:
3119 case CORINFO_INTRINSIC_Tanh:
3120 case CORINFO_INTRINSIC_Asin:
3121 case CORINFO_INTRINSIC_Asinh:
3122 case CORINFO_INTRINSIC_Acos:
3123 case CORINFO_INTRINSIC_Acosh:
3124 case CORINFO_INTRINSIC_Atan:
3125 case CORINFO_INTRINSIC_Atanh:
3126 case CORINFO_INTRINSIC_Atan2:
3127 case CORINFO_INTRINSIC_Log10:
3128 case CORINFO_INTRINSIC_Pow:
3129 case CORINFO_INTRINSIC_Exp:
3130 case CORINFO_INTRINSIC_Ceiling:
3131 case CORINFO_INTRINSIC_Floor:
3132 case CORINFO_INTRINSIC_Object_GetType:
3133 // Giving intrinsics a large fixed execution cost is because we'd like to CSE
3134 // them, even if they are implemented by calls. This is different from modeling
3135 // user calls since we never CSE user calls.
3140 case CORINFO_INTRINSIC_Abs:
3145 case CORINFO_INTRINSIC_Round:
3155 // We need to ensure that -x is evaluated before x or else
3156 // we get burned while adjusting genFPstkLevel in x*-x where
3157 // the rhs x is the last use of the enregistered x.
3159 // Even in the integer case we want to prefer to
3160 // evaluate the side without the GT_NEG node, all other things
3161 // being equal. Also a GT_NOT requires a scratch register
3171 // If we have a GT_ADDR of an GT_IND we can just copy the costs from indOp1
3172 if (op1->OperGet() == GT_IND)
3174 GenTree* indOp1 = op1->gtOp.gtOp1;
3175 costEx = indOp1->gtCostEx;
3176 costSz = indOp1->gtCostSz;
3183 /* Array Len should be the same as an indirections, which have a costEx of IND_COST_EX */
3184 costEx = IND_COST_EX - 1;
3190 // We estimate the cost of a GT_OBJ or GT_MKREFANY to be two loads (GT_INDs)
3191 costEx = 2 * IND_COST_EX;
3196 // We estimate the cost of a GT_BOX to be two stores (GT_INDs)
3197 costEx = 2 * IND_COST_EX;
3204 /* An indirection should always have a non-zero level.
3205 * Only constant leaf nodes have level 0.
3213 /* Indirections have a costEx of IND_COST_EX */
3214 costEx = IND_COST_EX;
3217 /* If we have to sign-extend or zero-extend, bump the cost */
3218 if (varTypeIsSmall(tree->TypeGet()))
3226 if (tree->TypeGet() == TYP_DOUBLE)
3232 #endif // _TARGET_ARM_
3235 // Can we form an addressing mode with this indirection?
3236 // TODO-CQ: Consider changing this to op1->gtEffectiveVal() to take into account
3237 // addressing modes hidden under a comma node.
3239 if (op1->gtOper == GT_ADD)
3242 #if SCALED_ADDR_MODES
3244 #endif // SCALED_ADDR_MODES
3249 // See if we can form a complex addressing mode.
3251 GenTree* addr = op1->gtEffectiveVal();
3253 bool doAddrMode = true;
3254 // See if we can form a complex addressing mode.
3255 // Always use an addrMode for an array index indirection.
3256 // TODO-1stClassStructs: Always do this, but first make sure it's
3257 // done in Lowering as well.
3258 if ((tree->gtFlags & GTF_IND_ARR_INDEX) == 0)
3260 if (tree->TypeGet() == TYP_STRUCT)
3264 else if (varTypeIsStruct(tree))
3266 // This is a heuristic attempting to match prior behavior when indirections
3267 // under a struct assignment would not be considered for addressing modes.
3268 if (compCurStmt != nullptr)
3270 GenTree* expr = compCurStmt->gtStmt.gtStmtExpr;
3271 if ((expr->OperGet() == GT_ASG) &&
3272 ((expr->gtGetOp1() == tree) || (expr->gtGetOp2() == tree)))
3280 codeGen->genCreateAddrMode(addr, // address
3282 &rev, // reverse ops
3285 #if SCALED_ADDR_MODES
3287 #endif // SCALED_ADDR_MODES
3288 &cns)) // displacement
3290 // We can form a complex addressing mode, so mark each of the interior
3291 // nodes with GTF_ADDRMODE_NO_CSE and calculate a more accurate cost.
3293 addr->gtFlags |= GTF_ADDRMODE_NO_CSE;
3294 #ifdef _TARGET_XARCH_
3295 // addrmodeCount is the count of items that we used to form
3296 // an addressing mode. The maximum value is 4 when we have
3297 // all of these: { base, idx, cns, mul }
3299 unsigned addrmodeCount = 0;
3302 costEx += base->gtCostEx;
3303 costSz += base->gtCostSz;
3309 costEx += idx->gtCostEx;
3310 costSz += idx->gtCostSz;
3316 if (((signed char)cns) == ((int)cns))
3330 // When we form a complex addressing mode we can reduced the costs
3331 // associated with the interior GT_ADD and GT_LSH nodes:
3333 // GT_ADD -- reduce this interior GT_ADD by (-3,-3)
3335 // GT_ADD 'cns' -- reduce this interior GT_ADD by (-2,-2)
3337 // 'base' GT_LSL -- reduce this interior GT_LSL by (-1,-1)
3341 if (addrmodeCount > 1)
3343 // The number of interior GT_ADD and GT_LSL will always be one less than addrmodeCount
3347 GenTree* tmp = addr;
3348 while (addrmodeCount > 0)
3350 // decrement the gtCosts for the interior GT_ADD or GT_LSH node by the remaining
3352 tmp->SetCosts(tmp->gtCostEx - addrmodeCount, tmp->gtCostSz - addrmodeCount);
3355 if (addrmodeCount > 0)
3357 GenTree* tmpOp1 = tmp->gtOp.gtOp1;
3358 GenTree* tmpOp2 = tmp->gtGetOp2();
3359 assert(tmpOp2 != nullptr);
3361 if ((tmpOp1 != base) && (tmpOp1->OperGet() == GT_ADD))
3365 else if (tmpOp2->OperGet() == GT_LSH)
3369 else if (tmpOp1->OperGet() == GT_LSH)
3373 else if (tmpOp2->OperGet() == GT_ADD)
3379 // We can very rarely encounter a tree that has a GT_COMMA node
3380 // that is difficult to walk, so we just early out without decrementing.
3386 #elif defined _TARGET_ARM_
3389 costEx += base->gtCostEx;
3390 costSz += base->gtCostSz;
3391 if ((base->gtOper == GT_LCL_VAR) && ((idx == NULL) || (cns == 0)))
3399 costEx += idx->gtCostEx;
3400 costSz += idx->gtCostSz;
3409 if (cns >= 128) // small offsets fits into a 16-bit instruction
3411 if (cns < 4096) // medium offsets require a 32-bit instruction
3418 costEx += 2; // Very large offsets require movw/movt instructions
3423 #elif defined _TARGET_ARM64_
3426 costEx += base->gtCostEx;
3427 costSz += base->gtCostSz;
3432 costEx += idx->gtCostEx;
3433 costSz += idx->gtCostSz;
3438 if (cns >= (4096 * genTypeSize(tree->TypeGet())))
3445 #error "Unknown _TARGET_"
3448 assert(addr->gtOper == GT_ADD);
3449 assert(!addr->gtOverflow());
3450 assert(op2 == nullptr);
3453 // If we have an addressing mode, we have one of:
3455 // [ idx * mul ] // mul >= 2, else we would use base instead of idx
3456 // [ idx * mul + cns] // mul >= 2, else we would use base instead of idx
3457 // [base + idx * mul ] // mul can be 0, 2, 4, or 8
3458 // [base + idx * mul + cns] // mul can be 0, 2, 4, or 8
3459 // Note that mul == 0 is semantically equivalent to mul == 1.
3460 // Note that cns can be zero.
3461 CLANG_FORMAT_COMMENT_ANCHOR;
3463 #if SCALED_ADDR_MODES
3464 assert((base != nullptr) || (idx != nullptr && mul >= 2));
3466 assert(base != NULL);
3469 INDEBUG(GenTree* op1Save = addr);
3471 // Walk 'addr' identifying non-overflow ADDs that will be part of the address mode.
3472 // Note that we will be modifying 'op1' and 'op2' so that eventually they should
3473 // map to the base and index.
3475 gtWalkOp(&op1, &op2, base, false);
3477 // op1 and op2 are now descendents of the root GT_ADD of the addressing mode.
3478 assert(op1 != op1Save);
3479 assert(op2 != nullptr);
3481 // Walk the operands again (the third operand is unused in this case).
3482 // This time we will only consider adds with constant op2's, since
3483 // we have already found either a non-ADD op1 or a non-constant op2.
3484 gtWalkOp(&op1, &op2, nullptr, true);
3486 #if defined(_TARGET_XARCH_)
3487 // For XARCH we will fold GT_ADDs in the op2 position into the addressing mode, so we call
3488 // gtWalkOp on both operands of the original GT_ADD.
3489 // This is not done for ARMARCH. Though the stated reason is that we don't try to create a
3490 // scaled index, in fact we actually do create them (even base + index*scale + offset).
3492 // At this point, 'op2' may itself be an ADD of a constant that should be folded
3493 // into the addressing mode.
3494 // Walk op2 looking for non-overflow GT_ADDs of constants.
3495 gtWalkOp(&op2, &op1, nullptr, true);
3496 #endif // defined(_TARGET_XARCH_)
3498 // OK we are done walking the tree
3499 // Now assert that op1 and op2 correspond with base and idx
3500 // in one of the several acceptable ways.
3502 // Note that sometimes op1/op2 is equal to idx/base
3503 // and other times op1/op2 is a GT_COMMA node with
3504 // an effective value that is idx/base
3508 if ((op1 != base) && (op1->gtOper == GT_LSH))
3510 op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3511 if (op1->gtOp.gtOp1->gtOper == GT_MUL)
3513 op1->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3515 assert((base == nullptr) || (op2 == base) ||
3516 (op2->gtEffectiveVal() == base->gtEffectiveVal()) ||
3517 (gtWalkOpEffectiveVal(op2) == gtWalkOpEffectiveVal(base)));
3522 assert(op2->gtOper == GT_LSH || op2->gtOper == GT_MUL);
3523 op2->gtFlags |= GTF_ADDRMODE_NO_CSE;
3524 // We may have eliminated multiple shifts and multiplies in the addressing mode,
3525 // so navigate down through them to get to "idx".
3526 GenTree* op2op1 = op2->gtOp.gtOp1;
3527 while ((op2op1->gtOper == GT_LSH || op2op1->gtOper == GT_MUL) && op2op1 != idx)
3529 op2op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3530 op2op1 = op2op1->gtOp.gtOp1;
3532 assert(op1->gtEffectiveVal() == base);
3533 assert(op2op1 == idx);
3540 if ((op1 == idx) || (op1->gtEffectiveVal() == idx))
3544 if ((op1->gtOper == GT_MUL) || (op1->gtOper == GT_LSH))
3546 if ((op1->gtOp.gtOp1->gtOper == GT_NOP) ||
3547 (op1->gtOp.gtOp1->gtOper == GT_MUL &&
3548 op1->gtOp.gtOp1->gtOp.gtOp1->gtOper == GT_NOP))
3550 op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3551 if (op1->gtOp.gtOp1->gtOper == GT_MUL)
3553 op1->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3558 assert((op2 == base) || (op2->gtEffectiveVal() == base));
3560 else if ((op1 == base) || (op1->gtEffectiveVal() == base))
3565 if ((op2->gtOper == GT_MUL) || (op2->gtOper == GT_LSH))
3567 if ((op2->gtOp.gtOp1->gtOper == GT_NOP) ||
3568 (op2->gtOp.gtOp1->gtOper == GT_MUL &&
3569 op2->gtOp.gtOp1->gtOp.gtOp1->gtOper == GT_NOP))
3571 op2->gtFlags |= GTF_ADDRMODE_NO_CSE;
3572 if (op2->gtOp.gtOp1->gtOper == GT_MUL)
3574 op2->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3578 assert((op2 == idx) || (op2->gtEffectiveVal() == idx));
3583 // op1 isn't base or idx. Is this possible? Or should there be an assert?
3588 } // end if (genCreateAddrMode(...))
3590 } // end if (op1->gtOper == GT_ADD)
3591 else if (gtIsLikelyRegVar(op1))
3593 /* Indirection of an enregister LCL_VAR, don't increase costEx/costSz */
3596 #ifdef _TARGET_XARCH_
3597 else if (op1->IsCnsIntOrI())
3599 // Indirection of a CNS_INT, subtract 1 from costEx
3600 // makes costEx 3 for x86 and 4 for amd64
3602 costEx += (op1->gtCostEx - 1);
3603 costSz += op1->gtCostSz;
3612 costEx += op1->gtCostEx;
3613 costSz += op1->gtCostSz;
3617 /* Binary operator - check for certain special cases */
3621 /* Default Binary ops have a cost of 1,1 */
3631 #ifndef _TARGET_64BIT_
3632 if (varTypeIsLong(op1->TypeGet()))
3634 /* Operations on longs are more expensive */
3644 /* Modulo by a power of 2 is easy */
3646 if (op2->IsCnsIntOrI())
3648 size_t ival = op2->gtIntConCommon.IconValue();
3650 if (ival > 0 && ival == genFindLowestBit(ival))
3663 /* fp division is very expensive to execute */
3664 costEx = 36; // TYP_DOUBLE
3669 /* integer division is also very expensive */
3673 // Encourage the first operand to be evaluated (into EAX/EDX) first */
3682 /* FP multiplication instructions are more expensive */
3688 /* Integer multiplication instructions are more expensive */
3692 if (tree->gtOverflow())
3694 /* Overflow check are more expensive */
3700 if ((tree->gtType == TYP_LONG) || tree->gtOverflow())
3702 /* We use imulEAX for TYP_LONG and overflow multiplications */
3703 // Encourage the first operand to be evaluated (into EAX/EDX) first */
3706 /* The 64-bit imul instruction costs more */
3709 #endif // _TARGET_X86_
3717 /* FP instructions are a bit more expensive */
3723 /* Overflow check are more expensive */
3724 if (tree->gtOverflow())
3733 /* Comma tosses the result of the left operand */
3734 gtSetEvalOrder(op1);
3735 level = gtSetEvalOrder(op2);
3737 /* GT_COMMA cost is the sum of op1 and op2 costs */
3738 costEx = (op1->gtCostEx + op2->gtCostEx);
3739 costSz = (op1->gtCostSz + op2->gtCostSz);
3745 level = gtSetEvalOrder(op1);
3746 lvl2 = gtSetEvalOrder(op2);
3752 else if (level == lvl2)
3757 costEx = op1->gtCostEx + op2->gtCostEx;
3758 costSz = op1->gtCostSz + op2->gtCostSz;
3765 const bool isListCallArgs = false;
3766 const bool callArgsInRegs = false;
3767 return gtSetListOrder(tree, isListCallArgs, callArgsInRegs);
3771 /* Assignments need a bit of special handling */
3772 /* Process the target */
3773 level = gtSetEvalOrder(op1);
3775 if (gtIsLikelyRegVar(op1))
3778 lvl2 = gtSetEvalOrder(op2);
3780 /* Assignment to an enregistered LCL_VAR */
3781 costEx = op2->gtCostEx;
3782 costSz = max(3, op2->gtCostSz); // 3 is an estimate for a reg-reg assignment
3783 goto DONE_OP1_AFTER_COST;
3791 /* Process the sub-operands */
3793 level = gtSetEvalOrder(op1);
3796 level -= lvlb; // lvlb is negative, so this increases level
3802 lvl2 = gtSetEvalOrder(op2) + lvlb;
3804 costEx += (op1->gtCostEx + op2->gtCostEx);
3805 costSz += (op1->gtCostSz + op2->gtCostSz);
3807 DONE_OP1_AFTER_COST:
3809 bool bReverseInAssignment = false;
3812 GenTree* op1Val = op1;
3814 // Skip over the GT_IND/GT_ADDR tree (if one exists)
3816 if ((op1->gtOper == GT_IND) && (op1->gtOp.gtOp1->gtOper == GT_ADDR))
3818 op1Val = op1->gtOp.gtOp1->gtOp.gtOp1;
3821 switch (op1Val->gtOper)
3828 // In an indirection, the destination address is evaluated prior to the source.
3829 // If we have any side effects on the target indirection,
3830 // we have to evaluate op1 first.
3831 // However, if the LHS is a lclVar address, SSA relies on using evaluation order for its
3832 // renaming, and therefore the RHS must be evaluated first.
3833 // If we have an assignment involving a lclVar address, the LHS may be marked as having
3835 // However the side-effects won't require that we evaluate the LHS address first:
3836 // - The GTF_GLOB_REF might have been conservatively set on a FIELD of a local.
3837 // - The local might be address-exposed, but that side-effect happens at the actual assignment (not
3838 // when its address is "evaluated") so it doesn't change the side effect to "evaluate" the address
3839 // after the RHS (note that in this case it won't be renamed by SSA anyway, but the reordering is
3842 if (op1Val->AsIndir()->Addr()->IsLocalAddrExpr())
3844 bReverseInAssignment = true;
3845 tree->gtFlags |= GTF_REVERSE_OPS;
3848 if (op1Val->AsIndir()->Addr()->gtFlags & GTF_ALL_EFFECT)
3853 // In case op2 assigns to a local var that is used in op1Val, we have to evaluate op1Val first.
3854 if (op2->gtFlags & GTF_ASG)
3859 // If op2 is simple then evaluate op1 first
3861 if (op2->OperKind() & GTK_LEAF)
3866 // fall through and set GTF_REVERSE_OPS
3871 // We evaluate op2 before op1
3872 bReverseInAssignment = true;
3873 tree->gtFlags |= GTF_REVERSE_OPS;
3880 else if (kind & GTK_RELOP)
3882 /* Float compares remove both operands from the FP stack */
3883 /* Also FP comparison uses EAX for flags */
3885 if (varTypeIsFloating(op1->TypeGet()))
3890 if ((tree->gtFlags & GTF_RELOP_JMP_USED) == 0)
3892 /* Using a setcc instruction is more expensive */
3897 /* Check for other interesting cases */
3906 /* Variable sized shifts are more expensive and use REG_SHIFT */
3908 if (!op2->IsCnsIntOrI())
3911 #ifndef _TARGET_64BIT_
3912 // Variable sized LONG shifts require the use of a helper call
3914 if (tree->gtType == TYP_LONG)
3918 costEx += 3 * IND_COST_EX;
3921 #endif // !_TARGET_64BIT_
3927 switch (tree->gtIntrinsic.gtIntrinsicId)
3929 case CORINFO_INTRINSIC_Atan2:
3930 case CORINFO_INTRINSIC_Pow:
3931 // These math intrinsics are actually implemented by user calls.
3932 // Increase the Sethi 'complexity' by two to reflect the argument
3933 // register requirement.
3937 assert(!"Unknown binary GT_INTRINSIC operator");
3947 /* We need to evalutate constants later as many places in codegen
3948 can't handle op1 being a constant. This is normally naturally
3949 enforced as constants have the least level of 0. However,
3950 sometimes we end up with a tree like "cns1 < nop(cns2)". In
3951 such cases, both sides have a level of 0. So encourage constants
3952 to be evaluated last in such cases */
3954 if ((level == 0) && (level == lvl2) && (op1->OperKind() & GTK_CONST) &&
3955 (tree->OperIsCommutative() || tree->OperIsCompare()))
3960 /* We try to swap operands if the second one is more expensive */
3965 if (tree->gtFlags & GTF_REVERSE_OPS)
3976 if (fgOrder == FGOrderLinear)
3978 // Don't swap anything if we're in linear order; we're really just interested in the costs.
3981 else if (bReverseInAssignment)
3983 // Assignments are special, we want the reverseops flags
3984 // so if possible it was set above.
3987 else if ((oper == GT_INTRINSIC) && IsIntrinsicImplementedByUserCall(tree->AsIntrinsic()->gtIntrinsicId))
3989 // We do not swap operand execution order for intrinsics that are implemented by user calls
3990 // because of trickiness around ensuring the execution order does not change during rationalization.
3995 if (tree->gtFlags & GTF_REVERSE_OPS)
3997 tryToSwap = (level > lvl2);
4001 tryToSwap = (level < lvl2);
4004 // Try to force extra swapping when in the stress mode:
4005 if (compStressCompile(STRESS_REVERSE_FLAG, 60) && ((tree->gtFlags & GTF_REVERSE_OPS) == 0) &&
4006 ((op2->OperKind() & GTK_CONST) == 0))
4014 bool canSwap = gtCanSwapOrder(opA, opB);
4018 /* Can we swap the order by commuting the operands? */
4028 if (GenTree::SwapRelop(oper) != oper)
4030 tree->SetOper(GenTree::SwapRelop(oper), GenTree::PRESERVE_VN);
4042 /* Swap the operands */
4044 tree->gtOp.gtOp1 = op2;
4045 tree->gtOp.gtOp2 = op1;
4059 /* Mark the operand's evaluation order to be swapped */
4060 if (tree->gtFlags & GTF_REVERSE_OPS)
4062 tree->gtFlags &= ~GTF_REVERSE_OPS;
4066 tree->gtFlags |= GTF_REVERSE_OPS;
4074 /* Swap the level counts */
4075 if (tree->gtFlags & GTF_REVERSE_OPS)
4084 /* Compute the sethi number for this binary operator */
4090 else if (level == lvl2)
4098 /* See what kind of a special operator we have here */
4102 unsigned lvl2; // Scratch variable
4106 assert(tree->gtFlags & GTF_CALL);
4112 /* Evaluate the 'this' argument, if present */
4114 if (tree->gtCall.gtCallObjp)
4116 GenTree* thisVal = tree->gtCall.gtCallObjp;
4118 lvl2 = gtSetEvalOrder(thisVal);
4123 costEx += thisVal->gtCostEx;
4124 costSz += thisVal->gtCostSz + 1;
4127 /* Evaluate the arguments, right to left */
4129 if (tree->gtCall.gtCallArgs)
4131 const bool isListCallArgs = true;
4132 const bool callArgsInRegs = false;
4133 lvl2 = gtSetListOrder(tree->gtCall.gtCallArgs, isListCallArgs, callArgsInRegs);
4138 costEx += tree->gtCall.gtCallArgs->gtCostEx;
4139 costSz += tree->gtCall.gtCallArgs->gtCostSz;
4142 /* Evaluate the temp register arguments list
4143 * This is a "hidden" list and its only purpose is to
4144 * extend the life of temps until we make the call */
4146 if (tree->gtCall.gtCallLateArgs)
4148 const bool isListCallArgs = true;
4149 const bool callArgsInRegs = true;
4150 lvl2 = gtSetListOrder(tree->gtCall.gtCallLateArgs, isListCallArgs, callArgsInRegs);
4155 costEx += tree->gtCall.gtCallLateArgs->gtCostEx;
4156 costSz += tree->gtCall.gtCallLateArgs->gtCostSz;
4159 if (tree->gtCall.gtCallType == CT_INDIRECT)
4161 // pinvoke-calli cookie is a constant, or constant indirection
4162 assert(tree->gtCall.gtCallCookie == nullptr || tree->gtCall.gtCallCookie->gtOper == GT_CNS_INT ||
4163 tree->gtCall.gtCallCookie->gtOper == GT_IND);
4165 GenTree* indirect = tree->gtCall.gtCallAddr;
4167 lvl2 = gtSetEvalOrder(indirect);
4172 costEx += indirect->gtCostEx + IND_COST_EX;
4173 costSz += indirect->gtCostSz;
4178 if (tree->gtCall.IsVirtualStub())
4180 // We generate movw/movt/ldr
4181 costEx += (1 + IND_COST_EX);
4183 if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT)
4185 // Must use R12 for the ldr target -- REG_JUMP_THUNK_PARAM
4189 else if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
4196 #ifdef _TARGET_XARCH_
4203 /* Virtual calls are a bit more expensive */
4204 if (tree->gtCall.IsVirtual())
4206 costEx += 2 * IND_COST_EX;
4211 costEx += 3 * IND_COST_EX;
4216 level = gtSetEvalOrder(tree->gtArrElem.gtArrObj);
4217 costEx = tree->gtArrElem.gtArrObj->gtCostEx;
4218 costSz = tree->gtArrElem.gtArrObj->gtCostSz;
4221 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
4223 lvl2 = gtSetEvalOrder(tree->gtArrElem.gtArrInds[dim]);
4228 costEx += tree->gtArrElem.gtArrInds[dim]->gtCostEx;
4229 costSz += tree->gtArrElem.gtArrInds[dim]->gtCostSz;
4232 level += tree->gtArrElem.gtArrRank;
4233 costEx += 2 + (tree->gtArrElem.gtArrRank * (IND_COST_EX + 1));
4234 costSz += 2 + (tree->gtArrElem.gtArrRank * 2);
4238 level = gtSetEvalOrder(tree->gtArrOffs.gtOffset);
4239 costEx = tree->gtArrOffs.gtOffset->gtCostEx;
4240 costSz = tree->gtArrOffs.gtOffset->gtCostSz;
4241 lvl2 = gtSetEvalOrder(tree->gtArrOffs.gtIndex);
4242 level = max(level, lvl2);
4243 costEx += tree->gtArrOffs.gtIndex->gtCostEx;
4244 costSz += tree->gtArrOffs.gtIndex->gtCostSz;
4245 lvl2 = gtSetEvalOrder(tree->gtArrOffs.gtArrObj);
4246 level = max(level, lvl2);
4247 costEx += tree->gtArrOffs.gtArrObj->gtCostEx;
4248 costSz += tree->gtArrOffs.gtArrObj->gtCostSz;
4253 level = gtSetEvalOrder(tree->gtCmpXchg.gtOpLocation);
4254 costSz = tree->gtCmpXchg.gtOpLocation->gtCostSz;
4256 lvl2 = gtSetEvalOrder(tree->gtCmpXchg.gtOpValue);
4261 costSz += tree->gtCmpXchg.gtOpValue->gtCostSz;
4263 lvl2 = gtSetEvalOrder(tree->gtCmpXchg.gtOpComparand);
4268 costSz += tree->gtCmpXchg.gtOpComparand->gtCostSz;
4270 costEx = MAX_COST; // Seriously, what could be more expensive than lock cmpxchg?
4271 costSz += 5; // size of lock cmpxchg [reg+C], reg
4274 case GT_ARR_BOUNDS_CHECK:
4277 #endif // FEATURE_SIMD
4278 #ifdef FEATURE_HW_INTRINSICS
4279 case GT_HW_INTRINSIC_CHK:
4280 #endif // FEATURE_HW_INTRINSICS
4282 costEx = 4; // cmp reg,reg and jae throw (not taken)
4283 costSz = 7; // jump to cold section
4285 level = gtSetEvalOrder(tree->gtBoundsChk.gtIndex);
4286 costEx += tree->gtBoundsChk.gtIndex->gtCostEx;
4287 costSz += tree->gtBoundsChk.gtIndex->gtCostSz;
4289 lvl2 = gtSetEvalOrder(tree->gtBoundsChk.gtArrLen);
4294 costEx += tree->gtBoundsChk.gtArrLen->gtCostEx;
4295 costSz += tree->gtBoundsChk.gtArrLen->gtCostSz;
4299 case GT_STORE_DYN_BLK:
4305 if (oper == GT_STORE_DYN_BLK)
4307 lvl2 = gtSetEvalOrder(tree->gtDynBlk.Data());
4308 level = max(level, lvl2);
4309 costEx += tree->gtDynBlk.Data()->gtCostEx;
4310 costSz += tree->gtDynBlk.Data()->gtCostSz;
4312 lvl2 = gtSetEvalOrder(tree->gtDynBlk.Addr());
4313 level = max(level, lvl2);
4314 costEx = tree->gtDynBlk.Addr()->gtCostEx;
4315 costSz = tree->gtDynBlk.Addr()->gtCostSz;
4316 unsigned sizeLevel = gtSetEvalOrder(tree->gtDynBlk.gtDynamicSize);
4318 // Determine whether the size node should be evaluated first.
4319 // We would like to do this if the sizeLevel is larger than the current level,
4320 // but we have to ensure that we obey ordering constraints.
4321 if (tree->AsDynBlk()->gtEvalSizeFirst != (level < sizeLevel))
4323 bool canChange = true;
4325 GenTree* sizeNode = tree->AsDynBlk()->gtDynamicSize;
4326 GenTree* dst = tree->AsDynBlk()->Addr();
4327 GenTree* src = tree->AsDynBlk()->Data();
4329 if (tree->AsDynBlk()->gtEvalSizeFirst)
4331 canChange = gtCanSwapOrder(sizeNode, dst);
4332 if (canChange && (src != nullptr))
4334 canChange = gtCanSwapOrder(sizeNode, src);
4339 canChange = gtCanSwapOrder(dst, sizeNode);
4340 if (canChange && (src != nullptr))
4342 gtCanSwapOrder(src, sizeNode);
4347 tree->AsDynBlk()->gtEvalSizeFirst = (level < sizeLevel);
4350 level = max(level, sizeLevel);
4351 costEx += tree->gtDynBlk.gtDynamicSize->gtCostEx;
4352 costSz += tree->gtDynBlk.gtDynamicSize->gtCostSz;
4357 costEx = 6; // cmp reg,reg; jae throw; mov reg, [addrmode] (not taken)
4358 costSz = 9; // jump to cold section
4360 level = gtSetEvalOrder(tree->AsIndexAddr()->Index());
4361 costEx += tree->AsIndexAddr()->Index()->gtCostEx;
4362 costSz += tree->AsIndexAddr()->Index()->gtCostSz;
4364 lvl2 = gtSetEvalOrder(tree->AsIndexAddr()->Arr());
4369 costEx += tree->AsIndexAddr()->Arr()->gtCostEx;
4370 costSz += tree->AsIndexAddr()->Arr()->gtCostSz;
4377 printf("unexpected operator in this tree:\n");
4381 NO_WAY("unexpected operator");
4386 #ifdef FEATURE_HW_INTRINSICS
4387 if ((oper == GT_HWIntrinsic) && (tree->gtGetOp1() == nullptr))
4389 // We can have nullary HWIntrinsic nodes, and we must have non-zero cost.
4393 #endif // FEATURE_HW_INTRINSICS
4395 // Some path through this function must have set the costs.
4396 assert(costEx != -1);
4397 assert(costSz != -1);
4399 tree->SetCosts(costEx, costSz);
4404 #pragma warning(pop)
4407 /*****************************************************************************
4409 * If the given tree is an integer constant that can be used
4410 * in a scaled index address mode as a multiplier (e.g. "[4*index]"), then return
4411 * the scale factor: 2, 4, or 8. Otherwise, return 0. Note that we never return 1,
4412 * to match the behavior of GetScaleIndexShf().
4415 unsigned GenTree::GetScaleIndexMul()
4417 if (IsCnsIntOrI() && jitIsScaleIndexMul(gtIntConCommon.IconValue()) && gtIntConCommon.IconValue() != 1)
4419 return (unsigned)gtIntConCommon.IconValue();
4425 /*****************************************************************************
4427 * If the given tree is the right-hand side of a left shift (that is,
4428 * 'y' in the tree 'x' << 'y'), and it is an integer constant that can be used
4429 * in a scaled index address mode as a multiplier (e.g. "[4*index]"), then return
4430 * the scale factor: 2, 4, or 8. Otherwise, return 0.
4433 unsigned GenTree::GetScaleIndexShf()
4435 if (IsCnsIntOrI() && jitIsScaleIndexShift(gtIntConCommon.IconValue()))
4437 return (unsigned)(1 << gtIntConCommon.IconValue());
4443 /*****************************************************************************
4445 * If the given tree is a scaled index (i.e. "op * 4" or "op << 2"), returns
4446 * the multiplier: 2, 4, or 8; otherwise returns 0. Note that "1" is never
4450 unsigned GenTree::GetScaledIndex()
4452 // with (!opts.OptEnabled(CLFLG_CONSTANTFOLD) we can have
4453 // CNS_INT * CNS_INT
4455 if (gtOp.gtOp1->IsCnsIntOrI())
4463 return gtOp.gtOp2->GetScaleIndexMul();
4466 return gtOp.gtOp2->GetScaleIndexShf();
4469 assert(!"GenTree::GetScaledIndex() called with illegal gtOper");
4476 /*****************************************************************************
4478 * Returns true if "addr" is a GT_ADD node, at least one of whose arguments is an integer (<= 32 bit)
4479 * constant. If it returns true, it sets "*offset" to (one of the) constant value(s), and
4480 * "*addr" to the other argument.
4483 bool GenTree::IsAddWithI32Const(GenTree** addr, int* offset)
4485 if (OperGet() == GT_ADD)
4487 if (gtOp.gtOp1->IsIntCnsFitsInI32())
4489 *offset = (int)gtOp.gtOp1->gtIntCon.gtIconVal;
4493 else if (gtOp.gtOp2->IsIntCnsFitsInI32())
4495 *offset = (int)gtOp.gtOp2->gtIntCon.gtIconVal;
4504 //------------------------------------------------------------------------
4505 // gtGetChildPointer: If 'parent' is the parent of this node, return the pointer
4506 // to the child node so that it can be modified; otherwise, return nullptr.
4509 // parent - The possible parent of this node
4512 // If "child" is a child of "parent", returns a pointer to the child node in the parent
4513 // (i.e. a pointer to a GenTree pointer).
4514 // Otherwise, returns nullptr.
4517 // 'parent' must be non-null
4520 // When FEATURE_MULTIREG_ARGS is defined we can get here with GT_OBJ tree.
4521 // This happens when we have a struct that is passed in multiple registers.
4523 // Also note that when UNIX_AMD64_ABI is defined the GT_LDOBJ
4524 // later gets converted to a GT_FIELD_LIST with two GT_LCL_FLDs in Lower/LowerXArch.
4527 GenTree** GenTree::gtGetChildPointer(GenTree* parent) const
4530 switch (parent->OperGet())
4533 if (!parent->OperIsSimple())
4537 if (this == parent->gtOp.gtOp1)
4539 return &(parent->gtOp.gtOp1);
4541 if (this == parent->gtOp.gtOp2)
4543 return &(parent->gtOp.gtOp2);
4548 if (this == parent->gtCmpXchg.gtOpLocation)
4550 return &(parent->gtCmpXchg.gtOpLocation);
4552 if (this == parent->gtCmpXchg.gtOpValue)
4554 return &(parent->gtCmpXchg.gtOpValue);
4556 if (this == parent->gtCmpXchg.gtOpComparand)
4558 return &(parent->gtCmpXchg.gtOpComparand);
4562 case GT_ARR_BOUNDS_CHECK:
4565 #endif // FEATURE_SIMD
4566 #ifdef FEATURE_HW_INTRINSICS
4567 case GT_HW_INTRINSIC_CHK:
4568 #endif // FEATURE_HW_INTRINSICS
4569 if (this == parent->gtBoundsChk.gtIndex)
4571 return &(parent->gtBoundsChk.gtIndex);
4573 if (this == parent->gtBoundsChk.gtArrLen)
4575 return &(parent->gtBoundsChk.gtArrLen);
4577 if (this == parent->gtBoundsChk.gtIndRngFailBB)
4579 return &(parent->gtBoundsChk.gtIndRngFailBB);
4584 if (this == parent->gtArrElem.gtArrObj)
4586 return &(parent->gtArrElem.gtArrObj);
4588 for (int i = 0; i < GT_ARR_MAX_RANK; i++)
4590 if (this == parent->gtArrElem.gtArrInds[i])
4592 return &(parent->gtArrElem.gtArrInds[i]);
4598 if (this == parent->gtArrOffs.gtOffset)
4600 return &(parent->gtArrOffs.gtOffset);
4602 if (this == parent->gtArrOffs.gtIndex)
4604 return &(parent->gtArrOffs.gtIndex);
4606 if (this == parent->gtArrOffs.gtArrObj)
4608 return &(parent->gtArrOffs.gtArrObj);
4612 case GT_STORE_DYN_BLK:
4614 if (this == parent->gtDynBlk.gtOp1)
4616 return &(parent->gtDynBlk.gtOp1);
4618 if (this == parent->gtDynBlk.gtOp2)
4620 return &(parent->gtDynBlk.gtOp2);
4622 if (this == parent->gtDynBlk.gtDynamicSize)
4624 return &(parent->gtDynBlk.gtDynamicSize);
4629 if (this == parent->AsField()->gtFldObj)
4631 return &(parent->AsField()->gtFldObj);
4636 if (this == parent->gtRetExpr.gtInlineCandidate)
4638 return &(parent->gtRetExpr.gtInlineCandidate);
4644 GenTreeCall* call = parent->AsCall();
4646 if (this == call->gtCallObjp)
4648 return &(call->gtCallObjp);
4650 if (this == call->gtCallArgs)
4652 return reinterpret_cast<GenTree**>(&(call->gtCallArgs));
4654 if (this == call->gtCallLateArgs)
4656 return reinterpret_cast<GenTree**>(&(call->gtCallLateArgs));
4658 if (this == call->gtControlExpr)
4660 return &(call->gtControlExpr);
4662 if (call->gtCallType == CT_INDIRECT)
4664 if (this == call->gtCallCookie)
4666 return &(call->gtCallCookie);
4668 if (this == call->gtCallAddr)
4670 return &(call->gtCallAddr);
4677 noway_assert(!"Illegal node for gtGetChildPointer()");
4684 bool GenTree::TryGetUse(GenTree* def, GenTree*** use)
4686 assert(def != nullptr);
4687 assert(use != nullptr);
4694 case GT_LCL_VAR_ADDR:
4695 case GT_LCL_FLD_ADDR:
4704 case GT_MEMORYBARRIER:
4709 case GT_START_NONGC:
4711 #if !FEATURE_EH_FUNCLETS
4713 #endif // !FEATURE_EH_FUNCLETS
4717 case GT_CLS_VAR_ADDR:
4721 case GT_PINVOKE_PROLOG:
4722 case GT_PINVOKE_EPILOG:
4726 // Standard unary operators
4727 case GT_STORE_LCL_VAR:
4728 case GT_STORE_LCL_FLD:
4744 case GT_RUNTIMELOOKUP:
4757 if (def == this->AsUnOp()->gtOp1)
4759 *use = &this->AsUnOp()->gtOp1;
4766 assert(this->AsUnOp()->gtOp1 != nullptr);
4767 return this->AsUnOp()->gtOp1->TryGetUseList(def, use);
4770 return TryGetUseList(def, use);
4772 #if FEATURE_ARG_SPLIT
4773 case GT_PUTARG_SPLIT:
4774 if (this->AsUnOp()->gtOp1->gtOper == GT_FIELD_LIST)
4776 return this->AsUnOp()->gtOp1->TryGetUseList(def, use);
4778 if (def == this->AsUnOp()->gtOp1)
4780 *use = &this->AsUnOp()->gtOp1;
4784 #endif // FEATURE_ARG_SPLIT
4788 if (this->AsSIMD()->gtSIMDIntrinsicID == SIMDIntrinsicInitN)
4790 assert(this->AsSIMD()->gtOp1 != nullptr);
4791 return this->AsSIMD()->gtOp1->TryGetUseList(def, use);
4794 return TryGetUseBinOp(def, use);
4795 #endif // FEATURE_SIMD
4797 #ifdef FEATURE_HW_INTRINSICS
4798 case GT_HWIntrinsic:
4799 if ((this->AsHWIntrinsic()->gtOp1 != nullptr) && this->AsHWIntrinsic()->gtOp1->OperIsList())
4801 return this->AsHWIntrinsic()->gtOp1->TryGetUseList(def, use);
4804 return TryGetUseBinOp(def, use);
4805 #endif // FEATURE_HW_INTRINSICS
4810 GenTreeCmpXchg* const cmpXchg = this->AsCmpXchg();
4811 if (def == cmpXchg->gtOpLocation)
4813 *use = &cmpXchg->gtOpLocation;
4816 if (def == cmpXchg->gtOpValue)
4818 *use = &cmpXchg->gtOpValue;
4821 if (def == cmpXchg->gtOpComparand)
4823 *use = &cmpXchg->gtOpComparand;
4829 case GT_ARR_BOUNDS_CHECK:
4832 #endif // FEATURE_SIMD
4833 #ifdef FEATURE_HW_INTRINSICS
4834 case GT_HW_INTRINSIC_CHK:
4835 #endif // FEATURE_HW_INTRINSICS
4837 GenTreeBoundsChk* const boundsChk = this->AsBoundsChk();
4838 if (def == boundsChk->gtIndex)
4840 *use = &boundsChk->gtIndex;
4843 if (def == boundsChk->gtArrLen)
4845 *use = &boundsChk->gtArrLen;
4852 if (def == this->AsField()->gtFldObj)
4854 *use = &this->AsField()->gtFldObj;
4860 if (def == this->AsStmt()->gtStmtExpr)
4862 *use = &this->AsStmt()->gtStmtExpr;
4869 GenTreeArrElem* const arrElem = this->AsArrElem();
4870 if (def == arrElem->gtArrObj)
4872 *use = &arrElem->gtArrObj;
4875 for (unsigned i = 0; i < arrElem->gtArrRank; i++)
4877 if (def == arrElem->gtArrInds[i])
4879 *use = &arrElem->gtArrInds[i];
4888 GenTreeArrOffs* const arrOffs = this->AsArrOffs();
4889 if (def == arrOffs->gtOffset)
4891 *use = &arrOffs->gtOffset;
4894 if (def == arrOffs->gtIndex)
4896 *use = &arrOffs->gtIndex;
4899 if (def == arrOffs->gtArrObj)
4901 *use = &arrOffs->gtArrObj;
4909 GenTreeDynBlk* const dynBlock = this->AsDynBlk();
4910 if (def == dynBlock->gtOp1)
4912 *use = &dynBlock->gtOp1;
4915 if (def == dynBlock->gtDynamicSize)
4917 *use = &dynBlock->gtDynamicSize;
4923 case GT_STORE_DYN_BLK:
4925 GenTreeDynBlk* const dynBlock = this->AsDynBlk();
4926 if (def == dynBlock->gtOp1)
4928 *use = &dynBlock->gtOp1;
4931 if (def == dynBlock->gtOp2)
4933 *use = &dynBlock->gtOp2;
4936 if (def == dynBlock->gtDynamicSize)
4938 *use = &dynBlock->gtDynamicSize;
4946 GenTreeCall* const call = this->AsCall();
4947 if (def == call->gtCallObjp)
4949 *use = &call->gtCallObjp;
4952 if (def == call->gtControlExpr)
4954 *use = &call->gtControlExpr;
4957 if (call->gtCallType == CT_INDIRECT)
4959 if (def == call->gtCallCookie)
4961 *use = &call->gtCallCookie;
4964 if (def == call->gtCallAddr)
4966 *use = &call->gtCallAddr;
4970 if ((call->gtCallArgs != nullptr) && call->gtCallArgs->TryGetUseList(def, use))
4975 return (call->gtCallLateArgs != nullptr) && call->gtCallLateArgs->TryGetUseList(def, use);
4980 assert(this->OperIsBinary());
4981 return TryGetUseBinOp(def, use);
4985 bool GenTree::TryGetUseList(GenTree* def, GenTree*** use)
4987 assert(def != nullptr);
4988 assert(use != nullptr);
4990 for (GenTreeArgList* node = this->AsArgList(); node != nullptr; node = node->Rest())
4992 if (def == node->gtOp1)
4994 *use = &node->gtOp1;
5001 bool GenTree::TryGetUseBinOp(GenTree* def, GenTree*** use)
5003 assert(def != nullptr);
5004 assert(use != nullptr);
5005 assert(this->OperIsBinary());
5007 GenTreeOp* const binOp = this->AsOp();
5008 if (def == binOp->gtOp1)
5010 *use = &binOp->gtOp1;
5013 if (def == binOp->gtOp2)
5015 *use = &binOp->gtOp2;
5021 //------------------------------------------------------------------------
5022 // GenTree::ReplaceOperand:
5023 // Replace a given operand to this node with a new operand. If the
5024 // current node is a call node, this will also udpate the call
5025 // argument table if necessary.
5028 // useEdge - the use edge that points to the operand to be replaced.
5029 // replacement - the replacement node.
5031 void GenTree::ReplaceOperand(GenTree** useEdge, GenTree* replacement)
5033 assert(useEdge != nullptr);
5034 assert(replacement != nullptr);
5035 assert(TryGetUse(*useEdge, &useEdge));
5037 if (OperGet() == GT_CALL)
5039 AsCall()->ReplaceCallOperand(useEdge, replacement);
5043 *useEdge = replacement;
5047 //------------------------------------------------------------------------
5048 // gtGetParent: Get the parent of this node, and optionally capture the
5049 // pointer to the child so that it can be modified.
5053 // parentChildPointer - A pointer to a GenTree** (yes, that's three
5054 // levels, i.e. GenTree ***), which if non-null,
5055 // will be set to point to the field in the parent
5056 // that points to this node.
5058 // Return value - The parent of this node.
5062 // This requires that the execution order must be defined (i.e. gtSetEvalOrder() has been called).
5063 // To enable the child to be replaced, it accepts an argument, parentChildPointer that, if non-null,
5064 // will be set to point to the child pointer in the parent that points to this node.
5066 GenTree* GenTree::gtGetParent(GenTree*** parentChildPtrPtr) const
5068 // Find the parent node; it must be after this node in the execution order.
5069 GenTree** parentChildPtr = nullptr;
5071 for (parent = gtNext; parent != nullptr; parent = parent->gtNext)
5073 parentChildPtr = gtGetChildPointer(parent);
5074 if (parentChildPtr != nullptr)
5079 if (parentChildPtrPtr != nullptr)
5081 *parentChildPtrPtr = parentChildPtr;
5086 //------------------------------------------------------------------------------
5087 // OperRequiresAsgFlag : Check whether the operation requires GTF_ASG flag regardless
5088 // of the children's flags.
5091 bool GenTree::OperRequiresAsgFlag()
5093 if (OperIs(GT_ASG) || OperIs(GT_XADD, GT_XCHG, GT_LOCKADD, GT_CMPXCHG, GT_MEMORYBARRIER))
5097 #ifdef FEATURE_HW_INTRINSICS
5098 if (gtOper == GT_HWIntrinsic)
5100 GenTreeHWIntrinsic* hwIntrinsicNode = this->AsHWIntrinsic();
5101 if (hwIntrinsicNode->OperIsMemoryStore())
5103 // A MemoryStore operation is an assignment
5107 #endif // FEATURE_HW_INTRINSICS
5111 //------------------------------------------------------------------------------
5112 // OperRequiresCallFlag : Check whether the operation requires GTF_CALL flag regardless
5113 // of the children's flags.
5116 bool GenTree::OperRequiresCallFlag(Compiler* comp)
5124 return comp->IsIntrinsicImplementedByUserCall(this->AsIntrinsic()->gtIntrinsicId);
5126 #if FEATURE_FIXED_OUT_ARGS && !defined(_TARGET_64BIT_)
5131 // Variable shifts of a long end up being helper calls, so mark the tree as such in morph.
5132 // This is potentially too conservative, since they'll get treated as having side effects.
5133 // It is important to mark them as calls so if they are part of an argument list,
5134 // they will get sorted and processed properly (for example, it is important to handle
5135 // all nested calls before putting struct arguments in the argument registers). We
5136 // could mark the trees just before argument processing, but it would require a full
5137 // tree walk of the argument tree, so we just do it when morphing, instead, even though we'll
5138 // mark non-argument trees (that will still get converted to calls, anyway).
5139 return (this->TypeGet() == TYP_LONG) && (gtGetOp2()->OperGet() != GT_CNS_INT);
5140 #endif // FEATURE_FIXED_OUT_ARGS && !_TARGET_64BIT_
5147 //------------------------------------------------------------------------------
5148 // OperIsImplicitIndir : Check whether the operation contains an implicit
5151 // this - a GenTree node
5154 // True if the given node contains an implicit indirection
5156 // Note that for the GT_HWIntrinsic node we have to examine the
5157 // details of the node to determine its result.
5160 bool GenTree::OperIsImplicitIndir() const
5173 case GT_STORE_DYN_BLK:
5179 #ifdef FEATURE_HW_INTRINSICS
5180 case GT_HWIntrinsic:
5182 GenTreeHWIntrinsic* hwIntrinsicNode = (const_cast<GenTree*>(this))->AsHWIntrinsic();
5183 return hwIntrinsicNode->OperIsMemoryLoadOrStore();
5185 #endif // FEATURE_HW_INTRINSICS
5191 //------------------------------------------------------------------------------
5192 // OperMayThrow : Check whether the operation may throw.
5196 // comp - Compiler instance
5199 // True if the given operator may cause an exception
5201 bool GenTree::OperMayThrow(Compiler* comp)
5212 /* Division with a non-zero, non-minus-one constant does not throw an exception */
5216 if (varTypeIsFloating(op->TypeGet()))
5218 return false; // Floating point division does not throw.
5221 // For integers only division by 0 or by -1 can throw
5222 if (op->IsIntegralConst() && !op->IsIntegralConst(0) && !op->IsIntegralConst(-1))
5229 // If this is an intrinsic that represents the object.GetType(), it can throw an NullReferenceException.
5230 // Report it as may throw.
5231 // Note: Some of the rest of the existing intrinsics could potentially throw an exception (for example
5232 // the array and string element access ones). They are handled differently than the GetType intrinsic
5233 // and are not marked with GTF_EXCEPT. If these are revisited at some point to be marked as
5235 // the code below might need to be specialized to handle them properly.
5236 if ((this->gtFlags & GTF_EXCEPT) != 0)
5245 CorInfoHelpFunc helper;
5246 helper = comp->eeGetHelperNum(this->AsCall()->gtCallMethHnd);
5247 return ((helper == CORINFO_HELP_UNDEF) || !comp->s_helperCallProperties.NoThrow(helper));
5255 return (((this->gtFlags & GTF_IND_NONFAULTING) == 0) && comp->fgAddrCouldBeNull(this->AsIndir()->Addr()));
5258 return (((this->gtFlags & GTF_IND_NONFAULTING) == 0) &&
5259 comp->fgAddrCouldBeNull(this->AsArrLen()->ArrRef()));
5262 return comp->fgAddrCouldBeNull(this->gtArrElem.gtArrObj);
5264 case GT_ARR_BOUNDS_CHECK:
5271 #endif // FEATURE_SIMD
5272 #ifdef FEATURE_HW_INTRINSICS
5273 case GT_HW_INTRINSIC_CHK:
5274 #endif // FEATURE_HW_INTRINSICS
5278 #ifdef FEATURE_HW_INTRINSICS
5279 case GT_HWIntrinsic:
5281 GenTreeHWIntrinsic* hwIntrinsicNode = this->AsHWIntrinsic();
5282 assert(hwIntrinsicNode != nullptr);
5283 if (hwIntrinsicNode->OperIsMemoryLoadOrStore())
5285 // This operation contains an implicit indirection
5286 // it could throw a null reference exception.
5291 #endif // FEATURE_HW_INTRINSICS
5297 /* Overflow arithmetic operations also throw exceptions */
5307 #if DEBUGGABLE_GENTREE
5309 GenTree::VtablePtr GenTree::s_vtablesForOpers[] = {nullptr};
5310 GenTree::VtablePtr GenTree::s_vtableForOp = nullptr;
5312 GenTree::VtablePtr GenTree::GetVtableForOper(genTreeOps oper)
5314 noway_assert(oper < GT_COUNT);
5316 // First, check a cache.
5318 if (s_vtablesForOpers[oper] != nullptr)
5320 return s_vtablesForOpers[oper];
5323 // Otherwise, look up the correct vtable entry. Note that we want the most derived GenTree subtype
5324 // for an oper. E.g., GT_LCL_VAR is defined in GTSTRUCT_3 as GenTreeLclVar and in GTSTRUCT_N as
5325 // GenTreeLclVarCommon. We want the GenTreeLclVar vtable, since nothing should actually be
5326 // instantiated as a GenTreeLclVarCommon.
5328 VtablePtr res = nullptr;
5334 #define GTSTRUCT_0(nm, tag) /*handle explicitly*/
5335 #define GTSTRUCT_1(nm, tag) \
5339 res = *reinterpret_cast<VtablePtr*>(>); \
5342 #define GTSTRUCT_2(nm, tag, tag2) \
5347 res = *reinterpret_cast<VtablePtr*>(>); \
5350 #define GTSTRUCT_3(nm, tag, tag2, tag3) \
5356 res = *reinterpret_cast<VtablePtr*>(>); \
5359 #define GTSTRUCT_4(nm, tag, tag2, tag3, tag4) \
5366 res = *reinterpret_cast<VtablePtr*>(>); \
5369 #define GTSTRUCT_N(nm, ...) /*handle explicitly*/
5370 #define GTSTRUCT_2_SPECIAL(nm, tag, tag2) /*handle explicitly*/
5371 #define GTSTRUCT_3_SPECIAL(nm, tag, tag2, tag3) /*handle explicitly*/
5372 #include "gtstructs.h"
5376 // Handle the special cases.
5377 // The following opers are in GTSTRUCT_N but no other place (namely, no subtypes).
5383 res = *reinterpret_cast<VtablePtr*>(>);
5391 res = *reinterpret_cast<VtablePtr*>(>);
5395 // Handle GT_LIST (but not GT_FIELD_LIST, which is also in a GTSTRUCT_1).
5400 res = *reinterpret_cast<VtablePtr*>(>);
5404 // We don't need to handle GTSTRUCT_N for LclVarCommon, since all those allowed opers are specified
5405 // in their proper subtype. Similarly for GenTreeIndir.
5409 // Should be unary or binary op.
5410 if (s_vtableForOp == nullptr)
5412 unsigned opKind = OperKind(oper);
5413 assert(!IsExOp(opKind));
5414 assert(OperIsSimple(oper) || OperIsLeaf(oper));
5415 // Need to provide non-null operands.
5416 GenTreeIntCon dummyOp(TYP_INT, 0);
5417 GenTreeOp gt(oper, TYP_INT, &dummyOp, ((opKind & GTK_UNOP) ? nullptr : &dummyOp));
5418 s_vtableForOp = *reinterpret_cast<VtablePtr*>(>);
5420 res = s_vtableForOp;
5424 s_vtablesForOpers[oper] = res;
5428 void GenTree::SetVtableForOper(genTreeOps oper)
5430 *reinterpret_cast<VtablePtr*>(this) = GetVtableForOper(oper);
5432 #endif // DEBUGGABLE_GENTREE
5434 GenTree* Compiler::gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, GenTree* op2)
5436 assert(op1 != nullptr);
5437 assert(op2 != nullptr);
5439 // We should not be allocating nodes that extend GenTreeOp with this;
5440 // should call the appropriate constructor for the extended type.
5441 assert(!GenTree::IsExOp(GenTree::OperKind(oper)));
5443 GenTree* node = new (this, oper) GenTreeOp(oper, type, op1, op2);
5448 GenTree* Compiler::gtNewQmarkNode(var_types type, GenTree* cond, GenTree* colon)
5450 compQmarkUsed = true;
5451 cond->gtFlags |= GTF_RELOP_QMARK;
5452 GenTree* result = new (this, GT_QMARK) GenTreeQmark(type, cond, colon, this);
5454 if (compQmarkRationalized)
5456 fgCheckQmarkAllowedForm(result);
5462 GenTreeQmark::GenTreeQmark(var_types type, GenTree* cond, GenTree* colonOp, Compiler* comp)
5463 : GenTreeOp(GT_QMARK, type, cond, colonOp)
5465 // These must follow a specific form.
5466 assert(cond != nullptr && cond->TypeGet() == TYP_INT);
5467 assert(colonOp != nullptr && colonOp->OperGet() == GT_COLON);
5470 GenTreeIntCon* Compiler::gtNewIconNode(ssize_t value, var_types type)
5472 return new (this, GT_CNS_INT) GenTreeIntCon(type, value);
5475 // return a new node representing the value in a physical register
5476 GenTree* Compiler::gtNewPhysRegNode(regNumber reg, var_types type)
5478 assert(genIsValidIntReg(reg) || (reg == REG_SPBASE));
5479 GenTree* result = new (this, GT_PHYSREG) GenTreePhysReg(reg, type);
5483 GenTree* Compiler::gtNewJmpTableNode()
5485 GenTree* node = new (this, GT_JMPTABLE) GenTreeJumpTable(TYP_INT);
5486 node->gtJumpTable.gtJumpTableAddr = 0;
5490 /*****************************************************************************
5492 * Converts an annotated token into an icon flags (so that we will later be
5493 * able to tell the type of the handle that will be embedded in the icon
5497 unsigned Compiler::gtTokenToIconFlags(unsigned token)
5501 switch (TypeFromToken(token))
5506 flags = GTF_ICON_CLASS_HDL;
5510 flags = GTF_ICON_METHOD_HDL;
5514 flags = GTF_ICON_FIELD_HDL;
5518 flags = GTF_ICON_TOKEN_HDL;
5525 //-----------------------------------------------------------------------------------------
5526 // gtNewIndOfIconHandleNode: Creates an indirection GenTree node of a constant handle
5529 // indType - The type returned by the indirection node
5530 // addr - The constant address to read from
5531 // iconFlags - The GTF_ICON flag value that specifies the kind of handle that we have
5532 // isInvariant - The indNode should also be marked as invariant
5535 // Returns a GT_IND node representing value at the address provided by 'value'
5538 // The GT_IND node is marked as non-faulting
5539 // If the indType is GT_REF we also mark the indNode as GTF_GLOB_REF
5542 GenTree* Compiler::gtNewIndOfIconHandleNode(var_types indType, size_t addr, unsigned iconFlags, bool isInvariant)
5544 GenTree* addrNode = gtNewIconHandleNode(addr, iconFlags);
5545 GenTree* indNode = gtNewOperNode(GT_IND, indType, addrNode);
5547 // This indirection won't cause an exception.
5549 indNode->gtFlags |= GTF_IND_NONFAULTING;
5551 // String Literal handles are indirections that return a TYP_REF.
5552 // They are pointers into the GC heap and they are not invariant
5553 // as the address is a reportable GC-root and as such it can be
5554 // modified during a GC collection
5556 if (indType == TYP_REF)
5558 // This indirection points into the gloabal heap
5559 indNode->gtFlags |= GTF_GLOB_REF;
5563 // This indirection also is invariant.
5564 indNode->gtFlags |= GTF_IND_INVARIANT;
5569 /*****************************************************************************
5571 * Allocates a integer constant entry that represents a HANDLE to something.
5572 * It may not be allowed to embed HANDLEs directly into the JITed code (for eg,
5573 * as arguments to JIT helpers). Get a corresponding value that can be embedded.
5574 * If the handle needs to be accessed via an indirection, pValue points to it.
5577 GenTree* Compiler::gtNewIconEmbHndNode(void* value, void* pValue, unsigned iconFlags, void* compileTimeHandle)
5580 GenTree* handleNode;
5582 if (value != nullptr)
5584 // When 'value' is non-null, pValue is required to be null
5585 assert(pValue == nullptr);
5587 // use 'value' to construct an integer constant node
5588 iconNode = gtNewIconHandleNode((size_t)value, iconFlags);
5590 // 'value' is the handle
5591 handleNode = iconNode;
5595 // When 'value' is null, pValue is required to be non-null
5596 assert(pValue != nullptr);
5598 // use 'pValue' to construct an integer constant node
5599 iconNode = gtNewIconHandleNode((size_t)pValue, iconFlags);
5601 // 'pValue' is an address of a location that contains the handle
5603 // construct the indirection of 'pValue'
5604 handleNode = gtNewOperNode(GT_IND, TYP_I_IMPL, iconNode);
5606 // This indirection won't cause an exception.
5607 handleNode->gtFlags |= GTF_IND_NONFAULTING;
5609 // It should also be invariant, but marking it as such leads to bad diffs.
5611 // This indirection also is invariant.
5612 handleNode->gtFlags |= GTF_IND_INVARIANT;
5616 iconNode->gtIntCon.gtCompileTimeHandle = (size_t)compileTimeHandle;
5621 /*****************************************************************************/
5622 GenTree* Compiler::gtNewStringLiteralNode(InfoAccessType iat, void* pValue)
5624 GenTree* tree = nullptr;
5628 case IAT_VALUE: // constructStringLiteral in CoreRT case can return IAT_VALUE
5629 tree = gtNewIconEmbHndNode(pValue, nullptr, GTF_ICON_STR_HDL, nullptr);
5630 tree->gtType = TYP_REF;
5631 tree = gtNewOperNode(GT_NOP, TYP_REF, tree); // prevents constant folding
5634 case IAT_PVALUE: // The value needs to be accessed via an indirection
5635 // Create an indirection
5636 tree = gtNewIndOfIconHandleNode(TYP_REF, (size_t)pValue, GTF_ICON_STR_HDL, false);
5639 case IAT_PPVALUE: // The value needs to be accessed via a double indirection
5640 // Create the first indirection
5641 tree = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)pValue, GTF_ICON_PSTR_HDL, true);
5643 // Create the second indirection
5644 tree = gtNewOperNode(GT_IND, TYP_REF, tree);
5645 // This indirection won't cause an exception.
5646 tree->gtFlags |= GTF_IND_NONFAULTING;
5647 // This indirection points into the gloabal heap (it is String Object)
5648 tree->gtFlags |= GTF_GLOB_REF;
5652 noway_assert(!"Unexpected InfoAccessType");
5658 /*****************************************************************************/
5660 GenTree* Compiler::gtNewLconNode(__int64 value)
5662 #ifdef _TARGET_64BIT_
5663 GenTree* node = new (this, GT_CNS_INT) GenTreeIntCon(TYP_LONG, value);
5665 GenTree* node = new (this, GT_CNS_LNG) GenTreeLngCon(value);
5671 GenTree* Compiler::gtNewDconNode(double value)
5673 GenTree* node = new (this, GT_CNS_DBL) GenTreeDblCon(value);
5678 GenTree* Compiler::gtNewSconNode(int CPX, CORINFO_MODULE_HANDLE scpHandle)
5681 #if SMALL_TREE_NODES
5683 /* 'GT_CNS_STR' nodes later get transformed into 'GT_CALL' */
5685 assert(GenTree::s_gtNodeSizes[GT_CALL] > GenTree::s_gtNodeSizes[GT_CNS_STR]);
5687 GenTree* node = new (this, GT_CALL) GenTreeStrCon(CPX, scpHandle DEBUGARG(/*largeNode*/ true));
5689 GenTree* node = new (this, GT_CNS_STR) GenTreeStrCon(CPX, scpHandle DEBUGARG(/*largeNode*/ true));
5695 GenTree* Compiler::gtNewZeroConNode(var_types type)
5701 zero = gtNewIconNode(0);
5708 zero = gtNewIconNode(0);
5709 zero->gtType = type;
5713 zero = gtNewLconNode(0);
5717 zero = gtNewDconNode(0.0);
5718 zero->gtType = type;
5722 zero = gtNewDconNode(0.0);
5726 noway_assert(!"Bad type in gtNewZeroConNode");
5733 GenTree* Compiler::gtNewOneConNode(var_types type)
5740 one = gtNewIconNode(1);
5745 one = gtNewLconNode(1);
5750 one = gtNewDconNode(1.0);
5755 noway_assert(!"Bad type in gtNewOneConNode");
5763 //---------------------------------------------------------------------
5764 // gtNewSIMDVectorZero: create a GT_SIMD node for Vector<T>.Zero
5767 // simdType - simd vector type
5768 // baseType - element type of vector
5769 // size - size of vector in bytes
5770 GenTree* Compiler::gtNewSIMDVectorZero(var_types simdType, var_types baseType, unsigned size)
5772 baseType = genActualType(baseType);
5773 GenTree* initVal = gtNewZeroConNode(baseType);
5774 initVal->gtType = baseType;
5775 return gtNewSIMDNode(simdType, initVal, nullptr, SIMDIntrinsicInit, baseType, size);
5778 //---------------------------------------------------------------------
5779 // gtNewSIMDVectorOne: create a GT_SIMD node for Vector<T>.One
5782 // simdType - simd vector type
5783 // baseType - element type of vector
5784 // size - size of vector in bytes
5785 GenTree* Compiler::gtNewSIMDVectorOne(var_types simdType, var_types baseType, unsigned size)
5788 if (varTypeIsSmallInt(baseType))
5790 unsigned baseSize = genTypeSize(baseType);
5800 initVal = gtNewIconNode(val);
5804 initVal = gtNewOneConNode(baseType);
5807 baseType = genActualType(baseType);
5808 initVal->gtType = baseType;
5809 return gtNewSIMDNode(simdType, initVal, nullptr, SIMDIntrinsicInit, baseType, size);
5811 #endif // FEATURE_SIMD
5813 GenTreeCall* Compiler::gtNewIndCallNode(GenTree* addr, var_types type, GenTreeArgList* args, IL_OFFSETX ilOffset)
5815 return gtNewCallNode(CT_INDIRECT, (CORINFO_METHOD_HANDLE)addr, type, args, ilOffset);
5818 GenTreeCall* Compiler::gtNewCallNode(
5819 gtCallTypes callType, CORINFO_METHOD_HANDLE callHnd, var_types type, GenTreeArgList* args, IL_OFFSETX ilOffset)
5821 GenTreeCall* node = new (this, GT_CALL) GenTreeCall(genActualType(type));
5823 node->gtFlags |= (GTF_CALL | GTF_GLOB_REF);
5826 node->gtFlags |= (args->gtFlags & GTF_ALL_EFFECT);
5828 node->gtCallType = callType;
5829 node->gtCallMethHnd = callHnd;
5830 node->gtCallArgs = args;
5831 node->gtCallObjp = nullptr;
5832 node->fgArgInfo = nullptr;
5833 node->callSig = nullptr;
5834 node->gtRetClsHnd = nullptr;
5835 node->gtControlExpr = nullptr;
5836 node->gtCallMoreFlags = 0;
5838 if (callType == CT_INDIRECT)
5840 node->gtCallCookie = nullptr;
5844 node->gtInlineCandidateInfo = nullptr;
5846 node->gtCallLateArgs = nullptr;
5847 node->gtReturnType = type;
5849 #ifdef FEATURE_READYTORUN_COMPILER
5850 node->gtEntryPoint.addr = nullptr;
5851 node->gtEntryPoint.accessType = IAT_VALUE;
5854 #if defined(DEBUG) || defined(INLINE_DATA)
5855 // These get updated after call node is built.
5856 node->gtInlineObservation = InlineObservation::CALLEE_UNUSED_INITIAL;
5857 node->gtRawILOffset = BAD_IL_OFFSET;
5860 // Spec: Managed Retval sequence points needs to be generated while generating debug info for debuggable code.
5862 // Implementation note: if not generating MRV info genCallSite2ILOffsetMap will be NULL and
5863 // codegen will pass BAD_IL_OFFSET as IL offset of a call node to emitter, which will cause emitter
5864 // not to emit IP mapping entry.
5865 if (opts.compDbgCode && opts.compDbgInfo)
5867 // Managed Retval - IL offset of the call. This offset is used to emit a
5868 // CALL_INSTRUCTION type sequence point while emitting corresponding native call.
5871 // a) (Opt) We need not store this offset if the method doesn't return a
5872 // value. Rather it can be made BAD_IL_OFFSET to prevent a sequence
5873 // point being emitted.
5875 // b) (Opt) Add new sequence points only if requested by debugger through
5876 // a new boundary type - ICorDebugInfo::BoundaryTypes
5877 if (genCallSite2ILOffsetMap == nullptr)
5879 genCallSite2ILOffsetMap = new (getAllocator()) CallSiteILOffsetTable(getAllocator());
5882 // Make sure that there are no duplicate entries for a given call node
5883 assert(!genCallSite2ILOffsetMap->Lookup(node));
5884 genCallSite2ILOffsetMap->Set(node, ilOffset);
5887 // Initialize gtOtherRegs
5888 node->ClearOtherRegs();
5890 // Initialize spill flags of gtOtherRegs
5891 node->ClearOtherRegFlags();
5893 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
5894 // Initialize the multi-reg long return info if necessary
5895 if (varTypeIsLong(node))
5897 // The return type will remain as the incoming long type
5898 node->gtReturnType = node->gtType;
5900 // Initialize Return type descriptor of call node
5901 ReturnTypeDesc* retTypeDesc = node->GetReturnTypeDesc();
5902 retTypeDesc->InitializeLongReturnType(this);
5904 // must be a long returned in two registers
5905 assert(retTypeDesc->GetReturnRegCount() == 2);
5907 #endif // defined(_TARGET_X86_) || defined(_TARGET_ARM_)
5912 GenTree* Compiler::gtNewLclvNode(unsigned lnum, var_types type, IL_OFFSETX ILoffs)
5914 // We need to ensure that all struct values are normalized.
5915 // It might be nice to assert this in general, but we have assignments of int to long.
5916 if (varTypeIsStruct(type))
5918 // Make an exception for implicit by-ref parameters during global morph, since
5919 // their lvType has been updated to byref but their appearances have not yet all
5920 // been rewritten and so may have struct type still.
5921 assert(type == lvaTable[lnum].lvType ||
5922 (lvaIsImplicitByRefLocal(lnum) && fgGlobalMorph && (lvaTable[lnum].lvType == TYP_BYREF)));
5924 GenTree* node = new (this, GT_LCL_VAR) GenTreeLclVar(type, lnum, ILoffs);
5926 /* Cannot have this assert because the inliner uses this function
5927 * to add temporaries */
5929 // assert(lnum < lvaCount);
5934 GenTree* Compiler::gtNewLclLNode(unsigned lnum, var_types type, IL_OFFSETX ILoffs)
5936 // We need to ensure that all struct values are normalized.
5937 // It might be nice to assert this in general, but we have assignments of int to long.
5938 if (varTypeIsStruct(type))
5940 // Make an exception for implicit by-ref parameters during global morph, since
5941 // their lvType has been updated to byref but their appearances have not yet all
5942 // been rewritten and so may have struct type still.
5943 assert(type == lvaTable[lnum].lvType ||
5944 (lvaIsImplicitByRefLocal(lnum) && fgGlobalMorph && (lvaTable[lnum].lvType == TYP_BYREF)));
5946 #if SMALL_TREE_NODES
5947 /* This local variable node may later get transformed into a large node */
5949 // assert(GenTree::s_gtNodeSizes[GT_CALL] > GenTree::s_gtNodeSizes[GT_LCL_VAR]);
5951 GenTree* node = new (this, GT_CALL) GenTreeLclVar(type, lnum, ILoffs DEBUGARG(/*largeNode*/ true));
5953 GenTree* node = new (this, GT_LCL_VAR) GenTreeLclVar(type, lnum, ILoffs DEBUGARG(/*largeNode*/ true));
5959 GenTreeLclFld* Compiler::gtNewLclFldNode(unsigned lnum, var_types type, unsigned offset)
5961 GenTreeLclFld* node = new (this, GT_LCL_FLD) GenTreeLclFld(type, lnum, offset);
5963 /* Cannot have this assert because the inliner uses this function
5964 * to add temporaries */
5966 // assert(lnum < lvaCount);
5968 node->gtFieldSeq = FieldSeqStore::NotAField();
5972 GenTree* Compiler::gtNewInlineCandidateReturnExpr(GenTree* inlineCandidate, var_types type)
5975 assert(GenTree::s_gtNodeSizes[GT_RET_EXPR] == TREE_NODE_SZ_LARGE);
5977 GenTree* node = new (this, GT_RET_EXPR) GenTreeRetExpr(type);
5979 node->gtRetExpr.gtInlineCandidate = inlineCandidate;
5981 if (varTypeIsStruct(inlineCandidate) && !inlineCandidate->OperIsBlkOp())
5983 node->gtRetExpr.gtRetClsHnd = gtGetStructHandle(inlineCandidate);
5986 // GT_RET_EXPR node eventually might be bashed back to GT_CALL (when inlining is aborted for example).
5987 // Therefore it should carry the GTF_CALL flag so that all the rules about spilling can apply to it as well.
5988 // For example, impImportLeave or CEE_POP need to spill GT_RET_EXPR before empty the evaluation stack.
5989 node->gtFlags |= GTF_CALL;
5994 GenTreeArgList* Compiler::gtNewListNode(GenTree* op1, GenTreeArgList* op2)
5996 assert((op1 != nullptr) && (op1->OperGet() != GT_LIST));
5998 return new (this, GT_LIST) GenTreeArgList(op1, op2);
6001 /*****************************************************************************
6003 * Create a list out of one value.
6006 GenTreeArgList* Compiler::gtNewArgList(GenTree* arg)
6008 return new (this, GT_LIST) GenTreeArgList(arg);
6011 /*****************************************************************************
6013 * Create a list out of the two values.
6016 GenTreeArgList* Compiler::gtNewArgList(GenTree* arg1, GenTree* arg2)
6018 return new (this, GT_LIST) GenTreeArgList(arg1, gtNewArgList(arg2));
6021 /*****************************************************************************
6023 * Create a list out of the three values.
6026 GenTreeArgList* Compiler::gtNewArgList(GenTree* arg1, GenTree* arg2, GenTree* arg3)
6028 return new (this, GT_LIST) GenTreeArgList(arg1, gtNewArgList(arg2, arg3));
6031 /*****************************************************************************
6033 * Create a list out of the three values.
6036 GenTreeArgList* Compiler::gtNewArgList(GenTree* arg1, GenTree* arg2, GenTree* arg3, GenTree* arg4)
6038 return new (this, GT_LIST) GenTreeArgList(arg1, gtNewArgList(arg2, arg3, arg4));
6041 /*****************************************************************************
6043 * Given a GT_CALL node, access the fgArgInfo and find the entry
6044 * that has the matching argNum and return the fgArgTableEntryPtr
6047 fgArgTabEntry* Compiler::gtArgEntryByArgNum(GenTreeCall* call, unsigned argNum)
6049 fgArgInfo* argInfo = call->fgArgInfo;
6050 noway_assert(argInfo != nullptr);
6051 return argInfo->GetArgEntry(argNum);
6054 /*****************************************************************************
6056 * Given a GT_CALL node, access the fgArgInfo and find the entry
6057 * that has the matching node and return the fgArgTableEntryPtr
6060 fgArgTabEntry* Compiler::gtArgEntryByNode(GenTreeCall* call, GenTree* node)
6062 fgArgInfo* argInfo = call->fgArgInfo;
6063 noway_assert(argInfo != nullptr);
6065 unsigned argCount = argInfo->ArgCount();
6066 fgArgTabEntry** argTable = argInfo->ArgTable();
6067 fgArgTabEntry* curArgTabEntry = nullptr;
6069 for (unsigned i = 0; i < argCount; i++)
6071 curArgTabEntry = argTable[i];
6073 if (curArgTabEntry->node == node)
6075 return curArgTabEntry;
6077 else if (curArgTabEntry->parent != nullptr)
6079 assert(curArgTabEntry->parent->OperIsList());
6080 if (curArgTabEntry->parent->Current() == node)
6082 return curArgTabEntry;
6085 else // (curArgTabEntry->parent == NULL)
6087 if (call->gtCallObjp == node)
6089 return curArgTabEntry;
6093 noway_assert(!"gtArgEntryByNode: node not found");
6097 /*****************************************************************************
6099 * Find and return the entry with the given "lateArgInx". Requires that one is found
6102 fgArgTabEntry* Compiler::gtArgEntryByLateArgIndex(GenTreeCall* call, unsigned lateArgInx)
6104 fgArgInfo* argInfo = call->fgArgInfo;
6105 noway_assert(argInfo != nullptr);
6106 assert(lateArgInx != UINT_MAX);
6108 unsigned argCount = argInfo->ArgCount();
6109 fgArgTabEntry** argTable = argInfo->ArgTable();
6110 fgArgTabEntry* curArgTabEntry = nullptr;
6112 for (unsigned i = 0; i < argCount; i++)
6114 curArgTabEntry = argTable[i];
6115 if (curArgTabEntry->isLateArg() && curArgTabEntry->lateArgInx == lateArgInx)
6117 return curArgTabEntry;
6120 noway_assert(!"gtArgEntryByNode: node not found");
6124 //------------------------------------------------------------------------
6125 // gtArgNodeByLateArgInx: Given a call instruction, find the argument with the given
6126 // late arg index (i.e. the given position in the gtCallLateArgs list).
6128 // call - the call node
6129 // lateArgInx - the index into the late args list
6132 // The late argument node.
6134 GenTree* Compiler::gtArgNodeByLateArgInx(GenTreeCall* call, unsigned lateArgInx)
6136 GenTree* argx = nullptr;
6137 unsigned regIndex = 0;
6139 for (GenTreeArgList *list = call->gtCall.gtCallLateArgs; list != nullptr; regIndex++, list = list->Rest())
6141 argx = list->Current();
6142 assert(!argx->IsArgPlaceHolderNode()); // No placeholder nodes are in gtCallLateArgs;
6143 if (regIndex == lateArgInx)
6148 noway_assert(argx != nullptr);
6152 /*****************************************************************************
6154 * Given an fgArgTabEntry*, return true if it is the 'this' pointer argument.
6156 bool Compiler::gtArgIsThisPtr(fgArgTabEntry* argEntry)
6158 return (argEntry->parent == nullptr);
6161 /*****************************************************************************
6163 * Create a node that will assign 'src' to 'dst'.
6166 GenTree* Compiler::gtNewAssignNode(GenTree* dst, GenTree* src)
6168 /* Mark the target as being assigned */
6170 if ((dst->gtOper == GT_LCL_VAR) || (dst->OperGet() == GT_LCL_FLD))
6172 dst->gtFlags |= GTF_VAR_DEF;
6173 if (dst->IsPartialLclFld(this))
6175 // We treat these partial writes as combined uses and defs.
6176 dst->gtFlags |= GTF_VAR_USEASG;
6179 dst->gtFlags |= GTF_DONT_CSE;
6181 /* Create the assignment node */
6183 GenTree* asg = gtNewOperNode(GT_ASG, dst->TypeGet(), dst, src);
6185 /* Mark the expression as containing an assignment */
6187 asg->gtFlags |= GTF_ASG;
6192 //------------------------------------------------------------------------
6193 // gtNewObjNode: Creates a new Obj node.
6196 // structHnd - The class handle of the struct type.
6197 // addr - The address of the struct.
6200 // Returns a node representing the struct value at the given address.
6203 // Any entry and exit conditions, such as required preconditions of
6204 // data structures, memory to be freed by caller, etc.
6207 // It will currently return a GT_OBJ node for any struct type, but may
6208 // return a GT_IND or a non-indirection for a scalar type.
6209 // The node will not yet have its GC info initialized. This is because
6210 // we may not need this info if this is an r-value.
6212 GenTree* Compiler::gtNewObjNode(CORINFO_CLASS_HANDLE structHnd, GenTree* addr)
6214 var_types nodeType = impNormStructType(structHnd);
6215 assert(varTypeIsStruct(nodeType));
6216 unsigned size = info.compCompHnd->getClassSize(structHnd);
6218 // It would be convenient to set the GC info at this time, but we don't actually require
6219 // it unless this is going to be a destination.
6220 if (!varTypeIsStruct(nodeType))
6222 if ((addr->gtOper == GT_ADDR) && (addr->gtGetOp1()->TypeGet() == nodeType))
6224 return addr->gtGetOp1();
6228 return gtNewOperNode(GT_IND, nodeType, addr);
6231 GenTreeBlk* newBlkOrObjNode = new (this, GT_OBJ) GenTreeObj(nodeType, addr, structHnd, size);
6233 // An Obj is not a global reference, if it is known to be a local struct.
6234 if ((addr->gtFlags & GTF_GLOB_REF) == 0)
6236 GenTreeLclVarCommon* lclNode = addr->IsLocalAddrExpr();
6237 if (lclNode != nullptr)
6239 newBlkOrObjNode->gtFlags |= GTF_IND_NONFAULTING;
6240 if (!lvaIsImplicitByRefLocal(lclNode->gtLclNum))
6242 newBlkOrObjNode->gtFlags &= ~GTF_GLOB_REF;
6246 return newBlkOrObjNode;
6249 //------------------------------------------------------------------------
6250 // gtSetObjGcInfo: Set the GC info on an object node
6253 // objNode - The object node of interest
6255 void Compiler::gtSetObjGcInfo(GenTreeObj* objNode)
6257 CORINFO_CLASS_HANDLE structHnd = objNode->gtClass;
6258 var_types nodeType = objNode->TypeGet();
6259 unsigned size = objNode->gtBlkSize;
6261 unsigned gcPtrCount = 0;
6262 BYTE* gcPtrs = nullptr;
6264 assert(varTypeIsStruct(nodeType));
6265 assert(size == info.compCompHnd->getClassSize(structHnd));
6266 assert(nodeType == impNormStructType(structHnd));
6268 if (nodeType == TYP_STRUCT)
6270 if (size >= TARGET_POINTER_SIZE)
6272 // Get the GC fields info
6273 var_types simdBaseType; // Dummy argument
6274 slots = roundUp(size, TARGET_POINTER_SIZE) / TARGET_POINTER_SIZE;
6275 gcPtrs = new (this, CMK_ASTNode) BYTE[slots];
6276 nodeType = impNormStructType(structHnd, gcPtrs, &gcPtrCount, &simdBaseType);
6279 objNode->SetGCInfo(gcPtrs, gcPtrCount, slots);
6280 assert(objNode->gtType == nodeType);
6283 //------------------------------------------------------------------------
6284 // gtNewStructVal: Return a node that represents a struct value
6287 // structHnd - The class for the struct
6288 // addr - The address of the struct
6291 // A block, object or local node that represents the struct value pointed to by 'addr'.
6293 GenTree* Compiler::gtNewStructVal(CORINFO_CLASS_HANDLE structHnd, GenTree* addr)
6295 if (addr->gtOper == GT_ADDR)
6297 GenTree* val = addr->gtGetOp1();
6298 if (val->OperGet() == GT_LCL_VAR)
6300 unsigned lclNum = addr->gtGetOp1()->AsLclVarCommon()->gtLclNum;
6301 LclVarDsc* varDsc = &(lvaTable[lclNum]);
6302 if (varTypeIsStruct(varDsc) && (varDsc->lvVerTypeInfo.GetClassHandle() == structHnd) &&
6303 !lvaIsImplicitByRefLocal(lclNum))
6305 return addr->gtGetOp1();
6309 return gtNewObjNode(structHnd, addr);
6312 //------------------------------------------------------------------------
6313 // gtNewBlockVal: Return a node that represents a possibly untyped block value
6316 // addr - The address of the block
6317 // size - The size of the block
6320 // A block, object or local node that represents the block value pointed to by 'addr'.
6322 GenTree* Compiler::gtNewBlockVal(GenTree* addr, unsigned size)
6324 // By default we treat this as an opaque struct type with known size.
6325 var_types blkType = TYP_STRUCT;
6326 if ((addr->gtOper == GT_ADDR) && (addr->gtGetOp1()->OperGet() == GT_LCL_VAR))
6328 GenTree* val = addr->gtGetOp1();
6330 if (varTypeIsSIMD(val))
6332 if (genTypeSize(val->TypeGet()) == size)
6334 blkType = val->TypeGet();
6335 return addr->gtGetOp1();
6339 #endif // FEATURE_SIMD
6340 if (val->TypeGet() == TYP_STRUCT)
6342 GenTreeLclVarCommon* lcl = addr->gtGetOp1()->AsLclVarCommon();
6343 LclVarDsc* varDsc = &(lvaTable[lcl->gtLclNum]);
6344 if ((varDsc->TypeGet() == TYP_STRUCT) && (varDsc->lvExactSize == size))
6346 return addr->gtGetOp1();
6350 return new (this, GT_BLK) GenTreeBlk(GT_BLK, blkType, addr, size);
6353 // Creates a new assignment node for a CpObj.
6354 // Parameters (exactly the same as MSIL CpObj):
6356 // dstAddr - The target to copy the struct to
6357 // srcAddr - The source to copy the struct from
6358 // structHnd - A class token that represents the type of object being copied. May be null
6359 // if FEATURE_SIMD is enabled and the source has a SIMD type.
6360 // isVolatile - Is this marked as volatile memory?
6362 GenTree* Compiler::gtNewCpObjNode(GenTree* dstAddr, GenTree* srcAddr, CORINFO_CLASS_HANDLE structHnd, bool isVolatile)
6364 GenTree* lhs = gtNewStructVal(structHnd, dstAddr);
6365 GenTree* src = nullptr;
6368 if (lhs->OperIsBlk())
6370 size = lhs->AsBlk()->gtBlkSize;
6371 if (lhs->OperGet() == GT_OBJ)
6373 gtSetObjGcInfo(lhs->AsObj());
6378 size = genTypeSize(lhs->gtType);
6381 if (srcAddr->OperGet() == GT_ADDR)
6383 src = srcAddr->gtOp.gtOp1;
6387 src = gtNewOperNode(GT_IND, lhs->TypeGet(), srcAddr);
6390 GenTree* result = gtNewBlkOpNode(lhs, src, size, isVolatile, true);
6394 //------------------------------------------------------------------------
6395 // FixupInitBlkValue: Fixup the init value for an initBlk operation
6398 // asgType - The type of assignment that the initBlk is being transformed into
6401 // Modifies the constant value on this node to be the appropriate "fill"
6402 // value for the initblk.
6405 // The initBlk MSIL instruction takes a byte value, which must be
6406 // extended to the size of the assignment when an initBlk is transformed
6407 // to an assignment of a primitive type.
6408 // This performs the appropriate extension.
6410 void GenTreeIntCon::FixupInitBlkValue(var_types asgType)
6412 assert(varTypeIsIntegralOrI(asgType));
6413 unsigned size = genTypeSize(asgType);
6416 size_t cns = gtIconVal;
6422 #ifdef _TARGET_64BIT_
6427 #endif // _TARGET_64BIT_
6429 // Make the type match for evaluation types.
6432 // if we are initializing a GC type the value being assigned must be zero (null).
6433 assert(!varTypeIsGC(asgType) || (cns == 0));
6441 //------------------------------------------------------------------------
6442 // gtBlockOpInit: Initializes a BlkOp GenTree
6445 // result - an assignment node that is to be initialized.
6446 // dst - the target (destination) we want to either initialize or copy to.
6447 // src - the init value for InitBlk or the source struct for CpBlk/CpObj.
6448 // isVolatile - specifies whether this node is a volatile memory operation.
6451 // 'result' is an assignment that is newly constructed.
6452 // If 'dst' is TYP_STRUCT, then it must be a block node or lclVar.
6455 // This procedure centralizes all the logic to both enforce proper structure and
6456 // to properly construct any InitBlk/CpBlk node.
6458 void Compiler::gtBlockOpInit(GenTree* result, GenTree* dst, GenTree* srcOrFillVal, bool isVolatile)
6460 if (!result->OperIsBlkOp())
6462 assert(dst->TypeGet() != TYP_STRUCT);
6466 // If the copy involves GC pointers, the caller must have already set
6467 // the node additional members (gtGcPtrs, gtGcPtrCount, gtSlots) on the dst.
6468 if ((dst->gtOper == GT_OBJ) && dst->AsBlk()->HasGCPtr())
6470 GenTreeObj* objNode = dst->AsObj();
6471 assert(objNode->gtGcPtrs != nullptr);
6472 assert(!IsUninitialized(objNode->gtGcPtrs));
6473 assert(!IsUninitialized(objNode->gtGcPtrCount));
6474 assert(!IsUninitialized(objNode->gtSlots) && objNode->gtSlots > 0);
6476 for (unsigned i = 0; i < objNode->gtGcPtrCount; ++i)
6478 CorInfoGCType t = (CorInfoGCType)objNode->gtGcPtrs[i];
6493 /* In the case of CpBlk, we want to avoid generating
6494 * nodes where the source and destination are the same
6495 * because of two reasons, first, is useless, second
6496 * it introduces issues in liveness and also copying
6497 * memory from an overlapping memory location is
6498 * undefined both as per the ECMA standard and also
6499 * the memcpy semantics specify that.
6501 * NOTE: In this case we'll only detect the case for addr of a local
6502 * and a local itself, any other complex expressions won't be
6505 * TODO-Cleanup: though having this logic is goodness (i.e. avoids self-assignment
6506 * of struct vars very early), it was added because fgInterBlockLocalVarLiveness()
6507 * isn't handling self-assignment of struct variables correctly. This issue may not
6508 * surface if struct promotion is ON (which is the case on x86/arm). But still the
6509 * fundamental issue exists that needs to be addressed.
6511 if (result->OperIsCopyBlkOp())
6513 GenTree* currSrc = srcOrFillVal;
6514 GenTree* currDst = dst;
6516 if (currSrc->OperIsBlk() && (currSrc->AsBlk()->Addr()->OperGet() == GT_ADDR))
6518 currSrc = currSrc->AsBlk()->Addr()->gtGetOp1();
6520 if (currDst->OperIsBlk() && (currDst->AsBlk()->Addr()->OperGet() == GT_ADDR))
6522 currDst = currDst->AsBlk()->Addr()->gtGetOp1();
6525 if (currSrc->OperGet() == GT_LCL_VAR && currDst->OperGet() == GT_LCL_VAR &&
6526 currSrc->gtLclVarCommon.gtLclNum == currDst->gtLclVarCommon.gtLclNum)
6529 // TODO-Cleanup: probably doesn't matter, but could do this earlier and avoid creating a GT_ASG
6530 result->gtBashToNOP();
6535 // Propagate all effect flags from children
6536 result->gtFlags |= dst->gtFlags & GTF_ALL_EFFECT;
6537 result->gtFlags |= result->gtOp.gtOp2->gtFlags & GTF_ALL_EFFECT;
6539 result->gtFlags |= (dst->gtFlags & GTF_EXCEPT) | (srcOrFillVal->gtFlags & GTF_EXCEPT);
6543 result->gtFlags |= GTF_BLK_VOLATILE;
6547 if (result->OperIsCopyBlkOp() && varTypeIsSIMD(srcOrFillVal))
6549 // If the source is a GT_SIMD node of SIMD type, then the dst lclvar struct
6550 // should be labeled as simd intrinsic related struct.
6551 // This is done so that the morpher can transform any field accesses into
6552 // intrinsics, thus avoiding conflicting access methods (fields vs. whole-register).
6554 GenTree* src = srcOrFillVal;
6555 if (src->OperIsIndir() && (src->AsIndir()->Addr()->OperGet() == GT_ADDR))
6557 src = src->AsIndir()->Addr()->gtGetOp1();
6559 #ifdef FEATURE_HW_INTRINSICS
6560 if ((src->OperGet() == GT_SIMD) || (src->OperGet() == GT_HWIntrinsic))
6562 if (src->OperGet() == GT_SIMD)
6563 #endif // FEATURE_HW_INTRINSICS
6565 if (dst->OperIsBlk() && (dst->AsIndir()->Addr()->OperGet() == GT_ADDR))
6567 dst = dst->AsIndir()->Addr()->gtGetOp1();
6570 if (dst->OperIsLocal() && varTypeIsStruct(dst))
6572 setLclRelatedToSIMDIntrinsic(dst);
6576 #endif // FEATURE_SIMD
6579 //------------------------------------------------------------------------
6580 // gtNewBlkOpNode: Creates a GenTree for a block (struct) assignment.
6583 // dst - Destination or target to copy to / initialize the buffer.
6584 // srcOrFillVall - the size of the buffer to copy/initialize or zero, in the case of CpObj.
6585 // size - The size of the buffer or a class token (in the case of CpObj).
6586 // isVolatile - Whether this is a volatile memory operation or not.
6587 // isCopyBlock - True if this is a block copy (rather than a block init).
6590 // Returns the newly constructed and initialized block operation.
6593 // If size is zero, the dst must be a GT_OBJ with the class handle.
6594 // 'dst' must be a block node or lclVar.
6596 GenTree* Compiler::gtNewBlkOpNode(GenTree* dst, GenTree* srcOrFillVal, unsigned size, bool isVolatile, bool isCopyBlock)
6598 assert(dst->OperIsBlk() || dst->OperIsLocal());
6601 srcOrFillVal->gtFlags |= GTF_DONT_CSE;
6602 if (srcOrFillVal->OperIsIndir() && (srcOrFillVal->gtGetOp1()->gtOper == GT_ADDR))
6604 srcOrFillVal = srcOrFillVal->gtGetOp1()->gtGetOp1();
6610 assert(varTypeIsIntegral(srcOrFillVal));
6611 if (varTypeIsStruct(dst))
6613 if (!srcOrFillVal->IsIntegralConst(0))
6615 srcOrFillVal = gtNewOperNode(GT_INIT_VAL, TYP_INT, srcOrFillVal);
6620 GenTree* result = gtNewAssignNode(dst, srcOrFillVal);
6621 gtBlockOpInit(result, dst, srcOrFillVal, isVolatile);
6625 //------------------------------------------------------------------------
6626 // gtNewPutArgReg: Creates a new PutArgReg node.
6629 // type - The actual type of the argument
6630 // arg - The argument node
6631 // argReg - The register that the argument will be passed in
6634 // Returns the newly created PutArgReg node.
6637 // The node is generated as GenTreeMultiRegOp on RyuJIT/armel, GenTreeOp on all the other archs.
6639 GenTree* Compiler::gtNewPutArgReg(var_types type, GenTree* arg, regNumber argReg)
6641 assert(arg != nullptr);
6643 GenTree* node = nullptr;
6644 #if defined(_TARGET_ARM_)
6645 // A PUTARG_REG could be a MultiRegOp on arm since we could move a double register to two int registers.
6646 node = new (this, GT_PUTARG_REG) GenTreeMultiRegOp(GT_PUTARG_REG, type, arg, nullptr);
6647 if (type == TYP_LONG)
6649 node->AsMultiRegOp()->gtOtherReg = REG_NEXT(argReg);
6652 node = gtNewOperNode(GT_PUTARG_REG, type, arg);
6654 node->gtRegNum = argReg;
6659 //------------------------------------------------------------------------
6660 // gtNewBitCastNode: Creates a new BitCast node.
6663 // type - The actual type of the argument
6664 // arg - The argument node
6665 // argReg - The register that the argument will be passed in
6668 // Returns the newly created BitCast node.
6671 // The node is generated as GenTreeMultiRegOp on RyuJIT/arm, as GenTreeOp on all the other archs.
6673 GenTree* Compiler::gtNewBitCastNode(var_types type, GenTree* arg)
6675 assert(arg != nullptr);
6677 GenTree* node = nullptr;
6678 #if defined(_TARGET_ARM_)
6679 // A BITCAST could be a MultiRegOp on arm since we could move a double register to two int registers.
6680 node = new (this, GT_BITCAST) GenTreeMultiRegOp(GT_BITCAST, type, arg, nullptr);
6682 node = gtNewOperNode(GT_BITCAST, type, arg);
6688 //------------------------------------------------------------------------
6689 // gtNewAllocObjNode: Helper to create an object allocation node.
6692 // pResolvedToken - Resolved token for the object being allocated
6693 // useParent - true iff the token represents a child of the object's class
6696 // Returns GT_ALLOCOBJ node that will be later morphed into an
6697 // allocation helper call or local variable allocation on the stack.
6699 GenTreeAllocObj* Compiler::gtNewAllocObjNode(CORINFO_RESOLVED_TOKEN* pResolvedToken, BOOL useParent)
6701 const BOOL mustRestoreHandle = TRUE;
6702 BOOL* const pRuntimeLookup = nullptr;
6703 bool usingReadyToRunHelper = false;
6704 CorInfoHelpFunc helper = CORINFO_HELP_UNDEF;
6705 GenTree* opHandle = impTokenToHandle(pResolvedToken, pRuntimeLookup, mustRestoreHandle, useParent);
6707 #ifdef FEATURE_READYTORUN_COMPILER
6708 CORINFO_CONST_LOOKUP lookup;
6710 if (opts.IsReadyToRun())
6712 helper = CORINFO_HELP_READYTORUN_NEW;
6713 CORINFO_LOOKUP_KIND* const pGenericLookupKind = nullptr;
6714 usingReadyToRunHelper =
6715 info.compCompHnd->getReadyToRunHelper(pResolvedToken, pGenericLookupKind, helper, &lookup);
6719 if (!usingReadyToRunHelper)
6721 if (opHandle == nullptr)
6723 // We must be backing out of an inline.
6724 assert(compDonotInline());
6728 helper = info.compCompHnd->getNewHelper(pResolvedToken, info.compMethodHnd);
6731 // TODO: ReadyToRun: When generic dictionary lookups are necessary, replace the lookup call
6732 // and the newfast call with a single call to a dynamic R2R cell that will:
6733 // 1) Load the context
6734 // 2) Perform the generic dictionary lookup and caching, and generate the appropriate stub
6735 // 3) Allocate and return the new object for boxing
6736 // Reason: performance (today, we'll always use the slow helper for the R2R generics case)
6738 GenTreeAllocObj* allocObj = gtNewAllocObjNode(helper, pResolvedToken->hClass, TYP_REF, opHandle);
6740 #ifdef FEATURE_READYTORUN_COMPILER
6741 if (usingReadyToRunHelper)
6743 allocObj->gtEntryPoint = lookup;
6750 /*****************************************************************************
6752 * Clones the given tree value and returns a copy of the given tree.
6753 * If 'complexOK' is false, the cloning is only done provided the tree
6754 * is not too complex (whatever that may mean);
6755 * If 'complexOK' is true, we try slightly harder to clone the tree.
6756 * In either case, NULL is returned if the tree cannot be cloned
6758 * Note that there is the function gtCloneExpr() which does a more
6759 * complete job if you can't handle this function failing.
6762 GenTree* Compiler::gtClone(GenTree* tree, bool complexOK)
6766 switch (tree->gtOper)
6770 #if defined(LATE_DISASM)
6771 if (tree->IsIconHandle())
6773 copy = gtNewIconHandleNode(tree->gtIntCon.gtIconVal, tree->gtFlags, tree->gtIntCon.gtFieldSeq);
6774 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6775 copy->gtType = tree->gtType;
6780 copy = new (this, GT_CNS_INT)
6781 GenTreeIntCon(tree->gtType, tree->gtIntCon.gtIconVal, tree->gtIntCon.gtFieldSeq);
6782 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6787 copy = gtNewLconNode(tree->gtLngCon.gtLconVal);
6791 // Remember that the LclVar node has been cloned. The flag will be set
6792 // on 'copy' as well.
6793 tree->gtFlags |= GTF_VAR_CLONED;
6794 copy = gtNewLclvNode(tree->gtLclVarCommon.gtLclNum, tree->gtType, tree->gtLclVar.gtLclILoffs);
6798 case GT_LCL_FLD_ADDR:
6799 // Remember that the LclVar node has been cloned. The flag will be set
6800 // on 'copy' as well.
6801 tree->gtFlags |= GTF_VAR_CLONED;
6802 copy = new (this, tree->gtOper)
6803 GenTreeLclFld(tree->gtOper, tree->TypeGet(), tree->gtLclFld.gtLclNum, tree->gtLclFld.gtLclOffs);
6804 copy->gtLclFld.gtFieldSeq = tree->gtLclFld.gtFieldSeq;
6808 copy = new (this, GT_CLS_VAR)
6809 GenTreeClsVar(tree->gtType, tree->gtClsVar.gtClsVarHnd, tree->gtClsVar.gtFieldSeq);
6818 if (tree->gtOper == GT_FIELD)
6822 // copied from line 9850
6825 if (tree->gtField.gtFldObj)
6827 objp = gtClone(tree->gtField.gtFldObj, false);
6834 copy = gtNewFieldRef(tree->TypeGet(), tree->gtField.gtFldHnd, objp, tree->gtField.gtFldOffset);
6835 copy->gtField.gtFldMayOverlap = tree->gtField.gtFldMayOverlap;
6836 #ifdef FEATURE_READYTORUN_COMPILER
6837 copy->gtField.gtFieldLookup = tree->gtField.gtFieldLookup;
6840 else if (tree->OperIs(GT_ADD, GT_SUB))
6842 GenTree* op1 = tree->gtOp.gtOp1;
6843 GenTree* op2 = tree->gtOp.gtOp2;
6845 if (op1->OperIsLeaf() && op2->OperIsLeaf())
6858 copy = gtNewOperNode(tree->OperGet(), tree->TypeGet(), op1, op2);
6865 else if (tree->gtOper == GT_ADDR)
6867 GenTree* op1 = gtClone(tree->gtOp.gtOp1);
6872 copy = gtNewOperNode(GT_ADDR, tree->TypeGet(), op1);
6882 copy->gtFlags |= tree->gtFlags & ~GTF_NODE_MASK;
6884 copy->gtDebugFlags |= tree->gtDebugFlags & ~GTF_DEBUG_NODE_MASK;
6885 #endif // defined(DEBUG)
6890 //------------------------------------------------------------------------
6891 // gtCloneExpr: Create a copy of `tree`, adding flags `addFlags`, mapping
6892 // local `varNum` to int constant `varVal` if it appears at
6893 // the root, and mapping uses of local `deepVarNum` to constant
6894 // `deepVarVal` if they occur beyond the root.
6897 // tree - GenTree to create a copy of
6898 // addFlags - GTF_* flags to add to the copied tree nodes
6899 // varNum - lclNum to replace at the root, or ~0 for no root replacement
6900 // varVal - If replacing at root, replace local `varNum` with IntCns `varVal`
6901 // deepVarNum - lclNum to replace uses of beyond the root, or ~0 for no replacement
6902 // deepVarVal - If replacing beyond root, replace `deepVarNum` with IntCns `deepVarVal`
6905 // A copy of the given tree with the replacements and added flags specified.
6908 // Top-level callers should generally call the overload that doesn't have
6909 // the explicit `deepVarNum` and `deepVarVal` parameters; those are used in
6910 // recursive invocations to avoid replacing defs.
6912 GenTree* Compiler::gtCloneExpr(
6913 GenTree* tree, unsigned addFlags, unsigned varNum, int varVal, unsigned deepVarNum, int deepVarVal)
6915 if (tree == nullptr)
6920 /* Figure out what kind of a node we have */
6922 genTreeOps oper = tree->OperGet();
6923 unsigned kind = tree->OperKind();
6926 /* Is this a constant or leaf node? */
6928 if (kind & (GTK_CONST | GTK_LEAF))
6934 #if defined(LATE_DISASM)
6935 if (tree->IsIconHandle())
6937 copy = gtNewIconHandleNode(tree->gtIntCon.gtIconVal, tree->gtFlags, tree->gtIntCon.gtFieldSeq);
6938 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6939 copy->gtType = tree->gtType;
6944 copy = gtNewIconNode(tree->gtIntCon.gtIconVal, tree->gtType);
6945 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6946 copy->gtIntCon.gtFieldSeq = tree->gtIntCon.gtFieldSeq;
6951 copy = gtNewLconNode(tree->gtLngCon.gtLconVal);
6955 copy = gtNewDconNode(tree->gtDblCon.gtDconVal);
6956 copy->gtType = tree->gtType; // keep the same type
6960 copy = gtNewSconNode(tree->gtStrCon.gtSconCPX, tree->gtStrCon.gtScpHnd);
6965 if (tree->gtLclVarCommon.gtLclNum == varNum)
6967 copy = gtNewIconNode(varVal, tree->gtType);
6968 if (tree->gtFlags & GTF_VAR_ARR_INDEX)
6970 copy->LabelIndex(this);
6975 // Remember that the LclVar node has been cloned. The flag will
6976 // be set on 'copy' as well.
6977 tree->gtFlags |= GTF_VAR_CLONED;
6978 copy = gtNewLclvNode(tree->gtLclVar.gtLclNum, tree->gtType, tree->gtLclVar.gtLclILoffs);
6979 copy->AsLclVarCommon()->SetSsaNum(tree->AsLclVarCommon()->GetSsaNum());
6981 copy->gtFlags = tree->gtFlags;
6985 if (tree->gtLclFld.gtLclNum == varNum)
6987 IMPL_LIMITATION("replacing GT_LCL_FLD with a constant");
6991 // Remember that the LclVar node has been cloned. The flag will
6992 // be set on 'copy' as well.
6993 tree->gtFlags |= GTF_VAR_CLONED;
6994 copy = new (this, GT_LCL_FLD)
6995 GenTreeLclFld(tree->TypeGet(), tree->gtLclFld.gtLclNum, tree->gtLclFld.gtLclOffs);
6996 copy->gtLclFld.gtFieldSeq = tree->gtLclFld.gtFieldSeq;
6997 copy->gtFlags = tree->gtFlags;
7002 copy = new (this, GT_CLS_VAR)
7003 GenTreeClsVar(tree->TypeGet(), tree->gtClsVar.gtClsVarHnd, tree->gtClsVar.gtFieldSeq);
7007 // GT_RET_EXPR is unique node, that contains a link to a gtInlineCandidate node,
7008 // that is part of another statement. We cannot clone both here and cannot
7009 // create another GT_RET_EXPR that points to the same gtInlineCandidate.
7010 NO_WAY("Cloning of GT_RET_EXPR node not supported");
7013 case GT_MEMORYBARRIER:
7014 copy = new (this, GT_MEMORYBARRIER) GenTree(GT_MEMORYBARRIER, TYP_VOID);
7018 copy = gtNewArgPlaceHolderNode(tree->gtType, tree->gtArgPlace.gtArgPlaceClsHnd);
7022 copy = new (this, oper) GenTreeFptrVal(tree->gtType, tree->gtFptrVal.gtFptrMethod);
7024 #ifdef FEATURE_READYTORUN_COMPILER
7025 copy->gtFptrVal.gtEntryPoint = tree->gtFptrVal.gtEntryPoint;
7031 copy = new (this, oper) GenTree(oper, tree->gtType);
7034 #if !FEATURE_EH_FUNCLETS
7036 #endif // !FEATURE_EH_FUNCLETS
7038 copy = new (this, oper) GenTreeVal(oper, tree->gtType, tree->gtVal.gtVal1);
7042 copy = new (this, oper) GenTreeLabel(tree->gtLabel.gtLabBB);
7046 NO_WAY("Cloning of node not supported");
7051 /* Is it a 'simple' unary/binary operator? */
7053 if (kind & GTK_SMPOP)
7055 /* If necessary, make sure we allocate a "fat" tree node */
7056 CLANG_FORMAT_COMMENT_ANCHOR;
7058 #if SMALL_TREE_NODES
7061 /* These nodes sometimes get bashed to "fat" ones */
7070 // In the implementation of gtNewLargeOperNode you have
7071 // to give an oper that will create a small node,
7072 // otherwise it asserts.
7074 if (GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL)
7076 copy = gtNewLargeOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1,
7077 tree->OperIsBinary() ? tree->gtOp.gtOp2 : nullptr);
7079 else // Always a large tree
7081 if (tree->OperIsBinary())
7083 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2);
7087 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1);
7094 new (this, LargeOpOpcode()) GenTreeCast(tree->TypeGet(), tree->gtCast.CastOp(), tree->IsUnsigned(),
7095 tree->gtCast.gtCastType DEBUGARG(/*largeNode*/ TRUE));
7098 // The nodes below this are not bashed, so they can be allocated at their individual sizes.
7101 assert((tree->gtOp.gtOp2 == nullptr) || tree->gtOp.gtOp2->OperIsList());
7102 copy = new (this, GT_LIST) GenTreeArgList(tree->gtOp.gtOp1);
7103 copy->gtOp.gtOp2 = tree->gtOp.gtOp2;
7107 copy = new (this, GT_FIELD_LIST) GenTreeFieldList(tree->gtOp.gtOp1, tree->AsFieldList()->gtFieldOffset,
7108 tree->AsFieldList()->gtFieldType, nullptr);
7109 copy->gtOp.gtOp2 = tree->gtOp.gtOp2;
7110 copy->gtFlags = (copy->gtFlags & ~GTF_FIELD_LIST_HEAD) | (tree->gtFlags & GTF_FIELD_LIST_HEAD);
7115 GenTreeIndex* asInd = tree->AsIndex();
7116 copy = new (this, GT_INDEX)
7117 GenTreeIndex(asInd->TypeGet(), asInd->Arr(), asInd->Index(), asInd->gtIndElemSize);
7118 copy->AsIndex()->gtStructElemClass = asInd->gtStructElemClass;
7124 GenTreeIndexAddr* asIndAddr = tree->AsIndexAddr();
7126 copy = new (this, GT_INDEX_ADDR)
7127 GenTreeIndexAddr(asIndAddr->Arr(), asIndAddr->Index(), asIndAddr->gtElemType,
7128 asIndAddr->gtStructElemClass, asIndAddr->gtElemSize, asIndAddr->gtLenOffset,
7129 asIndAddr->gtElemOffset);
7130 copy->AsIndexAddr()->gtIndRngFailBB = asIndAddr->gtIndRngFailBB;
7136 GenTreeAllocObj* asAllocObj = tree->AsAllocObj();
7137 copy = new (this, GT_ALLOCOBJ) GenTreeAllocObj(tree->TypeGet(), asAllocObj->gtNewHelper,
7138 asAllocObj->gtAllocObjClsHnd, asAllocObj->gtOp1);
7142 case GT_RUNTIMELOOKUP:
7144 GenTreeRuntimeLookup* asRuntimeLookup = tree->AsRuntimeLookup();
7146 copy = new (this, GT_RUNTIMELOOKUP)
7147 GenTreeRuntimeLookup(asRuntimeLookup->gtHnd, asRuntimeLookup->gtHndType, asRuntimeLookup->gtOp1);
7152 copy = gtNewArrLen(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtArrLen.ArrLenOffset());
7156 copy = new (this, GT_ARR_INDEX)
7157 GenTreeArrIndex(tree->TypeGet(),
7158 gtCloneExpr(tree->gtArrIndex.ArrObj(), addFlags, deepVarNum, deepVarVal),
7159 gtCloneExpr(tree->gtArrIndex.IndexExpr(), addFlags, deepVarNum, deepVarVal),
7160 tree->gtArrIndex.gtCurrDim, tree->gtArrIndex.gtArrRank,
7161 tree->gtArrIndex.gtArrElemType);
7165 copy = new (this, GT_QMARK) GenTreeQmark(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2, this);
7169 copy = new (this, GT_OBJ)
7170 GenTreeObj(tree->TypeGet(), tree->gtOp.gtOp1, tree->AsObj()->gtClass, tree->gtBlk.gtBlkSize);
7171 copy->AsObj()->CopyGCInfo(tree->AsObj());
7172 copy->gtBlk.gtBlkOpGcUnsafe = tree->gtBlk.gtBlkOpGcUnsafe;
7176 copy = new (this, GT_BLK) GenTreeBlk(GT_BLK, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtBlk.gtBlkSize);
7177 copy->gtBlk.gtBlkOpGcUnsafe = tree->gtBlk.gtBlkOpGcUnsafe;
7181 copy = new (this, GT_DYN_BLK) GenTreeDynBlk(tree->gtOp.gtOp1, tree->gtDynBlk.gtDynamicSize);
7182 copy->gtBlk.gtBlkOpGcUnsafe = tree->gtBlk.gtBlkOpGcUnsafe;
7186 copy = new (this, GT_BOX)
7187 GenTreeBox(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtBox.gtAsgStmtWhenInlinedBoxValue,
7188 tree->gtBox.gtCopyStmtWhenInlinedBoxValue);
7192 copy = new (this, GT_INTRINSIC)
7193 GenTreeIntrinsic(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2,
7194 tree->gtIntrinsic.gtIntrinsicId, tree->gtIntrinsic.gtMethodHandle);
7195 #ifdef FEATURE_READYTORUN_COMPILER
7196 copy->gtIntrinsic.gtEntryPoint = tree->gtIntrinsic.gtEntryPoint;
7202 GenTreeAddrMode* addrModeOp = tree->AsAddrMode();
7203 copy = new (this, GT_LEA)
7204 GenTreeAddrMode(addrModeOp->TypeGet(), addrModeOp->Base(), addrModeOp->Index(), addrModeOp->gtScale,
7205 static_cast<unsigned>(addrModeOp->Offset()));
7212 copy = new (this, oper) GenTreeCopyOrReload(oper, tree->TypeGet(), tree->gtGetOp1());
7219 GenTreeSIMD* simdOp = tree->AsSIMD();
7220 copy = gtNewSIMDNode(simdOp->TypeGet(), simdOp->gtGetOp1(), simdOp->gtGetOp2IfPresent(),
7221 simdOp->gtSIMDIntrinsicID, simdOp->gtSIMDBaseType, simdOp->gtSIMDSize);
7226 #ifdef FEATURE_HW_INTRINSICS
7227 case GT_HWIntrinsic:
7229 GenTreeHWIntrinsic* hwintrinsicOp = tree->AsHWIntrinsic();
7230 copy = new (this, GT_HWIntrinsic)
7231 GenTreeHWIntrinsic(hwintrinsicOp->TypeGet(), hwintrinsicOp->gtGetOp1(),
7232 hwintrinsicOp->gtGetOp2IfPresent(), hwintrinsicOp->gtHWIntrinsicId,
7233 hwintrinsicOp->gtSIMDBaseType, hwintrinsicOp->gtSIMDSize);
7234 copy->AsHWIntrinsic()->gtIndexBaseType = hwintrinsicOp->gtIndexBaseType;
7240 assert(!GenTree::IsExOp(tree->OperKind()) && tree->OperIsSimple());
7241 // We're in the SimpleOp case, so it's always unary or binary.
7242 if (GenTree::OperIsUnary(tree->OperGet()))
7244 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, /*doSimplifications*/ false);
7248 assert(GenTree::OperIsBinary(tree->OperGet()));
7249 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2);
7254 // We're in the SimpleOp case, so it's always unary or binary.
7255 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2);
7258 // Some flags are conceptually part of the gtOper, and should be copied immediately.
7259 if (tree->gtOverflowEx())
7261 copy->gtFlags |= GTF_OVERFLOW;
7264 if (tree->gtOp.gtOp1)
7266 if (tree->gtOper == GT_ASG)
7268 // Don't replace varNum if it appears as the LHS of an assign.
7269 copy->gtOp.gtOp1 = gtCloneExpr(tree->gtOp.gtOp1, addFlags, -1, 0, deepVarNum, deepVarVal);
7273 copy->gtOp.gtOp1 = gtCloneExpr(tree->gtOp.gtOp1, addFlags, deepVarNum, deepVarVal);
7277 if (tree->gtGetOp2IfPresent())
7279 copy->gtOp.gtOp2 = gtCloneExpr(tree->gtOp.gtOp2, addFlags, deepVarNum, deepVarVal);
7283 addFlags |= tree->gtFlags;
7285 // Copy any node annotations, if necessary.
7286 switch (tree->gtOper)
7294 if (!tree->AsIndir()->gtOp1->OperIs(GT_INDEX_ADDR) && TryGetArrayInfo(tree->AsIndir(), &arrInfo))
7296 GetArrayInfoMap()->Set(copy, arrInfo);
7306 /* GTF_NODE_MASK should not be propagated from 'tree' to 'copy' */
7307 addFlags &= ~GTF_NODE_MASK;
7310 // Effects flags propagate upwards.
7311 if (copy->gtOp.gtOp1 != nullptr)
7313 copy->gtFlags |= (copy->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
7315 if (copy->gtGetOp2IfPresent() != nullptr)
7317 copy->gtFlags |= (copy->gtGetOp2()->gtFlags & GTF_ALL_EFFECT);
7323 /* See what kind of a special operator we have here */
7328 copy = gtCloneExpr(tree->gtStmt.gtStmtExpr, addFlags, deepVarNum, deepVarVal);
7329 copy = gtNewStmt(copy, tree->gtStmt.gtStmtILoffsx);
7334 // We can't safely clone calls that have GT_RET_EXPRs via gtCloneExpr.
7335 // You must use gtCloneCandidateCall for these calls (and then do appropriate other fixup)
7336 if (tree->gtCall.IsInlineCandidate() || tree->gtCall.IsGuardedDevirtualizationCandidate())
7338 NO_WAY("Cloning of calls with associated GT_RET_EXPR nodes is not supported");
7341 copy = gtCloneExprCallHelper(tree->AsCall(), addFlags, deepVarNum, deepVarVal);
7346 copy = gtNewFieldRef(tree->TypeGet(), tree->gtField.gtFldHnd, nullptr, tree->gtField.gtFldOffset);
7348 copy->gtField.gtFldObj = tree->gtField.gtFldObj
7349 ? gtCloneExpr(tree->gtField.gtFldObj, addFlags, deepVarNum, deepVarVal)
7351 copy->gtField.gtFldMayOverlap = tree->gtField.gtFldMayOverlap;
7352 #ifdef FEATURE_READYTORUN_COMPILER
7353 copy->gtField.gtFieldLookup = tree->gtField.gtFieldLookup;
7360 GenTree* inds[GT_ARR_MAX_RANK];
7361 for (unsigned dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
7363 inds[dim] = gtCloneExpr(tree->gtArrElem.gtArrInds[dim], addFlags, deepVarNum, deepVarVal);
7365 copy = new (this, GT_ARR_ELEM)
7366 GenTreeArrElem(tree->TypeGet(), gtCloneExpr(tree->gtArrElem.gtArrObj, addFlags, deepVarNum, deepVarVal),
7367 tree->gtArrElem.gtArrRank, tree->gtArrElem.gtArrElemSize, tree->gtArrElem.gtArrElemType,
7374 copy = new (this, GT_ARR_OFFSET)
7375 GenTreeArrOffs(tree->TypeGet(), gtCloneExpr(tree->gtArrOffs.gtOffset, addFlags, deepVarNum, deepVarVal),
7376 gtCloneExpr(tree->gtArrOffs.gtIndex, addFlags, deepVarNum, deepVarVal),
7377 gtCloneExpr(tree->gtArrOffs.gtArrObj, addFlags, deepVarNum, deepVarVal),
7378 tree->gtArrOffs.gtCurrDim, tree->gtArrOffs.gtArrRank, tree->gtArrOffs.gtArrElemType);
7383 copy = new (this, GT_CMPXCHG)
7384 GenTreeCmpXchg(tree->TypeGet(),
7385 gtCloneExpr(tree->gtCmpXchg.gtOpLocation, addFlags, deepVarNum, deepVarVal),
7386 gtCloneExpr(tree->gtCmpXchg.gtOpValue, addFlags, deepVarNum, deepVarVal),
7387 gtCloneExpr(tree->gtCmpXchg.gtOpComparand, addFlags, deepVarNum, deepVarVal));
7390 case GT_ARR_BOUNDS_CHECK:
7393 #endif // FEATURE_SIMD
7394 #ifdef FEATURE_HW_INTRINSICS
7395 case GT_HW_INTRINSIC_CHK:
7396 #endif // FEATURE_HW_INTRINSICS
7397 copy = new (this, oper)
7398 GenTreeBoundsChk(oper, tree->TypeGet(),
7399 gtCloneExpr(tree->gtBoundsChk.gtIndex, addFlags, deepVarNum, deepVarVal),
7400 gtCloneExpr(tree->gtBoundsChk.gtArrLen, addFlags, deepVarNum, deepVarVal),
7401 tree->gtBoundsChk.gtThrowKind);
7402 copy->gtBoundsChk.gtIndRngFailBB = tree->gtBoundsChk.gtIndRngFailBB;
7405 case GT_STORE_DYN_BLK:
7407 copy = new (this, oper)
7408 GenTreeDynBlk(gtCloneExpr(tree->gtDynBlk.Addr(), addFlags, deepVarNum, deepVarVal),
7409 gtCloneExpr(tree->gtDynBlk.gtDynamicSize, addFlags, deepVarNum, deepVarVal));
7416 NO_WAY("unexpected operator");
7421 // If it has a zero-offset field seq, copy annotation.
7422 if (tree->TypeGet() == TYP_BYREF)
7424 FieldSeqNode* fldSeq = nullptr;
7425 if (GetZeroOffsetFieldMap()->Lookup(tree, &fldSeq))
7427 GetZeroOffsetFieldMap()->Set(copy, fldSeq);
7431 copy->gtVNPair = tree->gtVNPair; // A cloned tree gets the orginal's Value number pair
7433 /* Compute the flags for the copied node. Note that we can do this only
7434 if we didnt gtFoldExpr(copy) */
7436 if (copy->gtOper == oper)
7438 addFlags |= tree->gtFlags;
7441 /* GTF_NODE_MASK should not be propagated from 'tree' to 'copy' */
7442 addFlags &= ~GTF_NODE_MASK;
7444 // Some other flags depend on the context of the expression, and should not be preserved.
7445 // For example, GTF_RELOP_QMARK:
7446 if (copy->OperKind() & GTK_RELOP)
7448 addFlags &= ~GTF_RELOP_QMARK;
7450 // On the other hand, if we're creating such a context, restore this flag.
7451 if (copy->OperGet() == GT_QMARK)
7453 copy->gtOp.gtOp1->gtFlags |= GTF_RELOP_QMARK;
7456 copy->gtFlags |= addFlags;
7458 // Update side effect flags since they may be different from the source side effect flags.
7459 // For example, we may have replaced some locals with constants and made indirections non-throwing.
7460 gtUpdateNodeSideEffects(copy);
7463 /* GTF_COLON_COND should be propagated from 'tree' to 'copy' */
7464 copy->gtFlags |= (tree->gtFlags & GTF_COLON_COND);
7467 // Non-node debug flags should be propagated from 'tree' to 'copy'
7468 copy->gtDebugFlags |= (tree->gtDebugFlags & ~GTF_DEBUG_NODE_MASK);
7471 /* Make sure to copy back fields that may have been initialized */
7473 copy->CopyRawCosts(tree);
7474 copy->gtRsvdRegs = tree->gtRsvdRegs;
7475 copy->CopyReg(tree);
7479 //------------------------------------------------------------------------
7480 // gtCloneExprCallHelper: clone a call tree
7483 // Do not invoke this method directly, instead call either gtCloneExpr
7484 // or gtCloneCandidateCall, as appropriate.
7487 // tree - the call to clone
7488 // addFlags - GTF_* flags to add to the copied tree nodes
7489 // deepVarNum - lclNum to replace uses of beyond the root, or BAD_VAR_NUM for no replacement
7490 // deepVarVal - If replacing beyond root, replace `deepVarNum` with IntCns `deepVarVal`
7493 // Cloned copy of call and all subtrees.
7495 GenTreeCall* Compiler::gtCloneExprCallHelper(GenTreeCall* tree, unsigned addFlags, unsigned deepVarNum, int deepVarVal)
7497 GenTreeCall* copy = new (this, GT_CALL) GenTreeCall(tree->TypeGet());
7499 copy->gtCallObjp = tree->gtCallObjp ? gtCloneExpr(tree->gtCallObjp, addFlags, deepVarNum, deepVarVal) : nullptr;
7501 tree->gtCallArgs ? gtCloneExpr(tree->gtCallArgs, addFlags, deepVarNum, deepVarVal)->AsArgList() : nullptr;
7502 copy->gtCallMoreFlags = tree->gtCallMoreFlags;
7503 copy->gtCallLateArgs = tree->gtCallLateArgs
7504 ? gtCloneExpr(tree->gtCallLateArgs, addFlags, deepVarNum, deepVarVal)->AsArgList()
7507 #if !FEATURE_FIXED_OUT_ARGS
7508 copy->regArgList = tree->regArgList;
7509 copy->regArgListCount = tree->regArgListCount;
7512 // The call sig comes from the EE and doesn't change throughout the compilation process, meaning
7513 // we only really need one physical copy of it. Therefore a shallow pointer copy will suffice.
7514 // (Note that this still holds even if the tree we are cloning was created by an inlinee compiler,
7515 // because the inlinee still uses the inliner's memory allocator anyway.)
7516 copy->callSig = tree->callSig;
7518 copy->gtCallType = tree->gtCallType;
7519 copy->gtReturnType = tree->gtReturnType;
7520 copy->gtControlExpr = tree->gtControlExpr;
7522 /* Copy the union */
7523 if (tree->gtCallType == CT_INDIRECT)
7525 copy->gtCallCookie =
7526 tree->gtCallCookie ? gtCloneExpr(tree->gtCallCookie, addFlags, deepVarNum, deepVarVal) : nullptr;
7527 copy->gtCallAddr = tree->gtCallAddr ? gtCloneExpr(tree->gtCallAddr, addFlags, deepVarNum, deepVarVal) : nullptr;
7529 else if (tree->IsVirtualStub())
7531 copy->gtCallMethHnd = tree->gtCallMethHnd;
7532 copy->gtStubCallStubAddr = tree->gtStubCallStubAddr;
7536 copy->gtCallMethHnd = tree->gtCallMethHnd;
7537 copy->gtInlineCandidateInfo = nullptr;
7540 if (tree->fgArgInfo)
7542 // Create and initialize the fgArgInfo for our copy of the call tree
7543 copy->fgArgInfo = new (this, CMK_Unknown) fgArgInfo(copy, tree);
7547 copy->fgArgInfo = nullptr;
7550 copy->gtRetClsHnd = tree->gtRetClsHnd;
7552 #if FEATURE_MULTIREG_RET
7553 copy->gtReturnTypeDesc = tree->gtReturnTypeDesc;
7556 #ifdef FEATURE_READYTORUN_COMPILER
7557 copy->setEntryPoint(tree->gtEntryPoint);
7560 #if defined(DEBUG) || defined(INLINE_DATA)
7561 copy->gtInlineObservation = tree->gtInlineObservation;
7562 copy->gtRawILOffset = tree->gtCall.gtRawILOffset;
7565 copy->CopyOtherRegFlags(tree);
7570 //------------------------------------------------------------------------
7571 // gtCloneCandidateCall: clone a call that is an inline or guarded
7572 // devirtualization candidate (~ any call that can have a GT_RET_EXPR)
7575 // If the call really is a candidate, the caller must take additional steps
7576 // after cloning to re-establish candidate info and the relationship between
7577 // the candidate and any associated GT_RET_EXPR.
7580 // call - the call to clone
7583 // Cloned copy of call and all subtrees.
7585 GenTreeCall* Compiler::gtCloneCandidateCall(GenTreeCall* call)
7587 assert(call->IsInlineCandidate() || call->IsGuardedDevirtualizationCandidate());
7589 GenTreeCall* result = gtCloneExprCallHelper(call);
7591 // There is some common post-processing in gtCloneExpr that we reproduce
7592 // here, for the fields that make sense for candidate calls.
7593 result->gtFlags |= call->gtFlags;
7596 result->gtDebugFlags |= (call->gtDebugFlags & ~GTF_DEBUG_NODE_MASK);
7599 result->CopyReg(call);
7604 //------------------------------------------------------------------------
7605 // gtReplaceTree: Replace a tree with a new tree.
7608 // stmt - The top-level root stmt of the tree being replaced.
7609 // Must not be null.
7610 // tree - The tree being replaced. Must not be null.
7611 // replacementTree - The replacement tree. Must not be null.
7614 // The tree node that replaces the old tree.
7617 // The sequencing of the stmt has been done.
7620 // The caller must ensure that the original statement has been sequenced,
7621 // and the side effect flags are updated on the statement nodes,
7622 // but this method will sequence 'replacementTree', and insert it into the
7623 // proper place in the statement sequence.
7625 GenTree* Compiler::gtReplaceTree(GenTree* stmt, GenTree* tree, GenTree* replacementTree)
7627 assert(fgStmtListThreaded);
7628 assert(tree != nullptr);
7629 assert(stmt != nullptr);
7630 assert(replacementTree != nullptr);
7632 GenTree** treePtr = nullptr;
7633 GenTree* treeParent = tree->gtGetParent(&treePtr);
7635 assert(treeParent != nullptr || tree == stmt->gtStmt.gtStmtExpr);
7637 if (treePtr == nullptr)
7639 // Replace the stmt expr and rebuild the linear order for "stmt".
7640 assert(treeParent == nullptr);
7641 assert(fgOrder != FGOrderLinear);
7642 stmt->gtStmt.gtStmtExpr = tree;
7647 assert(treeParent != nullptr);
7649 // Check to see if the node to be replaced is a call argument and if so,
7650 // set `treeParent` to the call node.
7651 GenTree* cursor = treeParent;
7652 while ((cursor != nullptr) && (cursor->OperGet() == GT_LIST))
7654 cursor = cursor->gtNext;
7657 if ((cursor != nullptr) && (cursor->OperGet() == GT_CALL))
7659 treeParent = cursor;
7664 assert(treeParent->TryGetUse(tree, &useEdge));
7665 assert(useEdge == treePtr);
7668 GenTree* treeFirstNode = fgGetFirstNode(tree);
7669 GenTree* treeLastNode = tree;
7670 GenTree* treePrevNode = treeFirstNode->gtPrev;
7671 GenTree* treeNextNode = treeLastNode->gtNext;
7673 treeParent->ReplaceOperand(treePtr, replacementTree);
7675 // Build the linear order for "replacementTree".
7676 fgSetTreeSeq(replacementTree, treePrevNode);
7678 // Restore linear-order Prev and Next for "replacementTree".
7679 if (treePrevNode != nullptr)
7681 treeFirstNode = fgGetFirstNode(replacementTree);
7682 treeFirstNode->gtPrev = treePrevNode;
7683 treePrevNode->gtNext = treeFirstNode;
7687 // Update the linear oder start of "stmt" if treeFirstNode
7688 // appears to have replaced the original first node.
7689 assert(treeFirstNode == stmt->gtStmt.gtStmtList);
7690 stmt->gtStmt.gtStmtList = fgGetFirstNode(replacementTree);
7693 if (treeNextNode != nullptr)
7695 treeLastNode = replacementTree;
7696 treeLastNode->gtNext = treeNextNode;
7697 treeNextNode->gtPrev = treeLastNode;
7701 return replacementTree;
7704 //------------------------------------------------------------------------
7705 // gtUpdateSideEffects: Update the side effects of a tree and its ancestors
7708 // stmt - The tree's statement
7709 // tree - Tree to update the side effects for
7711 // Note: If tree's order hasn't been established, the method updates side effect
7712 // flags on all statement's nodes.
7714 void Compiler::gtUpdateSideEffects(GenTree* stmt, GenTree* tree)
7716 if (fgStmtListThreaded)
7718 gtUpdateTreeAncestorsSideEffects(tree);
7722 gtUpdateStmtSideEffects(stmt);
7726 //------------------------------------------------------------------------
7727 // gtUpdateTreeAncestorsSideEffects: Update the side effects of a tree and its ancestors
7728 // when statement order has been established.
7731 // tree - Tree to update the side effects for
7733 void Compiler::gtUpdateTreeAncestorsSideEffects(GenTree* tree)
7735 assert(fgStmtListThreaded);
7736 while (tree != nullptr)
7738 gtUpdateNodeSideEffects(tree);
7739 tree = tree->gtGetParent(nullptr);
7743 //------------------------------------------------------------------------
7744 // gtUpdateStmtSideEffects: Update the side effects for statement tree nodes.
7747 // stmt - The statement to update side effects on
7749 void Compiler::gtUpdateStmtSideEffects(GenTree* stmt)
7751 fgWalkTree(&stmt->gtStmt.gtStmtExpr, fgUpdateSideEffectsPre, fgUpdateSideEffectsPost);
7754 //------------------------------------------------------------------------
7755 // gtUpdateNodeOperSideEffects: Update the side effects based on the node operation.
7758 // tree - Tree to update the side effects on
7761 // This method currently only updates GTF_EXCEPT, GTF_ASG, and GTF_CALL flags.
7762 // The other side effect flags may remain unnecessarily (conservatively) set.
7763 // The caller of this method is expected to update the flags based on the children's flags.
7765 void Compiler::gtUpdateNodeOperSideEffects(GenTree* tree)
7767 if (tree->OperMayThrow(this))
7769 tree->gtFlags |= GTF_EXCEPT;
7773 tree->gtFlags &= ~GTF_EXCEPT;
7774 if (tree->OperIsIndirOrArrLength())
7776 tree->gtFlags |= GTF_IND_NONFAULTING;
7780 if (tree->OperRequiresAsgFlag())
7782 tree->gtFlags |= GTF_ASG;
7786 tree->gtFlags &= ~GTF_ASG;
7789 if (tree->OperRequiresCallFlag(this))
7791 tree->gtFlags |= GTF_CALL;
7795 tree->gtFlags &= ~GTF_CALL;
7799 //------------------------------------------------------------------------
7800 // gtUpdateNodeSideEffects: Update the side effects based on the node operation and
7801 // children's side efects.
7804 // tree - Tree to update the side effects on
7807 // This method currently only updates GTF_EXCEPT and GTF_ASG flags. The other side effect
7808 // flags may remain unnecessarily (conservatively) set.
7810 void Compiler::gtUpdateNodeSideEffects(GenTree* tree)
7812 gtUpdateNodeOperSideEffects(tree);
7813 unsigned nChildren = tree->NumChildren();
7814 for (unsigned childNum = 0; childNum < nChildren; childNum++)
7816 GenTree* child = tree->GetChild(childNum);
7817 if (child != nullptr)
7819 tree->gtFlags |= (child->gtFlags & GTF_ALL_EFFECT);
7824 //------------------------------------------------------------------------
7825 // fgUpdateSideEffectsPre: Update the side effects based on the tree operation.
7828 // pTree - Pointer to the tree to update the side effects
7829 // fgWalkPre - Walk data
7832 // This method currently only updates GTF_EXCEPT and GTF_ASG flags. The other side effect
7833 // flags may remain unnecessarily (conservatively) set.
7835 Compiler::fgWalkResult Compiler::fgUpdateSideEffectsPre(GenTree** pTree, fgWalkData* fgWalkPre)
7837 fgWalkPre->compiler->gtUpdateNodeOperSideEffects(*pTree);
7839 return WALK_CONTINUE;
7842 //------------------------------------------------------------------------
7843 // fgUpdateSideEffectsPost: Update the side effects of the parent based on the tree's flags.
7846 // pTree - Pointer to the tree
7847 // fgWalkPost - Walk data
7850 // The routine is used for updating the stale side effect flags for ancestor
7851 // nodes starting from treeParent up to the top-level stmt expr.
7853 Compiler::fgWalkResult Compiler::fgUpdateSideEffectsPost(GenTree** pTree, fgWalkData* fgWalkPost)
7855 GenTree* tree = *pTree;
7856 GenTree* parent = fgWalkPost->parent;
7857 if (parent != nullptr)
7859 parent->gtFlags |= (tree->gtFlags & GTF_ALL_EFFECT);
7861 return WALK_CONTINUE;
7864 /*****************************************************************************
7866 * Compares two trees and returns true when both trees are the same.
7867 * Instead of fully comparing the two trees this method can just return false.
7868 * Thus callers should not assume that the trees are different when false is returned.
7869 * Only when true is returned can the caller perform code optimizations.
7870 * The current implementation only compares a limited set of LEAF/CONST node
7871 * and returns false for all othere trees.
7873 bool Compiler::gtCompareTree(GenTree* op1, GenTree* op2)
7875 /* Make sure that both trees are of the same GT node kind */
7876 if (op1->OperGet() != op2->OperGet())
7881 /* Make sure that both trees are returning the same type */
7882 if (op1->gtType != op2->gtType)
7887 /* Figure out what kind of a node we have */
7889 genTreeOps oper = op1->OperGet();
7890 unsigned kind = op1->OperKind();
7892 /* Is this a constant or leaf node? */
7894 if (kind & (GTK_CONST | GTK_LEAF))
7899 if ((op1->gtIntCon.gtIconVal == op2->gtIntCon.gtIconVal) && GenTree::SameIconHandleFlag(op1, op2))
7906 if (op1->gtLngCon.gtLconVal == op2->gtLngCon.gtLconVal)
7913 if (op1->gtStrCon.gtSconCPX == op2->gtStrCon.gtSconCPX)
7920 if (op1->gtLclVarCommon.gtLclNum == op2->gtLclVarCommon.gtLclNum)
7927 if (op1->gtClsVar.gtClsVarHnd == op2->gtClsVar.gtClsVarHnd)
7934 // we return false for these unhandled 'oper' kinds
7941 GenTree* Compiler::gtGetThisArg(GenTreeCall* call)
7943 if (call->gtCallObjp != nullptr)
7945 if (call->gtCallObjp->gtOper != GT_NOP && call->gtCallObjp->gtOper != GT_ASG)
7947 if (!(call->gtCallObjp->gtFlags & GTF_LATE_ARG))
7949 return call->gtCallObjp;
7953 if (call->gtCallLateArgs)
7955 regNumber thisReg = REG_ARG_0;
7956 unsigned argNum = 0;
7957 fgArgTabEntry* thisArgTabEntry = gtArgEntryByArgNum(call, argNum);
7958 GenTree* result = thisArgTabEntry->node;
7960 #if !FEATURE_FIXED_OUT_ARGS
7961 GenTree* lateArgs = call->gtCallLateArgs;
7962 regList list = call->regArgList;
7964 while (lateArgs != NULL)
7966 assert(lateArgs->gtOper == GT_LIST);
7967 assert(index < call->regArgListCount);
7968 regNumber curArgReg = list[index];
7969 if (curArgReg == thisReg)
7971 if (optAssertionPropagatedCurrentStmt)
7972 result = lateArgs->gtOp.gtOp1;
7974 assert(result == lateArgs->gtOp.gtOp1);
7977 lateArgs = lateArgs->gtOp.gtOp2;
7987 bool GenTree::gtSetFlags() const
7990 // When FEATURE_SET_FLAGS (_TARGET_ARM_) is active the method returns true
7991 // when the gtFlags has the flag GTF_SET_FLAGS set
7992 // otherwise the architecture will be have instructions that typically set
7993 // the flags and this method will return true.
7995 // Exceptions: GT_IND (load/store) is not allowed to set the flags
7996 // and on XARCH the GT_MUL/GT_DIV and all overflow instructions
7997 // do not set the condition flags
7999 // Precondition we have a GTK_SMPOP
8001 if (!varTypeIsIntegralOrI(TypeGet()) && (TypeGet() != TYP_VOID))
8006 if (((gtFlags & GTF_SET_FLAGS) != 0) && (gtOper != GT_IND))
8008 // GTF_SET_FLAGS is not valid on GT_IND and is overlaid with GTF_NONFAULTING_IND
8017 bool GenTree::gtRequestSetFlags()
8019 bool result = false;
8021 #if FEATURE_SET_FLAGS
8022 // This method is a Nop unless FEATURE_SET_FLAGS is defined
8024 // In order to set GTF_SET_FLAGS
8025 // we must have a GTK_SMPOP
8026 // and we have a integer or machine size type (not floating point or TYP_LONG on 32-bit)
8028 if (!OperIsSimple())
8031 if (!varTypeIsIntegralOrI(TypeGet()))
8038 // These will turn into simple load from memory instructions
8039 // and we can't force the setting of the flags on load from memory
8044 // These instructions don't set the flags (on x86/x64)
8049 // Otherwise we can set the flags for this gtOper
8050 // and codegen must set the condition flags.
8052 gtFlags |= GTF_SET_FLAGS;
8056 #endif // FEATURE_SET_FLAGS
8058 // Codegen for this tree must set the condition flags if
8059 // this method returns true.
8064 unsigned GenTree::NumChildren()
8066 if (OperIsConst() || OperIsLeaf())
8070 else if (OperIsUnary())
8072 if (OperGet() == GT_NOP || OperGet() == GT_RETURN || OperGet() == GT_RETFILT)
8074 if (gtOp.gtOp1 == nullptr)
8088 else if (OperIsBinary())
8090 // All binary operators except LEA have at least one arg; the second arg may sometimes be null, however.
8091 if (OperGet() == GT_LEA)
8093 unsigned childCount = 0;
8094 if (gtOp.gtOp1 != nullptr)
8098 if (gtOp.gtOp2 != nullptr)
8104 #ifdef FEATURE_HW_INTRINSICS
8105 // GT_HWIntrinsic require special handling
8106 if (OperGet() == GT_HWIntrinsic)
8108 if (gtOp.gtOp1 == nullptr)
8114 assert(gtOp.gtOp1 != nullptr);
8115 if (gtOp.gtOp2 == nullptr)
8132 case GT_ARR_BOUNDS_CHECK:
8135 #endif // FEATURE_SIMD
8136 #ifdef FEATURE_HW_INTRINSICS
8137 case GT_HW_INTRINSIC_CHK:
8138 #endif // FEATURE_HW_INTRINSICS
8146 return 1 + AsArrElem()->gtArrRank;
8152 case GT_STORE_DYN_BLK:
8157 GenTreeCall* call = AsCall();
8158 unsigned res = 0; // arg list(s) (including late args).
8159 if (call->gtCallObjp != nullptr)
8163 if (call->gtCallArgs != nullptr)
8167 if (call->gtCallLateArgs != nullptr)
8169 res++; // Add late args?
8171 if (call->gtControlExpr != nullptr)
8176 if (call->gtCallType == CT_INDIRECT)
8178 if (call->gtCallCookie != nullptr)
8182 if (call->gtCallAddr != nullptr)
8197 GenTree* GenTree::GetChild(unsigned childNum)
8199 assert(childNum < NumChildren()); // Precondition.
8200 assert(NumChildren() <= MAX_CHILDREN);
8201 assert(!(OperIsConst() || OperIsLeaf()));
8204 return AsUnOp()->gtOp1;
8206 // Special case for assignment of dynamic block.
8207 // This code is here to duplicate the former case where the size may be evaluated prior to the
8208 // source and destination addresses. In order to do this, we treat the size as a child of the
8210 // TODO-1stClassStructs: Revisit the need to duplicate former behavior, so that we can remove
8211 // these special cases.
8212 if ((OperGet() == GT_ASG) && (gtOp.gtOp1->OperGet() == GT_DYN_BLK) && (childNum == 2))
8214 return gtOp.gtOp1->AsDynBlk()->gtDynamicSize;
8216 else if (OperIsBinary())
8218 if (OperIsAddrMode())
8220 // If this is the first (0th) child, only return op1 if it is non-null
8221 // Otherwise, we return gtOp2.
8222 if (childNum == 0 && AsOp()->gtOp1 != nullptr)
8224 return AsOp()->gtOp1;
8226 return AsOp()->gtOp2;
8228 // TODO-Cleanup: Consider handling ReverseOps here, and then we wouldn't have to handle it in
8229 // fgGetFirstNode(). However, it seems that it causes loop hoisting behavior to change.
8232 return AsOp()->gtOp1;
8236 return AsOp()->gtOp2;
8248 return AsCmpXchg()->gtOpLocation;
8250 return AsCmpXchg()->gtOpValue;
8252 return AsCmpXchg()->gtOpComparand;
8256 case GT_ARR_BOUNDS_CHECK:
8259 #endif // FEATURE_SIMD
8260 #ifdef FEATURE_HW_INTRINSICS
8261 case GT_HW_INTRINSIC_CHK:
8262 #endif // FEATURE_HW_INTRINSICS
8266 return AsBoundsChk()->gtIndex;
8268 return AsBoundsChk()->gtArrLen;
8273 case GT_STORE_DYN_BLK:
8277 return AsDynBlk()->Addr();
8279 return AsDynBlk()->Data();
8281 return AsDynBlk()->gtDynamicSize;
8289 return AsDynBlk()->gtEvalSizeFirst ? AsDynBlk()->gtDynamicSize : AsDynBlk()->Addr();
8291 return AsDynBlk()->gtEvalSizeFirst ? AsDynBlk()->Addr() : AsDynBlk()->gtDynamicSize;
8297 return AsField()->gtFldObj;
8300 return AsStmt()->gtStmtExpr;
8305 return AsArrElem()->gtArrObj;
8309 return AsArrElem()->gtArrInds[childNum - 1];
8316 return AsArrOffs()->gtOffset;
8318 return AsArrOffs()->gtIndex;
8320 return AsArrOffs()->gtArrObj;
8327 // The if chain below assumes that all possible children are non-null.
8328 // If some are null, "virtually skip them."
8329 // If there isn't "virtually skip it."
8330 GenTreeCall* call = AsCall();
8332 if (call->gtCallObjp == nullptr)
8336 if (childNum >= 1 && call->gtCallArgs == nullptr)
8340 if (childNum >= 2 && call->gtCallLateArgs == nullptr)
8344 if (childNum >= 3 && call->gtControlExpr == nullptr)
8348 if (call->gtCallType == CT_INDIRECT)
8350 if (childNum >= 4 && call->gtCallCookie == nullptr)
8358 return call->gtCallObjp;
8360 else if (childNum == 1)
8362 return call->gtCallArgs;
8364 else if (childNum == 2)
8366 return call->gtCallLateArgs;
8368 else if (childNum == 3)
8370 return call->gtControlExpr;
8374 assert(call->gtCallType == CT_INDIRECT);
8377 return call->gtCallCookie;
8381 assert(childNum == 5);
8382 return call->gtCallAddr;
8394 GenTreeUseEdgeIterator::GenTreeUseEdgeIterator()
8395 : m_advance(nullptr), m_node(nullptr), m_edge(nullptr), m_argList(nullptr), m_state(-1)
8399 GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node)
8400 : m_advance(nullptr), m_node(node), m_edge(nullptr), m_argList(nullptr), m_state(0)
8402 assert(m_node != nullptr);
8404 // NOTE: the switch statement below must be updated when introducing new nodes.
8406 switch (m_node->OperGet())
8411 case GT_LCL_VAR_ADDR:
8412 case GT_LCL_FLD_ADDR:
8421 case GT_MEMORYBARRIER:
8426 case GT_START_NONGC:
8428 #if !FEATURE_EH_FUNCLETS
8430 #endif // !FEATURE_EH_FUNCLETS
8434 case GT_CLS_VAR_ADDR:
8438 case GT_PINVOKE_PROLOG:
8439 case GT_PINVOKE_EPILOG:
8444 // Standard unary operators
8445 case GT_STORE_LCL_VAR:
8446 case GT_STORE_LCL_FLD:
8462 case GT_RUNTIMELOOKUP:
8471 #if FEATURE_ARG_SPLIT
8472 case GT_PUTARG_SPLIT:
8473 #endif // FEATURE_ARG_SPLIT
8475 m_edge = &m_node->AsUnOp()->gtOp1;
8476 assert(*m_edge != nullptr);
8477 m_advance = &GenTreeUseEdgeIterator::Terminate;
8480 // Unary operators with an optional operand
8484 if (m_node->AsUnOp()->gtOp1 == nullptr)
8486 assert(m_node->NullOp1Legal());
8491 m_edge = &m_node->AsUnOp()->gtOp1;
8492 m_advance = &GenTreeUseEdgeIterator::Terminate;
8498 SetEntryStateForList(m_node->AsUnOp()->gtOp1);
8502 SetEntryStateForList(m_node);
8507 if (m_node->AsSIMD()->gtSIMDIntrinsicID == SIMDIntrinsicInitN)
8509 SetEntryStateForList(m_node->AsSIMD()->gtOp1);
8513 SetEntryStateForBinOp();
8516 #endif // FEATURE_SIMD
8518 #ifdef FEATURE_HW_INTRINSICS
8519 case GT_HWIntrinsic:
8520 if (m_node->AsHWIntrinsic()->gtOp1 == nullptr)
8522 assert(m_node->NullOp1Legal());
8525 else if (m_node->AsHWIntrinsic()->gtOp1->OperIsList())
8527 SetEntryStateForList(m_node->AsHWIntrinsic()->gtOp1);
8531 SetEntryStateForBinOp();
8534 #endif // FEATURE_HW_INTRINSICS
8536 // LEA, which may have no first operand
8538 if (m_node->AsAddrMode()->gtOp1 == nullptr)
8540 m_edge = &m_node->AsAddrMode()->gtOp2;
8541 m_advance = &GenTreeUseEdgeIterator::Terminate;
8545 SetEntryStateForBinOp();
8551 m_edge = &m_node->AsCmpXchg()->gtOpLocation;
8552 assert(*m_edge != nullptr);
8553 m_advance = &GenTreeUseEdgeIterator::AdvanceCmpXchg;
8556 case GT_ARR_BOUNDS_CHECK:
8559 #endif // FEATURE_SIMD
8560 #ifdef FEATURE_HW_INTRINSICS
8561 case GT_HW_INTRINSIC_CHK:
8562 #endif // FEATURE_HW_INTRINSICS
8563 m_edge = &m_node->AsBoundsChk()->gtIndex;
8564 assert(*m_edge != nullptr);
8565 m_advance = &GenTreeUseEdgeIterator::AdvanceBoundsChk;
8569 if (m_node->AsField()->gtFldObj == nullptr)
8575 m_edge = &m_node->AsField()->gtFldObj;
8576 m_advance = &GenTreeUseEdgeIterator::Terminate;
8581 if (m_node->AsStmt()->gtStmtExpr == nullptr)
8587 m_edge = &m_node->AsStmt()->gtStmtExpr;
8588 m_advance = &GenTreeUseEdgeIterator::Terminate;
8593 m_edge = &m_node->AsArrElem()->gtArrObj;
8594 assert(*m_edge != nullptr);
8595 m_advance = &GenTreeUseEdgeIterator::AdvanceArrElem;
8599 m_edge = &m_node->AsArrOffs()->gtOffset;
8600 assert(*m_edge != nullptr);
8601 m_advance = &GenTreeUseEdgeIterator::AdvanceArrOffset;
8606 GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
8607 m_edge = dynBlock->gtEvalSizeFirst ? &dynBlock->gtDynamicSize : &dynBlock->gtOp1;
8608 assert(*m_edge != nullptr);
8609 m_advance = &GenTreeUseEdgeIterator::AdvanceDynBlk;
8613 case GT_STORE_DYN_BLK:
8615 GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
8616 if (dynBlock->gtEvalSizeFirst)
8618 m_edge = &dynBlock->gtDynamicSize;
8622 m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp2 : &dynBlock->gtOp1;
8624 assert(*m_edge != nullptr);
8626 m_advance = &GenTreeUseEdgeIterator::AdvanceStoreDynBlk;
8631 AdvanceCall<CALL_INSTANCE>();
8636 assert(m_node->OperIsBinary());
8637 SetEntryStateForBinOp();
8642 //------------------------------------------------------------------------
8643 // GenTreeUseEdgeIterator::AdvanceCmpXchg: produces the next operand of a CmpXchg node and advances the state.
8645 void GenTreeUseEdgeIterator::AdvanceCmpXchg()
8650 m_edge = &m_node->AsCmpXchg()->gtOpValue;
8654 m_edge = &m_node->AsCmpXchg()->gtOpComparand;
8655 m_advance = &GenTreeUseEdgeIterator::Terminate;
8661 assert(*m_edge != nullptr);
8664 //------------------------------------------------------------------------
8665 // GenTreeUseEdgeIterator::AdvanceBoundsChk: produces the next operand of a BoundsChk node and advances the state.
8667 void GenTreeUseEdgeIterator::AdvanceBoundsChk()
8669 m_edge = &m_node->AsBoundsChk()->gtArrLen;
8670 assert(*m_edge != nullptr);
8671 m_advance = &GenTreeUseEdgeIterator::Terminate;
8674 //------------------------------------------------------------------------
8675 // GenTreeUseEdgeIterator::AdvanceArrElem: produces the next operand of a ArrElem node and advances the state.
8677 // Because these nodes are variadic, this function uses `m_state` to index into the list of array indices.
8679 void GenTreeUseEdgeIterator::AdvanceArrElem()
8681 if (m_state < m_node->AsArrElem()->gtArrRank)
8683 m_edge = &m_node->AsArrElem()->gtArrInds[m_state];
8684 assert(*m_edge != nullptr);
8693 //------------------------------------------------------------------------
8694 // GenTreeUseEdgeIterator::AdvanceArrOffset: produces the next operand of a ArrOffset node and advances the state.
8696 void GenTreeUseEdgeIterator::AdvanceArrOffset()
8701 m_edge = &m_node->AsArrOffs()->gtIndex;
8705 m_edge = &m_node->AsArrOffs()->gtArrObj;
8706 m_advance = &GenTreeUseEdgeIterator::Terminate;
8712 assert(*m_edge != nullptr);
8715 //------------------------------------------------------------------------
8716 // GenTreeUseEdgeIterator::AdvanceDynBlk: produces the next operand of a DynBlk node and advances the state.
8718 void GenTreeUseEdgeIterator::AdvanceDynBlk()
8720 GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
8722 m_edge = dynBlock->gtEvalSizeFirst ? &dynBlock->gtOp1 : &dynBlock->gtDynamicSize;
8723 assert(*m_edge != nullptr);
8724 m_advance = &GenTreeUseEdgeIterator::Terminate;
8727 //------------------------------------------------------------------------
8728 // GenTreeUseEdgeIterator::AdvanceStoreDynBlk: produces the next operand of a StoreDynBlk node and advances the state.
8730 // These nodes are moderately complicated but rare enough that templating this function is probably not
8731 // worth the extra complexity.
8733 void GenTreeUseEdgeIterator::AdvanceStoreDynBlk()
8735 GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
8736 if (dynBlock->gtEvalSizeFirst)
8741 m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp2 : &dynBlock->gtOp1;
8745 m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp1 : &dynBlock->gtOp2;
8746 m_advance = &GenTreeUseEdgeIterator::Terminate;
8757 m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp1 : &dynBlock->gtOp2;
8761 m_edge = &dynBlock->gtDynamicSize;
8762 m_advance = &GenTreeUseEdgeIterator::Terminate;
8769 assert(*m_edge != nullptr);
8772 //------------------------------------------------------------------------
8773 // GenTreeUseEdgeIterator::AdvanceBinOp: produces the next operand of a binary node and advances the state.
8775 // This function must be instantiated s.t. `ReverseOperands` is `true` iff the node is marked with the
8776 // `GTF_REVERSE_OPS` flag.
8778 template <bool ReverseOperands>
8779 void GenTreeUseEdgeIterator::AdvanceBinOp()
8781 assert(ReverseOperands == ((m_node->gtFlags & GTF_REVERSE_OPS) != 0));
8783 m_edge = !ReverseOperands ? &m_node->AsOp()->gtOp2 : &m_node->AsOp()->gtOp1;
8784 assert(*m_edge != nullptr);
8785 m_advance = &GenTreeUseEdgeIterator::Terminate;
8788 //------------------------------------------------------------------------
8789 // GenTreeUseEdgeIterator::SetEntryStateForBinOp: produces the first operand of a binary node and chooses
8790 // the appropriate advance function.
8792 void GenTreeUseEdgeIterator::SetEntryStateForBinOp()
8794 assert(m_node != nullptr);
8795 assert(m_node->OperIsBinary());
8797 GenTreeOp* const node = m_node->AsOp();
8799 if (node->gtOp2 == nullptr)
8801 assert(node->gtOp1 != nullptr);
8802 assert(node->NullOp2Legal());
8803 m_edge = &node->gtOp1;
8804 m_advance = &GenTreeUseEdgeIterator::Terminate;
8806 else if ((node->gtFlags & GTF_REVERSE_OPS) != 0)
8808 m_edge = &m_node->AsOp()->gtOp2;
8809 m_advance = &GenTreeUseEdgeIterator::AdvanceBinOp<true>;
8813 m_edge = &m_node->AsOp()->gtOp1;
8814 m_advance = &GenTreeUseEdgeIterator::AdvanceBinOp<false>;
8818 //------------------------------------------------------------------------
8819 // GenTreeUseEdgeIterator::AdvanceList: produces the next operand of a variadic node and advances the state.
8821 // This function does not use `m_state` for anything meaningful; it simply walks the `m_argList` until
8822 // there are no further entries.
8824 void GenTreeUseEdgeIterator::AdvanceList()
8826 assert(m_state == 0);
8828 if (m_argList == nullptr)
8834 GenTreeArgList* listNode = m_argList->AsArgList();
8835 m_edge = &listNode->gtOp1;
8836 m_argList = listNode->Rest();
8840 //------------------------------------------------------------------------
8841 // GenTreeUseEdgeIterator::SetEntryStateForList: produces the first operand of a list node.
8843 void GenTreeUseEdgeIterator::SetEntryStateForList(GenTree* list)
8846 m_advance = &GenTreeUseEdgeIterator::AdvanceList;
8850 //------------------------------------------------------------------------
8851 // GenTreeUseEdgeIterator::AdvanceCall: produces the next operand of a call node and advances the state.
8853 // This function is a bit tricky: in order to avoid doing unnecessary work, it is instantiated with the
8854 // state number the iterator will be in when it is called. For example, `AdvanceCall<CALL_INSTANCE>`
8855 // is the instantiation used when the iterator is at the `CALL_INSTANCE` state (i.e. the entry state).
8856 // This sort of templating allows each state to avoid processing earlier states without unnecessary
8857 // duplication of code.
8859 // Note that this method expands the argument lists (`gtCallArgs` and `gtCallLateArgs`) into their
8860 // component operands.
8862 template <int state>
8863 void GenTreeUseEdgeIterator::AdvanceCall()
8865 GenTreeCall* const call = m_node->AsCall();
8870 m_argList = call->gtCallArgs;
8871 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_ARGS>;
8872 if (call->gtCallObjp != nullptr)
8874 m_edge = &call->gtCallObjp;
8880 if (m_argList != nullptr)
8882 GenTreeArgList* argNode = m_argList->AsArgList();
8883 m_edge = &argNode->gtOp1;
8884 m_argList = argNode->Rest();
8887 m_argList = call->gtCallLateArgs;
8888 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_LATE_ARGS>;
8891 case CALL_LATE_ARGS:
8892 if (m_argList != nullptr)
8894 GenTreeArgList* argNode = m_argList->AsArgList();
8895 m_edge = &argNode->gtOp1;
8896 m_argList = argNode->Rest();
8899 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_CONTROL_EXPR>;
8902 case CALL_CONTROL_EXPR:
8903 if (call->gtControlExpr != nullptr)
8905 if (call->gtCallType == CT_INDIRECT)
8907 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_COOKIE>;
8911 m_advance = &GenTreeUseEdgeIterator::Terminate;
8913 m_edge = &call->gtControlExpr;
8916 else if (call->gtCallType != CT_INDIRECT)
8924 assert(call->gtCallType == CT_INDIRECT);
8926 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_ADDRESS>;
8927 if (call->gtCallCookie != nullptr)
8929 m_edge = &call->gtCallCookie;
8935 assert(call->gtCallType == CT_INDIRECT);
8937 m_advance = &GenTreeUseEdgeIterator::Terminate;
8938 if (call->gtCallAddr != nullptr)
8940 m_edge = &call->gtCallAddr;
8949 //------------------------------------------------------------------------
8950 // GenTreeUseEdgeIterator::Terminate: advances the iterator to the terminal state.
8952 void GenTreeUseEdgeIterator::Terminate()
8957 //------------------------------------------------------------------------
8958 // GenTreeUseEdgeIterator::operator++: advances the iterator to the next operand.
8960 GenTreeUseEdgeIterator& GenTreeUseEdgeIterator::operator++()
8962 // If we've reached the terminal state, do nothing.
8965 (this->*m_advance)();
8971 GenTreeUseEdgeIterator GenTree::UseEdgesBegin()
8973 return GenTreeUseEdgeIterator(this);
8976 GenTreeUseEdgeIterator GenTree::UseEdgesEnd()
8978 return GenTreeUseEdgeIterator();
8981 IteratorPair<GenTreeUseEdgeIterator> GenTree::UseEdges()
8983 return MakeIteratorPair(UseEdgesBegin(), UseEdgesEnd());
8986 GenTreeOperandIterator GenTree::OperandsBegin()
8988 return GenTreeOperandIterator(this);
8991 GenTreeOperandIterator GenTree::OperandsEnd()
8993 return GenTreeOperandIterator();
8996 IteratorPair<GenTreeOperandIterator> GenTree::Operands()
8998 return MakeIteratorPair(OperandsBegin(), OperandsEnd());
9001 bool GenTree::Precedes(GenTree* other)
9003 assert(other != nullptr);
9005 for (GenTree* node = gtNext; node != nullptr; node = node->gtNext)
9018 /* static */ int GenTree::gtDispFlags(unsigned flags, unsigned debugFlags)
9020 int charsDisplayed = 11; // 11 is the "baseline" number of flag characters displayed
9022 printf("%c", (flags & GTF_ASG) ? 'A' : (IsContained(flags) ? 'c' : '-'));
9023 printf("%c", (flags & GTF_CALL) ? 'C' : '-');
9024 printf("%c", (flags & GTF_EXCEPT) ? 'X' : '-');
9025 printf("%c", (flags & GTF_GLOB_REF) ? 'G' : '-');
9026 printf("%c", (debugFlags & GTF_DEBUG_NODE_MORPHED) ? '+' : // First print '+' if GTF_DEBUG_NODE_MORPHED is set
9027 (flags & GTF_ORDER_SIDEEFF) ? 'O' : '-'); // otherwise print 'O' or '-'
9028 printf("%c", (flags & GTF_COLON_COND) ? '?' : '-');
9029 printf("%c", (flags & GTF_DONT_CSE) ? 'N' : // N is for No cse
9030 (flags & GTF_MAKE_CSE) ? 'H' : '-'); // H is for Hoist this expr
9031 printf("%c", (flags & GTF_REVERSE_OPS) ? 'R' : '-');
9032 printf("%c", (flags & GTF_UNSIGNED) ? 'U' : (flags & GTF_BOOLEAN) ? 'B' : '-');
9033 #if FEATURE_SET_FLAGS
9034 printf("%c", (flags & GTF_SET_FLAGS) ? 'S' : '-');
9037 printf("%c", (flags & GTF_LATE_ARG) ? 'L' : '-');
9038 printf("%c", (flags & GTF_SPILLED) ? 'z' : (flags & GTF_SPILL) ? 'Z' : '-');
9040 return charsDisplayed;
9043 /*****************************************************************************/
9045 void Compiler::gtDispNodeName(GenTree* tree)
9047 /* print the node name */
9052 if (tree->gtOper < GT_COUNT)
9054 name = GenTree::OpName(tree->OperGet());
9061 char* bufp = &buf[0];
9063 if ((tree->gtOper == GT_CNS_INT) && tree->IsIconHandle())
9065 sprintf_s(bufp, sizeof(buf), " %s(h)%c", name, 0);
9067 else if (tree->gtOper == GT_PUTARG_STK)
9069 sprintf_s(bufp, sizeof(buf), " %s [+0x%02x]%c", name, tree->AsPutArgStk()->getArgOffset(), 0);
9071 else if (tree->gtOper == GT_CALL)
9073 const char* callType = "CALL";
9074 const char* gtfType = "";
9075 const char* ctType = "";
9076 char gtfTypeBuf[100];
9078 if (tree->gtCall.gtCallType == CT_USER_FUNC)
9080 if (tree->gtCall.IsVirtual())
9085 else if (tree->gtCall.gtCallType == CT_HELPER)
9089 else if (tree->gtCall.gtCallType == CT_INDIRECT)
9095 assert(!"Unknown gtCallType");
9098 if (tree->gtFlags & GTF_CALL_NULLCHECK)
9100 gtfType = " nullcheck";
9102 if (tree->gtCall.IsVirtualVtable())
9106 else if (tree->gtCall.IsVirtualStub())
9110 #ifdef FEATURE_READYTORUN_COMPILER
9111 else if (tree->gtCall.IsR2RRelativeIndir())
9113 gtfType = " r2r_ind";
9115 #endif // FEATURE_READYTORUN_COMPILER
9116 else if (tree->gtFlags & GTF_CALL_UNMANAGED)
9118 char* gtfTypeBufWalk = gtfTypeBuf;
9119 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " unman");
9120 if (tree->gtFlags & GTF_CALL_POP_ARGS)
9122 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " popargs");
9124 if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
9126 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " thiscall");
9128 gtfType = gtfTypeBuf;
9131 sprintf_s(bufp, sizeof(buf), " %s%s%s%c", callType, ctType, gtfType, 0);
9133 else if (tree->gtOper == GT_ARR_ELEM)
9135 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s[", name);
9136 for (unsigned rank = tree->gtArrElem.gtArrRank - 1; rank; rank--)
9138 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), ",");
9140 SimpleSprintf_s(bufp, buf, sizeof(buf), "]");
9142 else if (tree->gtOper == GT_ARR_OFFSET || tree->gtOper == GT_ARR_INDEX)
9144 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s[", name);
9145 unsigned char currDim;
9147 if (tree->gtOper == GT_ARR_OFFSET)
9149 currDim = tree->gtArrOffs.gtCurrDim;
9150 rank = tree->gtArrOffs.gtArrRank;
9154 currDim = tree->gtArrIndex.gtCurrDim;
9155 rank = tree->gtArrIndex.gtArrRank;
9158 for (unsigned char dim = 0; dim < rank; dim++)
9160 // Use a defacto standard i,j,k for the dimensions.
9161 // Note that we only support up to rank 3 arrays with these nodes, so we won't run out of characters.
9165 dimChar = 'i' + dim;
9167 else if (dim > currDim)
9172 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "%c", dimChar);
9173 if (dim != rank - 1)
9175 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), ",");
9178 SimpleSprintf_s(bufp, buf, sizeof(buf), "]");
9180 else if (tree->gtOper == GT_LEA)
9182 GenTreeAddrMode* lea = tree->AsAddrMode();
9183 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s(", name);
9184 if (lea->Base() != nullptr)
9186 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "b+");
9188 if (lea->Index() != nullptr)
9190 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "(i*%d)+", lea->gtScale);
9192 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "%d)", lea->Offset());
9194 else if (tree->gtOper == GT_ARR_BOUNDS_CHECK)
9196 switch (tree->gtBoundsChk.gtThrowKind)
9198 case SCK_RNGCHK_FAIL:
9199 sprintf_s(bufp, sizeof(buf), " %s_Rng", name);
9202 sprintf_s(bufp, sizeof(buf), " %s_Arg", name);
9204 case SCK_ARG_RNG_EXCPN:
9205 sprintf_s(bufp, sizeof(buf), " %s_ArgRng", name);
9211 else if (tree->gtOverflowEx())
9213 sprintf_s(bufp, sizeof(buf), " %s_ovfl%c", name, 0);
9215 else if (tree->OperIsBlk() && !tree->OperIsDynBlk())
9217 sprintf_s(bufp, sizeof(buf), " %s(%d)", name, tree->AsBlk()->gtBlkSize);
9221 sprintf_s(bufp, sizeof(buf), " %s%c", name, 0);
9224 if (strlen(buf) < 10)
9226 printf(" %-10s", buf);
9234 void Compiler::gtDispVN(GenTree* tree)
9236 if (tree->gtVNPair.GetLiberal() != ValueNumStore::NoVN)
9238 assert(tree->gtVNPair.GetConservative() != ValueNumStore::NoVN);
9240 vnpPrint(tree->gtVNPair, 0);
9244 //------------------------------------------------------------------------
9245 // gtDispNode: Print a tree to jitstdout.
9248 // tree - the tree to be printed
9249 // indentStack - the specification for the current level of indentation & arcs
9250 // msg - a contextual method (i.e. from the parent) to print
9256 // 'indentStack' may be null, in which case no indentation or arcs are printed
9257 // 'msg' may be null
9259 void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, __in __in_z __in_opt const char* msg, bool isLIR)
9261 bool printPointer = true; // always true..
9262 bool printFlags = true; // always true..
9263 bool printCost = true; // always true..
9271 printf("N%03u ", tree->gtSeqNum);
9272 if (tree->gtCostsInitialized)
9274 printf("(%3u,%3u) ", tree->gtCostEx, tree->gtCostSz);
9280 ") "); // This probably indicates a bug: the node has a sequence number, but not costs.
9285 if (tree->gtOper == GT_STMT)
9287 prev = tree->gtStmt.gtStmtExpr;
9294 bool hasSeqNum = true;
9295 unsigned dotNum = 0;
9299 prev = prev->gtPrev;
9301 if ((prev == nullptr) || (prev == tree))
9308 } while (prev->gtSeqNum == 0);
9310 // If we have an indent stack, don't add additional characters,
9311 // as it will mess up the alignment.
9312 bool displayDotNum = tree->gtOper != GT_STMT && hasSeqNum && (indentStack == nullptr);
9315 printf("N%03u.%02u ", prev->gtSeqNum, dotNum);
9322 if (tree->gtCostsInitialized)
9324 printf("(%3u,%3u) ", tree->gtCostEx, tree->gtCostSz);
9330 // Do better alignment in this case
9340 if (optValnumCSE_phase)
9342 if (IS_CSE_INDEX(tree->gtCSEnum))
9344 printf("CSE #%02d (%s)", GET_CSE_INDEX(tree->gtCSEnum), (IS_CSE_USE(tree->gtCSEnum) ? "use" : "def"));
9352 /* Print the node ID */
9356 if (tree->gtOper >= GT_COUNT)
9358 printf(" **** ILLEGAL NODE ****");
9364 /* First print the flags associated with the node */
9365 switch (tree->gtOper)
9373 case GT_STORE_DYN_BLK:
9376 // We prefer printing V or U
9377 if ((tree->gtFlags & (GTF_IND_VOLATILE | GTF_IND_UNALIGNED)) == 0)
9379 if (tree->gtFlags & GTF_IND_TGTANYWHERE)
9385 if (tree->gtFlags & GTF_IND_INVARIANT)
9391 if (tree->gtFlags & GTF_IND_ARR_INDEX)
9397 if (tree->gtFlags & GTF_IND_NONFAULTING)
9399 printf("n"); // print a n for non-faulting
9403 if (tree->gtFlags & GTF_IND_ASG_LHS)
9405 printf("D"); // print a D for definition
9415 if ((tree->gtFlags & (GTF_IND_VOLATILE | GTF_IND_UNALIGNED)) == 0) // We prefer printing V or U over R
9417 if (tree->gtFlags & GTF_INX_REFARR_LAYOUT)
9422 } // R means RefArray
9428 if (tree->gtFlags & GTF_IND_VOLATILE)
9434 if (tree->gtFlags & GTF_IND_UNALIGNED)
9443 if (tree->OperIsInitBlkOp())
9452 if (tree->gtCall.IsInlineCandidate())
9454 if (tree->gtCall.IsGuardedDevirtualizationCandidate())
9465 else if (tree->gtCall.IsGuardedDevirtualizationCandidate())
9471 if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_RETBUFFARG)
9477 if (tree->gtFlags & GTF_CALL_HOISTABLE)
9487 #if !defined(_TARGET_64BIT_)
9490 if (tree->gtFlags & GTF_MUL_64RSLT)
9499 if (tree->gtFlags & GTF_ADDR_ONSTACK)
9509 case GT_LCL_VAR_ADDR:
9510 case GT_LCL_FLD_ADDR:
9511 case GT_STORE_LCL_FLD:
9512 case GT_STORE_LCL_VAR:
9513 if (tree->gtFlags & GTF_VAR_USEASG)
9519 if (tree->gtFlags & GTF_VAR_DEF)
9525 if (tree->gtFlags & GTF_VAR_CAST)
9531 if (tree->gtFlags & GTF_VAR_ARR_INDEX)
9547 if (tree->gtFlags & GTF_RELOP_NAN_UN)
9553 if (tree->gtFlags & GTF_RELOP_JMP_USED)
9559 if (tree->gtFlags & GTF_RELOP_QMARK)
9568 printf((tree->gtFlags & GTF_JCMP_TST) ? "T" : "C");
9569 printf((tree->gtFlags & GTF_JCMP_EQ) ? "EQ" : "NE");
9573 if (tree->gtFlags & GTF_FIELD_LIST_HEAD)
9588 /* Then print the general purpose flags */
9589 unsigned flags = tree->gtFlags;
9591 if (tree->OperIsBinary())
9593 genTreeOps oper = tree->OperGet();
9595 // Check for GTF_ADDRMODE_NO_CSE flag on add/mul/shl Binary Operators
9596 if ((oper == GT_ADD) || (oper == GT_MUL) || (oper == GT_LSH))
9598 if ((tree->gtFlags & GTF_ADDRMODE_NO_CSE) != 0)
9600 flags |= GTF_DONT_CSE; // Force the GTF_ADDRMODE_NO_CSE flag to print out like GTF_DONT_CSE
9604 else // !tree->OperIsBinary()
9606 // the GTF_REVERSE flag only applies to binary operations
9607 flags &= ~GTF_REVERSE_OPS; // we use this value for GTF_VAR_ARR_INDEX above
9610 msgLength -= GenTree::gtDispFlags(flags, tree->gtDebugFlags);
9612 printf("%c", (flags & GTF_ASG ) ? 'A' : '-');
9613 printf("%c", (flags & GTF_CALL ) ? 'C' : '-');
9614 printf("%c", (flags & GTF_EXCEPT ) ? 'X' : '-');
9615 printf("%c", (flags & GTF_GLOB_REF ) ? 'G' : '-');
9616 printf("%c", (flags & GTF_ORDER_SIDEEFF ) ? 'O' : '-');
9617 printf("%c", (flags & GTF_COLON_COND ) ? '?' : '-');
9618 printf("%c", (flags & GTF_DONT_CSE ) ? 'N' : // N is for No cse
9619 (flags & GTF_MAKE_CSE ) ? 'H' : '-'); // H is for Hoist this expr
9620 printf("%c", (flags & GTF_REVERSE_OPS ) ? 'R' : '-');
9621 printf("%c", (flags & GTF_UNSIGNED ) ? 'U' :
9622 (flags & GTF_BOOLEAN ) ? 'B' : '-');
9623 printf("%c", (flags & GTF_SET_FLAGS ) ? 'S' : '-');
9624 printf("%c", (flags & GTF_SPILLED ) ? 'z' : '-');
9625 printf("%c", (flags & GTF_SPILL ) ? 'Z' : '-');
9629 // If we're printing a node for LIR, we use the space normally associated with the message
9630 // to display the node's temp name (if any)
9631 const bool hasOperands = tree->OperandsBegin() != tree->OperandsEnd();
9634 assert(msg == nullptr);
9636 // If the tree does not have any operands, we do not display the indent stack. This gives us
9637 // two additional characters for alignment.
9643 if (tree->IsValue())
9645 const size_t bufLength = msgLength - 1;
9646 msg = reinterpret_cast<char*>(alloca(bufLength * sizeof(char)));
9647 sprintf_s(const_cast<char*>(msg), bufLength, "t%d = %s", tree->gtTreeID, hasOperands ? "" : " ");
9651 /* print the msg associated with the node */
9662 printf(isLIR ? " %+*s" : " %-*s", msgLength, msg);
9664 /* Indent the node accordingly */
9665 if (!isLIR || hasOperands)
9667 printIndent(indentStack);
9670 gtDispNodeName(tree);
9672 assert(tree == nullptr || tree->gtOper < GT_COUNT);
9676 /* print the type of the node */
9677 if (tree->gtOper != GT_CAST)
9679 printf(" %-6s", varTypeName(tree->TypeGet()));
9680 if (tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_STORE_LCL_VAR)
9682 LclVarDsc* varDsc = &lvaTable[tree->gtLclVarCommon.gtLclNum];
9683 if (varDsc->lvAddrExposed)
9685 printf("(AX)"); // Variable has address exposed.
9688 if (varDsc->lvUnusedStruct)
9690 assert(varDsc->lvPromoted);
9691 printf("(U)"); // Unused struct
9693 else if (varDsc->lvPromoted)
9695 if (varTypeIsPromotable(varDsc))
9697 printf("(P)"); // Promoted struct
9701 // Promoted implicit by-refs can have this state during
9702 // global morph while they are being rewritten
9703 assert(fgGlobalMorph);
9704 printf("(P?!)"); // Promoted struct
9709 if (tree->gtOper == GT_STMT)
9711 if (opts.compDbgInfo)
9713 IL_OFFSET endIL = tree->gtStmt.gtStmtLastILoffs;
9716 if (tree->gtStmt.gtStmtILoffsx == BAD_IL_OFFSET)
9722 printf("0x%03X", jitGetILoffs(tree->gtStmt.gtStmtILoffsx));
9725 if (endIL == BAD_IL_OFFSET)
9731 printf("0x%03X", endIL);
9737 if (tree->IsArgPlaceHolderNode() && (tree->gtArgPlace.gtArgPlaceClsHnd != nullptr))
9739 printf(" => [clsHnd=%08X]", dspPtr(tree->gtArgPlace.gtArgPlaceClsHnd));
9742 if (tree->gtOper == GT_RUNTIMELOOKUP)
9744 #ifdef _TARGET_64BIT_
9745 printf(" 0x%llx", dspPtr(tree->gtRuntimeLookup.gtHnd));
9747 printf(" 0x%x", dspPtr(tree->gtRuntimeLookup.gtHnd));
9750 switch (tree->gtRuntimeLookup.gtHndType)
9752 case CORINFO_HANDLETYPE_CLASS:
9755 case CORINFO_HANDLETYPE_METHOD:
9758 case CORINFO_HANDLETYPE_FIELD:
9768 // for tracking down problems in reguse prediction or liveness tracking
9773 dspRegMask(tree->gtRsvdRegs);
9779 void Compiler::gtDispRegVal(GenTree* tree)
9781 switch (tree->GetRegTag())
9783 // Don't display NOREG; the absence of this tag will imply this state
9784 // case GenTree::GT_REGTAG_NONE: printf(" NOREG"); break;
9786 case GenTree::GT_REGTAG_REG:
9787 printf(" REG %s", compRegVarName(tree->gtRegNum));
9794 if (tree->IsMultiRegCall())
9796 // 0th reg is gtRegNum, which is already printed above.
9797 // Print the remaining regs of a multi-reg call node.
9798 GenTreeCall* call = tree->AsCall();
9799 unsigned regCount = call->GetReturnTypeDesc()->TryGetReturnRegCount();
9800 for (unsigned i = 1; i < regCount; ++i)
9802 printf(",%s", compRegVarName(call->GetRegNumByIdx(i)));
9805 else if (tree->IsCopyOrReloadOfMultiRegCall())
9807 GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
9808 GenTreeCall* call = tree->gtGetOp1()->AsCall();
9809 unsigned regCount = call->GetReturnTypeDesc()->TryGetReturnRegCount();
9810 for (unsigned i = 1; i < regCount; ++i)
9812 printf(",%s", compRegVarName(copyOrReload->GetRegNumByIdx(i)));
9816 #if FEATURE_MULTIREG_RET
9817 if (tree->IsCopyOrReload())
9819 for (int i = 1; i < MAX_RET_REG_COUNT; i++)
9821 regNumber reg = (regNumber)tree->AsCopyOrReload()->GetRegNumByIdx(i);
9826 printf(",%s", compRegVarName(reg));
9831 #if defined(_TARGET_ARM_)
9832 if (tree->OperIsMultiRegOp() && (tree->AsMultiRegOp()->gtOtherReg != REG_NA))
9834 printf(",%s", compRegVarName(tree->AsMultiRegOp()->gtOtherReg));
9839 // We usually/commonly don't expect to print anything longer than this string,
9840 #define LONGEST_COMMON_LCL_VAR_DISPLAY "V99 PInvokeFrame"
9841 #define LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH (sizeof(LONGEST_COMMON_LCL_VAR_DISPLAY))
9842 #define BUF_SIZE (LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH * 2)
9844 void Compiler::gtGetLclVarNameInfo(unsigned lclNum, const char** ilKindOut, const char** ilNameOut, unsigned* ilNumOut)
9846 const char* ilKind = nullptr;
9847 const char* ilName = nullptr;
9849 unsigned ilNum = compMap2ILvarNum(lclNum);
9851 if (ilNum == (unsigned)ICorDebugInfo::RETBUF_ILNUM)
9855 else if (ilNum == (unsigned)ICorDebugInfo::VARARGS_HND_ILNUM)
9857 ilName = "VarArgHandle";
9859 else if (ilNum == (unsigned)ICorDebugInfo::TYPECTXT_ILNUM)
9863 else if (ilNum == (unsigned)ICorDebugInfo::UNKNOWN_ILNUM)
9866 if (lclNumIsTrueCSE(lclNum))
9869 ilNum = lclNum - optCSEstart;
9871 else if (lclNum >= optCSEstart)
9873 // Currently any new LclVar's introduced after the CSE phase
9874 // are believed to be created by the "rationalizer" that is what is meant by the "rat" prefix.
9876 ilNum = lclNum - (optCSEstart + optCSEcount);
9879 #endif // FEATURE_ANYCSE
9881 if (lclNum == info.compLvFrameListRoot)
9883 ilName = "FramesRoot";
9885 else if (lclNum == lvaInlinedPInvokeFrameVar)
9887 ilName = "PInvokeFrame";
9889 else if (lclNum == lvaGSSecurityCookie)
9891 ilName = "GsCookie";
9893 #if FEATURE_FIXED_OUT_ARGS
9894 else if (lclNum == lvaPInvokeFrameRegSaveVar)
9896 ilName = "PInvokeFrameRegSave";
9898 else if (lclNum == lvaOutgoingArgSpaceVar)
9902 #endif // FEATURE_FIXED_OUT_ARGS
9904 else if (lclNum == lvaPromotedStructAssemblyScratchVar)
9906 ilName = "PromotedStructScratch";
9908 #endif // _TARGET_ARM_
9909 #if !FEATURE_EH_FUNCLETS
9910 else if (lclNum == lvaShadowSPslotsVar)
9914 #endif // !FEATURE_EH_FUNCLETS
9915 #ifdef JIT32_GCENCODER
9916 else if (lclNum == lvaLocAllocSPvar)
9918 ilName = "LocAllocSP";
9920 #endif // JIT32_GCENCODER
9921 #if FEATURE_EH_FUNCLETS
9922 else if (lclNum == lvaPSPSym)
9926 #endif // FEATURE_EH_FUNCLETS
9930 if (compIsForInlining())
9932 ilNum = lclNum - impInlineInfo->InlinerCompiler->info.compLocalsCount;
9936 ilNum = lclNum - info.compLocalsCount;
9941 else if (lclNum < (compIsForInlining() ? impInlineInfo->InlinerCompiler->info.compArgsCount : info.compArgsCount))
9943 if (ilNum == 0 && !info.compIsStatic)
9954 if (!lvaTable[lclNum].lvIsStructField)
9958 if (compIsForInlining())
9960 ilNum -= impInlineInfo->InlinerCompiler->info.compILargsCount;
9964 ilNum -= info.compILargsCount;
9968 *ilKindOut = ilKind;
9969 *ilNameOut = ilName;
9973 /*****************************************************************************/
9974 int Compiler::gtGetLclVarName(unsigned lclNum, char* buf, unsigned buf_remaining)
9976 char* bufp_next = buf;
9977 unsigned charsPrinted = 0;
9980 sprintf_result = sprintf_s(bufp_next, buf_remaining, "V%02u", lclNum);
9982 if (sprintf_result < 0)
9984 return sprintf_result;
9987 charsPrinted += sprintf_result;
9988 bufp_next += sprintf_result;
9989 buf_remaining -= sprintf_result;
9991 const char* ilKind = nullptr;
9992 const char* ilName = nullptr;
9995 gtGetLclVarNameInfo(lclNum, &ilKind, &ilName, &ilNum);
9997 if (ilName != nullptr)
9999 sprintf_result = sprintf_s(bufp_next, buf_remaining, " %s", ilName);
10000 if (sprintf_result < 0)
10002 return sprintf_result;
10004 charsPrinted += sprintf_result;
10005 bufp_next += sprintf_result;
10006 buf_remaining -= sprintf_result;
10008 else if (ilKind != nullptr)
10010 sprintf_result = sprintf_s(bufp_next, buf_remaining, " %s%d", ilKind, ilNum);
10011 if (sprintf_result < 0)
10013 return sprintf_result;
10015 charsPrinted += sprintf_result;
10016 bufp_next += sprintf_result;
10017 buf_remaining -= sprintf_result;
10020 assert(charsPrinted > 0);
10021 assert(buf_remaining > 0);
10023 return (int)charsPrinted;
10026 /*****************************************************************************
10027 * Get the local var name, and create a copy of the string that can be used in debug output.
10029 char* Compiler::gtGetLclVarName(unsigned lclNum)
10031 char buf[BUF_SIZE];
10032 int charsPrinted = gtGetLclVarName(lclNum, buf, _countof(buf));
10033 if (charsPrinted < 0)
10038 char* retBuf = new (this, CMK_DebugOnly) char[charsPrinted + 1];
10039 strcpy_s(retBuf, charsPrinted + 1, buf);
10043 /*****************************************************************************/
10044 void Compiler::gtDispLclVar(unsigned lclNum, bool padForBiggestDisp)
10046 char buf[BUF_SIZE];
10047 int charsPrinted = gtGetLclVarName(lclNum, buf, _countof(buf));
10049 if (charsPrinted < 0)
10056 if (padForBiggestDisp && (charsPrinted < LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH))
10058 printf("%*c", LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH - charsPrinted, ' ');
10062 /*****************************************************************************/
10063 void Compiler::gtDispConst(GenTree* tree)
10065 assert(tree->OperKind() & GTK_CONST);
10067 switch (tree->gtOper)
10070 if (tree->IsIconHandle(GTF_ICON_STR_HDL))
10072 const wchar_t* str = eeGetCPString(tree->gtIntCon.gtIconVal);
10073 if (str != nullptr)
10075 printf(" 0x%X \"%S\"", dspPtr(tree->gtIntCon.gtIconVal), str);
10079 // Note that eGetCPString isn't currently implemented on Linux/ARM
10080 // and instead always returns nullptr
10081 printf(" 0x%X [ICON_STR_HDL]", dspPtr(tree->gtIntCon.gtIconVal));
10086 ssize_t dspIconVal = tree->IsIconHandle() ? dspPtr(tree->gtIntCon.gtIconVal) : tree->gtIntCon.gtIconVal;
10088 if (tree->TypeGet() == TYP_REF)
10090 assert(tree->gtIntCon.gtIconVal == 0);
10093 else if ((tree->gtIntCon.gtIconVal > -1000) && (tree->gtIntCon.gtIconVal < 1000))
10095 printf(" %ld", dspIconVal);
10096 #ifdef _TARGET_64BIT_
10098 else if ((tree->gtIntCon.gtIconVal & 0xFFFFFFFF00000000LL) != 0)
10100 printf(" 0x%llx", dspIconVal);
10105 printf(" 0x%X", dspIconVal);
10108 if (tree->IsIconHandle())
10110 switch (tree->GetIconHandleFlag())
10112 case GTF_ICON_SCOPE_HDL:
10115 case GTF_ICON_CLASS_HDL:
10118 case GTF_ICON_METHOD_HDL:
10121 case GTF_ICON_FIELD_HDL:
10124 case GTF_ICON_STATIC_HDL:
10127 case GTF_ICON_STR_HDL:
10128 unreached(); // This case is handled above
10130 case GTF_ICON_PSTR_HDL:
10133 case GTF_ICON_PTR_HDL:
10136 case GTF_ICON_VARG_HDL:
10139 case GTF_ICON_PINVKI_HDL:
10140 printf(" pinvoke");
10142 case GTF_ICON_TOKEN_HDL:
10145 case GTF_ICON_TLS_HDL:
10148 case GTF_ICON_FTN_ADDR:
10151 case GTF_ICON_CIDMID_HDL:
10152 printf(" cid/mid");
10154 case GTF_ICON_BBC_PTR:
10158 printf(" UNKNOWN");
10163 if ((tree->gtFlags & GTF_ICON_FIELD_OFF) != 0)
10165 printf(" field offset");
10168 #ifdef FEATURE_SIMD
10169 if ((tree->gtFlags & GTF_ICON_SIMD_COUNT) != 0)
10171 printf(" Vector<T>.Count");
10175 if ((tree->IsReuseRegVal()) != 0)
10177 printf(" reuse reg val");
10181 gtDispFieldSeq(tree->gtIntCon.gtFieldSeq);
10186 printf(" 0x%016I64x", tree->gtLngCon.gtLconVal);
10190 if (*((__int64*)&tree->gtDblCon.gtDconVal) == (__int64)I64(0x8000000000000000))
10192 printf(" -0.00000");
10196 printf(" %#.17g", tree->gtDblCon.gtDconVal);
10200 printf("<string constant>");
10203 assert(!"unexpected constant node");
10206 gtDispRegVal(tree);
10209 void Compiler::gtDispFieldSeq(FieldSeqNode* pfsn)
10211 if (pfsn == FieldSeqStore::NotAField() || (pfsn == nullptr))
10218 while (pfsn != nullptr)
10220 assert(pfsn != FieldSeqStore::NotAField()); // Can't exist in a field sequence list except alone
10221 CORINFO_FIELD_HANDLE fldHnd = pfsn->m_fieldHnd;
10222 // First check the "pseudo" field handles...
10223 if (fldHnd == FieldSeqStore::FirstElemPseudoField)
10225 printf("#FirstElem");
10227 else if (fldHnd == FieldSeqStore::ConstantIndexPseudoField)
10229 printf("#ConstantIndex");
10233 printf("%s", eeGetFieldName(fldHnd));
10235 pfsn = pfsn->m_next;
10236 if (pfsn != nullptr)
10244 //------------------------------------------------------------------------
10245 // gtDispLeaf: Print a single leaf node to jitstdout.
10248 // tree - the tree to be printed
10249 // indentStack - the specification for the current level of indentation & arcs
10255 // 'indentStack' may be null, in which case no indentation or arcs are printed
10257 void Compiler::gtDispLeaf(GenTree* tree, IndentStack* indentStack)
10259 if (tree->OperKind() & GTK_CONST)
10265 bool isLclFld = false;
10267 switch (tree->gtOper)
10273 case GT_LCL_FLD_ADDR:
10274 case GT_STORE_LCL_FLD:
10280 case GT_LCL_VAR_ADDR:
10281 case GT_STORE_LCL_VAR:
10283 varNum = tree->gtLclVarCommon.gtLclNum;
10284 varDsc = &lvaTable[varNum];
10285 gtDispLclVar(varNum);
10286 if (tree->gtLclVarCommon.HasSsaName())
10288 if (tree->gtFlags & GTF_VAR_USEASG)
10290 assert(tree->gtFlags & GTF_VAR_DEF);
10291 printf("ud:%d->%d", tree->gtLclVarCommon.gtSsaNum, GetSsaNumForLocalVarDef(tree));
10295 printf("%s:%d", (tree->gtFlags & GTF_VAR_DEF) ? "d" : "u", tree->gtLclVarCommon.gtSsaNum);
10301 printf("[+%u]", tree->gtLclFld.gtLclOffs);
10302 gtDispFieldSeq(tree->gtLclFld.gtFieldSeq);
10305 if (varDsc->lvRegister)
10308 varDsc->PrintVarReg();
10310 else if (tree->InReg())
10312 printf(" %s", compRegVarName(tree->gtRegNum));
10315 if (varDsc->lvPromoted)
10317 if (!varTypeIsPromotable(varDsc) && !varDsc->lvUnusedStruct)
10319 // Promoted implicit byrefs can get in this state while they are being rewritten
10320 // in global morph.
10321 assert(fgGlobalMorph);
10325 CORINFO_CLASS_HANDLE typeHnd = varDsc->lvVerTypeInfo.GetClassHandle();
10326 CORINFO_FIELD_HANDLE fldHnd;
10328 for (unsigned i = varDsc->lvFieldLclStart; i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++i)
10330 LclVarDsc* fieldVarDsc = &lvaTable[i];
10331 const char* fieldName;
10332 #if !defined(_TARGET_64BIT_)
10333 if (varTypeIsLong(varDsc))
10335 fieldName = (i == 0) ? "lo" : "hi";
10338 #endif // !defined(_TARGET_64BIT_)
10340 fldHnd = info.compCompHnd->getFieldInClass(typeHnd, fieldVarDsc->lvFldOrdinal);
10341 fieldName = eeGetFieldName(fldHnd);
10346 printIndent(indentStack);
10347 printf(" %-6s V%02u.%s (offs=0x%02x) -> ", varTypeName(fieldVarDsc->TypeGet()),
10348 tree->gtLclVarCommon.gtLclNum, fieldName, fieldVarDsc->lvFldOffset);
10351 if (fieldVarDsc->lvRegister)
10354 fieldVarDsc->PrintVarReg();
10357 if (fieldVarDsc->lvTracked && fgLocalVarLivenessDone && // Includes local variable liveness
10358 ((tree->gtFlags & GTF_VAR_DEATH) != 0))
10360 printf(" (last use)");
10365 else // a normal not-promoted lclvar
10367 if (varDsc->lvTracked && fgLocalVarLivenessDone && ((tree->gtFlags & GTF_VAR_DEATH) != 0))
10369 printf(" (last use)");
10376 const char* methodName;
10377 const char* className;
10379 methodName = eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtVal.gtVal1, &className);
10380 printf(" %s.%s\n", className, methodName);
10385 printf(" Hnd=%#x", dspPtr(tree->gtClsVar.gtClsVarHnd));
10386 gtDispFieldSeq(tree->gtClsVar.gtFieldSeq);
10389 case GT_CLS_VAR_ADDR:
10390 printf(" Hnd=%#x", dspPtr(tree->gtClsVar.gtClsVarHnd));
10394 if (tree->gtLabel.gtLabBB)
10396 printf(" dst=" FMT_BB, tree->gtLabel.gtLabBB->bbNum);
10400 printf(" dst=<null>");
10407 const char* methodName;
10408 const char* className;
10410 methodName = eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtFptrVal.gtFptrMethod, &className);
10411 printf(" %s.%s\n", className, methodName);
10415 #if !FEATURE_EH_FUNCLETS
10417 printf(" endNstLvl=%d", tree->gtVal.gtVal1);
10419 #endif // !FEATURE_EH_FUNCLETS
10421 // Vanilla leaves. No qualifying information available. So do nothing
10424 case GT_START_NONGC:
10427 case GT_MEMORYBARRIER:
10429 case GT_PINVOKE_PROLOG:
10434 printf("(inl return from call ");
10435 printTreeID(tree->gtRetExpr.gtInlineCandidate);
10440 printf(" %s", getRegName(tree->gtPhysReg.gtSrcReg, varTypeIsFloating(tree)));
10444 printf(" IL offset: ");
10445 if (tree->gtStmt.gtStmtILoffsx == BAD_IL_OFFSET)
10451 printf("0x%x", jitGetILoffs(tree->gtStmt.gtStmtILoffsx));
10457 printf(" cond=%s", GenTree::OpName(tree->AsCC()->gtCondition));
10460 printf(" cond=%s%s", (tree->gtFlags & GTF_JCMP_TST) ? "TEST_" : "",
10461 (tree->gtFlags & GTF_JCMP_EQ) ? "EQ" : "NE");
10464 assert(!"don't know how to display tree leaf node");
10467 gtDispRegVal(tree);
10470 //------------------------------------------------------------------------
10471 // gtDispLeaf: Print a child node to jitstdout.
10474 // tree - the tree to be printed
10475 // indentStack - the specification for the current level of indentation & arcs
10476 // arcType - the type of arc to use for this child
10477 // msg - a contextual method (i.e. from the parent) to print
10478 // topOnly - a boolean indicating whether to print the children, or just the top node
10484 // 'indentStack' may be null, in which case no indentation or arcs are printed
10485 // 'msg' has a default value of null
10486 // 'topOnly' is an optional argument that defaults to false
10488 void Compiler::gtDispChild(GenTree* child,
10489 IndentStack* indentStack,
10490 IndentInfo arcType,
10491 __in_opt const char* msg, /* = nullptr */
10492 bool topOnly) /* = false */
10494 indentStack->Push(arcType);
10495 gtDispTree(child, indentStack, msg, topOnly);
10496 indentStack->Pop();
10499 #ifdef FEATURE_SIMD
10500 // Intrinsic Id to name map
10501 extern const char* const simdIntrinsicNames[] = {
10502 #define SIMD_INTRINSIC(mname, inst, id, name, r, ac, arg1, arg2, arg3, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) name,
10503 #include "simdintrinsiclist.h"
10505 #endif // FEATURE_SIMD
10507 /*****************************************************************************/
10509 void Compiler::gtDispTree(GenTree* tree,
10510 IndentStack* indentStack, /* = nullptr */
10511 __in __in_z __in_opt const char* msg, /* = nullptr */
10512 bool topOnly, /* = false */
10513 bool isLIR) /* = false */
10515 if (tree == nullptr)
10517 printf(" [%08X] <NULL>\n", tree);
10518 printf(""); // null string means flush
10522 if (indentStack == nullptr)
10524 indentStack = new (this, CMK_DebugOnly) IndentStack(this);
10527 if (IsUninitialized(tree))
10529 /* Value used to initalize nodes */
10530 printf("Uninitialized tree node!");
10534 if (tree->gtOper >= GT_COUNT)
10536 gtDispNode(tree, indentStack, msg, isLIR);
10537 printf("Bogus operator!");
10541 /* Is tree a leaf node? */
10543 if (tree->OperIsLeaf() || tree->OperIsLocalStore()) // local stores used to be leaves
10545 gtDispNode(tree, indentStack, msg, isLIR);
10546 gtDispLeaf(tree, indentStack);
10549 if (tree->OperIsLocalStore() && !topOnly)
10551 gtDispChild(tree->gtOp.gtOp1, indentStack, IINone);
10556 // Determine what kind of arc to propagate.
10557 IndentInfo myArc = IINone;
10558 IndentInfo lowerArc = IINone;
10559 if (indentStack->Depth() > 0)
10561 myArc = indentStack->Pop();
10565 indentStack->Push(IIArc);
10569 indentStack->Push(IIArc);
10573 indentStack->Push(IINone);
10577 indentStack->Push(IIEmbedded);
10578 lowerArc = IIEmbedded;
10581 indentStack->Push(IINone);
10590 // Special case formatting for PHI nodes -- arg lists like calls.
10592 if (tree->OperGet() == GT_PHI)
10594 gtDispNode(tree, indentStack, msg, isLIR);
10600 if (tree->gtOp.gtOp1 != nullptr)
10602 IndentInfo arcType = IIArcTop;
10603 for (GenTreeArgList* args = tree->gtOp.gtOp1->AsArgList(); args != nullptr; args = args->Rest())
10605 if (args->Rest() == nullptr)
10607 arcType = IIArcBottom;
10609 gtDispChild(args->Current(), indentStack, arcType);
10617 /* Is it a 'simple' unary/binary operator? */
10619 const char* childMsg = nullptr;
10621 if (tree->OperIsSimple())
10625 if (tree->gtGetOp2IfPresent())
10627 // Label the childMsgs of the GT_COLON operator
10628 // op2 is the then part
10630 if (tree->gtOper == GT_COLON)
10634 gtDispChild(tree->gtOp.gtOp2, indentStack, IIArcTop, childMsg, topOnly);
10638 // Now, get the right type of arc for this node
10639 if (myArc != IINone)
10641 indentStack->Pop();
10642 indentStack->Push(myArc);
10645 gtDispNode(tree, indentStack, msg, isLIR);
10647 // Propagate lowerArc to the lower children.
10648 if (indentStack->Depth() > 0)
10650 (void)indentStack->Pop();
10651 indentStack->Push(lowerArc);
10654 if (tree->gtOper == GT_CAST)
10656 /* Format a message that explains the effect of this GT_CAST */
10658 var_types fromType = genActualType(tree->gtCast.CastOp()->TypeGet());
10659 var_types toType = tree->CastToType();
10660 var_types finalType = tree->TypeGet();
10662 /* if GTF_UNSIGNED is set then force fromType to an unsigned type */
10663 if (tree->gtFlags & GTF_UNSIGNED)
10665 fromType = genUnsignedType(fromType);
10668 if (finalType != toType)
10670 printf(" %s <-", varTypeName(finalType));
10673 printf(" %s <- %s", varTypeName(toType), varTypeName(fromType));
10676 if (tree->gtOper == GT_OBJ && (tree->gtFlags & GTF_VAR_DEATH))
10678 printf(" (last use)");
10680 if (tree->OperIsBlkOp())
10682 if (tree->OperIsCopyBlkOp())
10686 else if (tree->OperIsInitBlkOp())
10690 if (tree->OperIsStoreBlk() && (tree->AsBlk()->gtBlkOpKind != GenTreeBlk::BlkOpKindInvalid))
10692 switch (tree->AsBlk()->gtBlkOpKind)
10694 case GenTreeBlk::BlkOpKindRepInstr:
10695 printf(" (RepInstr)");
10697 case GenTreeBlk::BlkOpKindUnroll:
10698 printf(" (Unroll)");
10700 case GenTreeBlk::BlkOpKindHelper:
10701 printf(" (Helper)");
10708 else if (tree->OperIsFieldList())
10710 printf(" %s at offset %d", varTypeName(tree->AsFieldList()->gtFieldType),
10711 tree->AsFieldList()->gtFieldOffset);
10713 #if FEATURE_PUT_STRUCT_ARG_STK
10714 else if (tree->OperGet() == GT_PUTARG_STK)
10716 printf(" (%d slots)", tree->AsPutArgStk()->gtNumSlots);
10717 if (tree->AsPutArgStk()->gtPutArgStkKind != GenTreePutArgStk::Kind::Invalid)
10719 switch (tree->AsPutArgStk()->gtPutArgStkKind)
10721 case GenTreePutArgStk::Kind::RepInstr:
10722 printf(" (RepInstr)");
10724 case GenTreePutArgStk::Kind::Unroll:
10725 printf(" (Unroll)");
10727 case GenTreePutArgStk::Kind::Push:
10730 case GenTreePutArgStk::Kind::PushAllSlots:
10731 printf(" (PushAllSlots)");
10738 #endif // FEATURE_PUT_STRUCT_ARG_STK
10740 if (tree->gtOper == GT_INTRINSIC)
10742 switch (tree->gtIntrinsic.gtIntrinsicId)
10744 case CORINFO_INTRINSIC_Sin:
10747 case CORINFO_INTRINSIC_Cos:
10750 case CORINFO_INTRINSIC_Cbrt:
10753 case CORINFO_INTRINSIC_Sqrt:
10756 case CORINFO_INTRINSIC_Abs:
10759 case CORINFO_INTRINSIC_Round:
10762 case CORINFO_INTRINSIC_Cosh:
10765 case CORINFO_INTRINSIC_Sinh:
10768 case CORINFO_INTRINSIC_Tan:
10771 case CORINFO_INTRINSIC_Tanh:
10774 case CORINFO_INTRINSIC_Asin:
10777 case CORINFO_INTRINSIC_Asinh:
10780 case CORINFO_INTRINSIC_Acos:
10783 case CORINFO_INTRINSIC_Acosh:
10786 case CORINFO_INTRINSIC_Atan:
10789 case CORINFO_INTRINSIC_Atan2:
10792 case CORINFO_INTRINSIC_Atanh:
10795 case CORINFO_INTRINSIC_Log10:
10798 case CORINFO_INTRINSIC_Pow:
10801 case CORINFO_INTRINSIC_Exp:
10804 case CORINFO_INTRINSIC_Ceiling:
10805 printf(" ceiling");
10807 case CORINFO_INTRINSIC_Floor:
10810 case CORINFO_INTRINSIC_Object_GetType:
10811 printf(" objGetType");
10819 #ifdef FEATURE_SIMD
10820 if (tree->gtOper == GT_SIMD)
10822 printf(" %s %s", varTypeName(tree->gtSIMD.gtSIMDBaseType),
10823 simdIntrinsicNames[tree->gtSIMD.gtSIMDIntrinsicID]);
10825 #endif // FEATURE_SIMD
10827 #ifdef FEATURE_HW_INTRINSICS
10828 if (tree->gtOper == GT_HWIntrinsic)
10831 tree->gtHWIntrinsic.gtSIMDBaseType == TYP_UNKNOWN ? ""
10832 : varTypeName(tree->gtHWIntrinsic.gtSIMDBaseType),
10833 HWIntrinsicInfo::lookupName(tree->gtHWIntrinsic.gtHWIntrinsicId));
10835 #endif // FEATURE_HW_INTRINSICS
10837 gtDispRegVal(tree);
10841 if (!topOnly && tree->gtOp.gtOp1)
10844 // Label the child of the GT_COLON operator
10845 // op1 is the else part
10847 if (tree->gtOper == GT_COLON)
10851 else if (tree->gtOper == GT_QMARK)
10855 gtDispChild(tree->gtOp.gtOp1, indentStack, IIArcBottom, childMsg, topOnly);
10861 // Now, get the right type of arc for this node
10862 if (myArc != IINone)
10864 indentStack->Pop();
10865 indentStack->Push(myArc);
10867 gtDispNode(tree, indentStack, msg, isLIR);
10869 // Propagate lowerArc to the lower children.
10870 if (indentStack->Depth() > 0)
10872 (void)indentStack->Pop();
10873 indentStack->Push(lowerArc);
10876 // See what kind of a special operator we have here, and handle its special children.
10878 switch (tree->gtOper)
10881 if (FieldSeqStore::IsPseudoField(tree->gtField.gtFldHnd))
10883 printf(" #PseudoField:0x%x", tree->gtField.gtFldOffset);
10887 printf(" %s", eeGetFieldName(tree->gtField.gtFldHnd), 0);
10890 if (tree->gtField.gtFldObj && !topOnly)
10894 gtDispChild(tree->gtField.gtFldObj, indentStack, IIArcBottom);
10898 gtDispRegVal(tree);
10906 GenTreeCall* call = tree->AsCall();
10907 assert(call->gtFlags & GTF_CALL);
10908 unsigned numChildren = call->NumChildren();
10909 GenTree* lastChild = nullptr;
10910 if (numChildren != 0)
10912 lastChild = call->GetChild(numChildren - 1);
10915 if (call->gtCallType != CT_INDIRECT)
10917 const char* methodName;
10918 const char* className;
10920 methodName = eeGetMethodName(call->gtCallMethHnd, &className);
10922 printf(" %s.%s", className, methodName);
10925 if ((call->gtFlags & GTF_CALL_UNMANAGED) && (call->gtCallMoreFlags & GTF_CALL_M_FRAME_VAR_DEATH))
10927 printf(" (FramesRoot last use)");
10930 if (((call->gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0) && (call->gtInlineCandidateInfo != nullptr) &&
10931 (call->gtInlineCandidateInfo->exactContextHnd != nullptr))
10933 printf(" (exactContextHnd=0x%p)", dspPtr(call->gtInlineCandidateInfo->exactContextHnd));
10937 if (call->IsMultiRegCall())
10939 gtDispRegVal(call);
10950 if ((call->gtCallObjp != nullptr) && (call->gtCallObjp->gtOper != GT_NOP) &&
10951 (!call->gtCallObjp->IsArgPlaceHolderNode()))
10953 if (call->gtCallObjp->gtOper == GT_ASG)
10955 sprintf_s(bufp, sizeof(buf), "this SETUP%c", 0);
10959 sprintf_s(bufp, sizeof(buf), "this in %s%c", compRegVarName(REG_ARG_0), 0);
10961 gtDispChild(call->gtCallObjp, indentStack, (call->gtCallObjp == lastChild) ? IIArcBottom : IIArc,
10965 if (call->gtCallArgs)
10967 gtDispArgList(call, indentStack);
10970 if (call->gtCallType == CT_INDIRECT)
10972 gtDispChild(call->gtCallAddr, indentStack, (call->gtCallAddr == lastChild) ? IIArcBottom : IIArc,
10973 "calli tgt", topOnly);
10976 if (call->gtControlExpr != nullptr)
10978 gtDispChild(call->gtControlExpr, indentStack,
10979 (call->gtControlExpr == lastChild) ? IIArcBottom : IIArc, "control expr", topOnly);
10982 #if !FEATURE_FIXED_OUT_ARGS
10983 regList list = call->regArgList;
10985 /* process the late argument list */
10986 int lateArgIndex = 0;
10987 for (GenTreeArgList* lateArgs = call->gtCallLateArgs; lateArgs;
10988 (lateArgIndex++, lateArgs = lateArgs->Rest()))
10992 argx = lateArgs->Current();
10994 IndentInfo arcType = (lateArgs->Rest() == nullptr) ? IIArcBottom : IIArc;
10995 gtGetLateArgMsg(call, argx, lateArgIndex, -1, bufp, sizeof(buf));
10996 gtDispChild(argx, indentStack, arcType, bufp, topOnly);
11007 gtDispChild(tree->gtStmt.gtStmtExpr, indentStack, IIArcBottom);
11017 gtDispChild(tree->gtArrElem.gtArrObj, indentStack, IIArc, nullptr, topOnly);
11020 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
11022 IndentInfo arcType = ((dim + 1) == tree->gtArrElem.gtArrRank) ? IIArcBottom : IIArc;
11023 gtDispChild(tree->gtArrElem.gtArrInds[dim], indentStack, arcType, nullptr, topOnly);
11028 case GT_ARR_OFFSET:
11033 gtDispChild(tree->gtArrOffs.gtOffset, indentStack, IIArc, nullptr, topOnly);
11034 gtDispChild(tree->gtArrOffs.gtIndex, indentStack, IIArc, nullptr, topOnly);
11035 gtDispChild(tree->gtArrOffs.gtArrObj, indentStack, IIArcBottom, nullptr, topOnly);
11044 gtDispChild(tree->gtCmpXchg.gtOpLocation, indentStack, IIArc, nullptr, topOnly);
11045 gtDispChild(tree->gtCmpXchg.gtOpValue, indentStack, IIArc, nullptr, topOnly);
11046 gtDispChild(tree->gtCmpXchg.gtOpComparand, indentStack, IIArcBottom, nullptr, topOnly);
11050 case GT_ARR_BOUNDS_CHECK:
11051 #ifdef FEATURE_SIMD
11053 #endif // FEATURE_SIMD
11054 #ifdef FEATURE_HW_INTRINSICS
11055 case GT_HW_INTRINSIC_CHK:
11056 #endif // FEATURE_HW_INTRINSICS
11061 gtDispChild(tree->gtBoundsChk.gtIndex, indentStack, IIArc, nullptr, topOnly);
11062 gtDispChild(tree->gtBoundsChk.gtArrLen, indentStack, IIArcBottom, nullptr, topOnly);
11066 case GT_STORE_DYN_BLK:
11068 if (tree->OperIsCopyBlkOp())
11072 else if (tree->OperIsInitBlkOp())
11080 if (tree->gtDynBlk.Data() != nullptr)
11082 gtDispChild(tree->gtDynBlk.Data(), indentStack, IIArc, nullptr, topOnly);
11084 gtDispChild(tree->gtDynBlk.Addr(), indentStack, IIArc, nullptr, topOnly);
11085 gtDispChild(tree->gtDynBlk.gtDynamicSize, indentStack, IIArcBottom, nullptr, topOnly);
11090 printf("<DON'T KNOW HOW TO DISPLAY THIS NODE> :");
11091 printf(""); // null string means flush
11096 //------------------------------------------------------------------------
11097 // gtGetArgMsg: Construct a message about the given argument
11100 // call - The call for which 'arg' is an argument
11101 // arg - The argument for which a message should be constructed
11102 // argNum - The ordinal number of the arg in the argument list
11103 // listCount - When printing in LIR form this is the count for a GT_FIELD_LIST
11104 // or -1 if we are not printing in LIR form
11105 // bufp - A pointer to the buffer into which the message is written
11106 // bufLength - The length of the buffer pointed to by bufp
11109 // No return value, but bufp is written.
11112 // 'call' must be a call node
11113 // 'arg' must be an argument to 'call' (else gtArgEntryByNode will assert)
11115 void Compiler::gtGetArgMsg(
11116 GenTreeCall* call, GenTree* arg, unsigned argNum, int listCount, char* bufp, unsigned bufLength)
11118 if (call->gtCallLateArgs != nullptr)
11120 fgArgTabEntry* curArgTabEntry = gtArgEntryByArgNum(call, argNum);
11121 assert(curArgTabEntry);
11123 if (arg->gtFlags & GTF_LATE_ARG)
11125 sprintf_s(bufp, bufLength, "arg%d SETUP%c", argNum, 0);
11129 #ifdef _TARGET_ARM_
11130 if (curArgTabEntry->isSplit)
11132 regNumber firstReg = curArgTabEntry->regNum;
11133 if (listCount == -1)
11135 if (curArgTabEntry->numRegs == 1)
11137 sprintf_s(bufp, bufLength, "arg%d %s out+%02x%c", argNum, compRegVarName(firstReg),
11138 (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE, 0);
11142 regNumber lastReg = REG_STK;
11143 char separator = (curArgTabEntry->numRegs == 2) ? ',' : '-';
11144 if (curArgTabEntry->isHfaRegArg)
11146 unsigned lastRegNum = genMapFloatRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
11147 lastReg = genMapFloatRegArgNumToRegNum(lastRegNum);
11151 unsigned lastRegNum = genMapIntRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
11152 lastReg = genMapIntRegArgNumToRegNum(lastRegNum);
11154 sprintf_s(bufp, bufLength, "arg%d %s%c%s out+%02x%c", argNum, compRegVarName(firstReg),
11155 separator, compRegVarName(lastReg), (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE,
11161 unsigned curArgNum = BAD_VAR_NUM;
11162 bool isFloat = curArgTabEntry->isHfaRegArg;
11165 curArgNum = genMapFloatRegNumToRegArgNum(firstReg) + listCount;
11169 curArgNum = genMapIntRegNumToRegArgNum(firstReg) + listCount;
11172 if (!isFloat && curArgNum < MAX_REG_ARG)
11174 regNumber curReg = genMapIntRegArgNumToRegNum(curArgNum);
11175 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
11177 else if (isFloat && curArgNum < MAX_FLOAT_REG_ARG)
11179 regNumber curReg = genMapFloatRegArgNumToRegNum(curArgNum);
11180 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
11184 unsigned stackSlot = listCount - curArgTabEntry->numRegs;
11185 sprintf_s(bufp, bufLength, "arg%d m%d out+%02x%c", argNum, listCount,
11186 stackSlot * TARGET_POINTER_SIZE, 0);
11191 #endif // _TARGET_ARM_
11192 #if FEATURE_FIXED_OUT_ARGS
11193 if (listCount == -1)
11195 sprintf_s(bufp, bufLength, "arg%d out+%02x%c", argNum, curArgTabEntry->slotNum * TARGET_POINTER_SIZE,
11198 else // listCount is 0,1,2 or 3
11200 assert(listCount <= MAX_ARG_REG_COUNT);
11201 sprintf_s(bufp, bufLength, "arg%d out+%02x%c", argNum,
11202 (curArgTabEntry->slotNum + listCount) * TARGET_POINTER_SIZE, 0);
11205 sprintf_s(bufp, bufLength, "arg%d on STK%c", argNum, 0);
11211 sprintf_s(bufp, bufLength, "arg%d%c", argNum, 0);
11215 //------------------------------------------------------------------------
11216 // gtGetLateArgMsg: Construct a message about the given argument
11219 // call - The call for which 'arg' is an argument
11220 // argx - The argument for which a message should be constructed
11221 // lateArgIndex - The ordinal number of the arg in the lastArg list
11222 // listCount - When printing in LIR form this is the count for a multireg GT_FIELD_LIST
11223 // or -1 if we are not printing in LIR form
11224 // bufp - A pointer to the buffer into which the message is written
11225 // bufLength - The length of the buffer pointed to by bufp
11228 // No return value, but bufp is written.
11231 // 'call' must be a call node
11232 // 'arg' must be an argument to 'call' (else gtArgEntryByNode will assert)
11234 void Compiler::gtGetLateArgMsg(
11235 GenTreeCall* call, GenTree* argx, int lateArgIndex, int listCount, char* bufp, unsigned bufLength)
11237 assert(!argx->IsArgPlaceHolderNode()); // No place holders nodes are in gtCallLateArgs;
11239 fgArgTabEntry* curArgTabEntry = gtArgEntryByLateArgIndex(call, lateArgIndex);
11240 assert(curArgTabEntry);
11241 regNumber argReg = curArgTabEntry->regNum;
11243 #if !FEATURE_FIXED_OUT_ARGS
11244 assert(lateArgIndex < call->regArgListCount);
11245 assert(argReg == call->regArgList[lateArgIndex]);
11247 if (argReg == REG_STK)
11249 sprintf_s(bufp, bufLength, "arg%d in out+%02x%c", curArgTabEntry->argNum,
11250 curArgTabEntry->slotNum * TARGET_POINTER_SIZE, 0);
11255 if (gtArgIsThisPtr(curArgTabEntry))
11257 sprintf_s(bufp, bufLength, "this in %s%c", compRegVarName(argReg), 0);
11259 #ifdef _TARGET_ARM_
11260 else if (curArgTabEntry->isSplit)
11262 regNumber firstReg = curArgTabEntry->regNum;
11263 unsigned argNum = curArgTabEntry->argNum;
11264 if (listCount == -1)
11266 if (curArgTabEntry->numRegs == 1)
11268 sprintf_s(bufp, bufLength, "arg%d %s out+%02x%c", argNum, compRegVarName(firstReg),
11269 (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE, 0);
11273 regNumber lastReg = REG_STK;
11274 char separator = (curArgTabEntry->numRegs == 2) ? ',' : '-';
11275 if (curArgTabEntry->isHfaRegArg)
11277 unsigned lastRegNum = genMapFloatRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
11278 lastReg = genMapFloatRegArgNumToRegNum(lastRegNum);
11282 unsigned lastRegNum = genMapIntRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
11283 lastReg = genMapIntRegArgNumToRegNum(lastRegNum);
11285 sprintf_s(bufp, bufLength, "arg%d %s%c%s out+%02x%c", argNum, compRegVarName(firstReg), separator,
11286 compRegVarName(lastReg), (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE, 0);
11291 unsigned curArgNum = BAD_VAR_NUM;
11292 bool isFloat = curArgTabEntry->isHfaRegArg;
11295 curArgNum = genMapFloatRegNumToRegArgNum(firstReg) + listCount;
11299 curArgNum = genMapIntRegNumToRegArgNum(firstReg) + listCount;
11302 if (!isFloat && curArgNum < MAX_REG_ARG)
11304 regNumber curReg = genMapIntRegArgNumToRegNum(curArgNum);
11305 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
11307 else if (isFloat && curArgNum < MAX_FLOAT_REG_ARG)
11309 regNumber curReg = genMapFloatRegArgNumToRegNum(curArgNum);
11310 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
11314 unsigned stackSlot = listCount - curArgTabEntry->numRegs;
11315 sprintf_s(bufp, bufLength, "arg%d m%d out+%02x%c", argNum, listCount,
11316 stackSlot * TARGET_POINTER_SIZE, 0);
11321 #endif // _TARGET_ARM_
11324 #if FEATURE_MULTIREG_ARGS
11325 if (curArgTabEntry->numRegs >= 2)
11327 // listCount could be -1 but it is signed, so this comparison is OK.
11328 assert(listCount <= MAX_ARG_REG_COUNT);
11329 char separator = (curArgTabEntry->numRegs == 2) ? ',' : '-';
11330 sprintf_s(bufp, bufLength, "arg%d %s%c%s%c", curArgTabEntry->argNum, compRegVarName(argReg), separator,
11331 compRegVarName(curArgTabEntry->getRegNum(curArgTabEntry->numRegs - 1)), 0);
11336 sprintf_s(bufp, bufLength, "arg%d in %s%c", curArgTabEntry->argNum, compRegVarName(argReg), 0);
11342 //------------------------------------------------------------------------
11343 // gtDispArgList: Dump the tree for a call arg list
11346 // call - The call to dump arguments for
11347 // indentStack - the specification for the current level of indentation & arcs
11352 void Compiler::gtDispArgList(GenTreeCall* call, IndentStack* indentStack)
11354 GenTree* args = call->gtCallArgs;
11355 unsigned argnum = 0;
11356 const int BufLength = 256;
11357 char buf[BufLength];
11358 char* bufp = &buf[0];
11359 unsigned numChildren = call->NumChildren();
11360 assert(numChildren != 0);
11361 bool argListIsLastChild = (args == call->GetChild(numChildren - 1));
11363 IndentInfo arcType = IIArc;
11364 if (call->gtCallObjp != nullptr)
11369 while (args != nullptr)
11371 assert(args->gtOper == GT_LIST);
11372 GenTree* arg = args->gtOp.gtOp1;
11373 if (!arg->IsNothingNode() && !arg->IsArgPlaceHolderNode())
11375 gtGetArgMsg(call, arg, argnum, -1, bufp, BufLength);
11376 if (argListIsLastChild && (args->gtOp.gtOp2 == nullptr))
11378 arcType = IIArcBottom;
11380 gtDispChild(arg, indentStack, arcType, bufp, false);
11382 args = args->gtOp.gtOp2;
11387 //------------------------------------------------------------------------
11388 // gtDispArgList: Dump the tree for a call arg list
11391 // tree - The call for which 'arg' is an argument
11392 // indentStack - the specification for the current level of indentation & arcs
11398 // 'tree' must be a GT_LIST node
11400 void Compiler::gtDispTreeList(GenTree* tree, IndentStack* indentStack /* = nullptr */)
11402 for (/*--*/; tree != nullptr; tree = tree->gtNext)
11404 gtDispTree(tree, indentStack);
11409 //------------------------------------------------------------------------
11410 // Compiler::gtDispRange: dumps a range of LIR.
11413 // range - the range of LIR to display.
11415 void Compiler::gtDispRange(LIR::ReadOnlyRange const& range)
11417 for (GenTree* node : range)
11419 gtDispLIRNode(node);
11423 //------------------------------------------------------------------------
11424 // Compiler::gtDispTreeRange: dumps the LIR range that contains all of the
11425 // nodes in the dataflow tree rooted at a given
11429 // containingRange - the LIR range that contains the root node.
11430 // tree - the root of the dataflow tree.
11432 void Compiler::gtDispTreeRange(LIR::Range& containingRange, GenTree* tree)
11435 gtDispRange(containingRange.GetTreeRange(tree, &unused));
11438 //------------------------------------------------------------------------
11439 // Compiler::gtDispLIRNode: dumps a single LIR node.
11442 // node - the LIR node to dump.
11443 // prefixMsg - an optional prefix for each line of output.
11445 void Compiler::gtDispLIRNode(GenTree* node, const char* prefixMsg /* = nullptr */)
11447 auto displayOperand = [](GenTree* operand, const char* message, IndentInfo operandArc, IndentStack& indentStack,
11448 size_t prefixIndent) {
11449 assert(operand != nullptr);
11450 assert(message != nullptr);
11452 if (prefixIndent != 0)
11454 printf("%*s", (int)prefixIndent, "");
11457 // 49 spaces for alignment
11458 printf("%-49s", "");
11459 #if FEATURE_SET_FLAGS
11460 // additional flag enlarges the flag field by one character
11464 indentStack.Push(operandArc);
11465 indentStack.print();
11467 operandArc = IIArc;
11469 printf(" t%-5d %-6s %s\n", operand->gtTreeID, varTypeName(operand->TypeGet()), message);
11472 IndentStack indentStack(this);
11474 size_t prefixIndent = 0;
11475 if (prefixMsg != nullptr)
11477 prefixIndent = strlen(prefixMsg);
11480 const int bufLength = 256;
11481 char buf[bufLength];
11483 const bool nodeIsCall = node->IsCall();
11486 IndentInfo operandArc = IIArcTop;
11487 for (GenTree* operand : node->Operands())
11489 if (operand->IsArgPlaceHolderNode() || !operand->IsValue())
11491 // Either of these situations may happen with calls.
11497 GenTreeCall* call = node->AsCall();
11498 if (operand == call->gtCallObjp)
11500 sprintf_s(buf, sizeof(buf), "this in %s", compRegVarName(REG_ARG_0));
11501 displayOperand(operand, buf, operandArc, indentStack, prefixIndent);
11503 else if (operand == call->gtCallAddr)
11505 displayOperand(operand, "calli tgt", operandArc, indentStack, prefixIndent);
11507 else if (operand == call->gtControlExpr)
11509 displayOperand(operand, "control expr", operandArc, indentStack, prefixIndent);
11511 else if (operand == call->gtCallCookie)
11513 displayOperand(operand, "cookie", operandArc, indentStack, prefixIndent);
11517 fgArgTabEntry* curArgTabEntry = gtArgEntryByNode(call, operand);
11518 assert(curArgTabEntry);
11520 if (operand->OperGet() == GT_LIST)
11523 for (GenTreeArgList* element = operand->AsArgList(); element != nullptr; element = element->Rest())
11525 operand = element->Current();
11526 if (curArgTabEntry->lateArgInx == (unsigned)-1)
11528 gtGetArgMsg(call, operand, curArgTabEntry->argNum, listIndex, buf, sizeof(buf));
11532 gtGetLateArgMsg(call, operand, curArgTabEntry->lateArgInx, listIndex, buf, sizeof(buf));
11535 displayOperand(operand, buf, operandArc, indentStack, prefixIndent);
11536 operandArc = IIArc;
11541 if (!curArgTabEntry->isLateArg())
11543 gtGetArgMsg(call, operand, curArgTabEntry->argNum, -1, buf, sizeof(buf));
11547 gtGetLateArgMsg(call, operand, curArgTabEntry->lateArgInx, -1, buf, sizeof(buf));
11550 displayOperand(operand, buf, operandArc, indentStack, prefixIndent);
11554 else if (node->OperIsDynBlkOp())
11556 if (operand == node->AsBlk()->Addr())
11558 displayOperand(operand, "lhs", operandArc, indentStack, prefixIndent);
11560 else if (operand == node->AsBlk()->Data())
11562 displayOperand(operand, "rhs", operandArc, indentStack, prefixIndent);
11566 assert(operand == node->AsDynBlk()->gtDynamicSize);
11567 displayOperand(operand, "size", operandArc, indentStack, prefixIndent);
11570 else if (node->OperGet() == GT_DYN_BLK)
11572 if (operand == node->AsBlk()->Addr())
11574 displayOperand(operand, "lhs", operandArc, indentStack, prefixIndent);
11578 assert(operand == node->AsDynBlk()->gtDynamicSize);
11579 displayOperand(operand, "size", operandArc, indentStack, prefixIndent);
11582 else if (node->OperIs(GT_ASG))
11584 if (operand == node->gtGetOp1())
11586 displayOperand(operand, "lhs", operandArc, indentStack, prefixIndent);
11590 displayOperand(operand, "rhs", operandArc, indentStack, prefixIndent);
11595 displayOperand(operand, "", operandArc, indentStack, prefixIndent);
11598 operandArc = IIArc;
11601 // Visit the operator
11603 if (prefixMsg != nullptr)
11605 printf("%s", prefixMsg);
11608 const bool topOnly = true;
11609 const bool isLIR = true;
11610 gtDispTree(node, &indentStack, nullptr, topOnly, isLIR);
11613 /*****************************************************************************/
11616 /*****************************************************************************
11618 * Check if the given node can be folded,
11619 * and call the methods to perform the folding
11622 GenTree* Compiler::gtFoldExpr(GenTree* tree)
11624 unsigned kind = tree->OperKind();
11626 /* We must have a simple operation to fold */
11628 // If we're in CSE, it's not safe to perform tree
11629 // folding given that it can will potentially
11630 // change considered CSE candidates.
11631 if (optValnumCSE_phase)
11636 if (!(kind & GTK_SMPOP))
11641 GenTree* op1 = tree->gtOp.gtOp1;
11643 /* Filter out non-foldable trees that can have constant children */
11645 assert(kind & (GTK_UNOP | GTK_BINOP));
11646 switch (tree->gtOper)
11656 /* try to fold the current node */
11658 if ((kind & GTK_UNOP) && op1)
11660 if (op1->OperKind() & GTK_CONST)
11662 return gtFoldExprConst(tree);
11665 else if ((kind & GTK_BINOP) && op1 && tree->gtOp.gtOp2 &&
11666 // Don't take out conditionals for debugging
11667 !((opts.compDbgCode || opts.MinOpts()) && tree->OperIsCompare()))
11669 GenTree* op2 = tree->gtOp.gtOp2;
11671 // The atomic operations are exempted here because they are never computable statically;
11672 // one of their arguments is an address.
11673 if (((op1->OperKind() & op2->OperKind()) & GTK_CONST) && !tree->OperIsAtomicOp())
11675 /* both nodes are constants - fold the expression */
11676 return gtFoldExprConst(tree);
11678 else if ((op1->OperKind() | op2->OperKind()) & GTK_CONST)
11680 /* at least one is a constant - see if we have a
11681 * special operator that can use only one constant
11682 * to fold - e.g. booleans */
11684 return gtFoldExprSpecial(tree);
11686 else if (tree->OperIsCompare())
11688 /* comparisons of two local variables can sometimes be folded */
11690 return gtFoldExprCompare(tree);
11692 else if (op2->OperGet() == GT_COLON)
11694 assert(tree->OperGet() == GT_QMARK);
11696 GenTree* colon_op1 = op2->gtOp.gtOp1;
11697 GenTree* colon_op2 = op2->gtOp.gtOp2;
11699 if (gtCompareTree(colon_op1, colon_op2))
11701 // Both sides of the GT_COLON are the same tree
11703 GenTree* sideEffList = nullptr;
11704 gtExtractSideEffList(op1, &sideEffList);
11706 // Clear colon flags only if the qmark itself is not conditionaly executed
11707 if ((tree->gtFlags & GTF_COLON_COND) == 0)
11709 fgWalkTreePre(&colon_op2, gtClearColonCond);
11712 if (sideEffList == nullptr)
11714 // No side-effects, just return colon_op2
11722 printf("\nIdentical GT_COLON trees with side effects! Extracting side effects...\n");
11723 gtDispTree(sideEffList);
11727 // Change the GT_COLON into a GT_COMMA node with the side-effects
11728 op2->ChangeOper(GT_COMMA);
11729 op2->gtFlags |= (sideEffList->gtFlags & GTF_ALL_EFFECT);
11730 op2->gtOp.gtOp1 = sideEffList;
11737 /* Return the original node (folded/bashed or not) */
11742 //------------------------------------------------------------------------
11743 // gtFoldExprCall: see if a call is foldable
11746 // call - call to examine
11749 // The original call if no folding happened.
11750 // An alternative tree if folding happens.
11753 // Checks for calls to Type.op_Equality, Type.op_Inequality, and
11754 // Enum.HasFlag, and if the call is to one of these,
11755 // attempts to optimize.
11757 GenTree* Compiler::gtFoldExprCall(GenTreeCall* call)
11759 // Can only fold calls to special intrinsics.
11760 if ((call->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) == 0)
11765 // Defer folding if not optimizing.
11766 if (opts.compDbgCode || opts.MinOpts())
11771 // Fetch id of the intrinsic.
11772 const CorInfoIntrinsics methodID = info.compCompHnd->getIntrinsicID(call->gtCallMethHnd);
11776 case CORINFO_INTRINSIC_TypeEQ:
11777 case CORINFO_INTRINSIC_TypeNEQ:
11779 noway_assert(call->TypeGet() == TYP_INT);
11780 GenTree* op1 = call->gtCallArgs->gtOp.gtOp1;
11781 GenTree* op2 = call->gtCallArgs->gtOp.gtOp2->gtOp.gtOp1;
11783 // If either operand is known to be a RuntimeType, this can be folded
11784 GenTree* result = gtFoldTypeEqualityCall(methodID, op1, op2);
11785 if (result != nullptr)
11796 // Check for a new-style jit intrinsic.
11797 const NamedIntrinsic ni = lookupNamedIntrinsic(call->gtCallMethHnd);
11799 if (ni == NI_System_Enum_HasFlag)
11801 GenTree* thisOp = call->gtCallObjp;
11802 GenTree* flagOp = call->gtCallArgs->gtOp.gtOp1;
11803 GenTree* result = gtOptimizeEnumHasFlag(thisOp, flagOp);
11805 if (result != nullptr)
11814 //------------------------------------------------------------------------
11815 // gtFoldTypeEqualityCall: see if a (potential) type equality call is foldable
11818 // methodID -- type equality intrinsic ID
11819 // op1 -- first argument to call
11820 // op2 -- second argument to call
11823 // nulltpr if no folding happened.
11824 // An alternative tree if folding happens.
11827 // If either operand is known to be a a RuntimeType, then the type
11828 // equality methods will simply check object identity and so we can
11829 // fold the call into a simple compare of the call's operands.
11831 GenTree* Compiler::gtFoldTypeEqualityCall(CorInfoIntrinsics methodID, GenTree* op1, GenTree* op2)
11833 // The method must be be a type equality intrinsic
11834 assert(methodID == CORINFO_INTRINSIC_TypeEQ || methodID == CORINFO_INTRINSIC_TypeNEQ);
11836 if ((gtGetTypeProducerKind(op1) == TPK_Unknown) && (gtGetTypeProducerKind(op2) == TPK_Unknown))
11841 const genTreeOps simpleOp = (methodID == CORINFO_INTRINSIC_TypeEQ) ? GT_EQ : GT_NE;
11843 JITDUMP("\nFolding call to Type:op_%s to a simple compare via %s\n",
11844 methodID == CORINFO_INTRINSIC_TypeEQ ? "Equality" : "Inequality", GenTree::OpName(simpleOp));
11846 GenTree* compare = gtNewOperNode(simpleOp, TYP_INT, op1, op2);
11851 /*****************************************************************************
11853 * Some comparisons can be folded:
11856 * classVarA == classVarA
11857 * locA + locB == locB + locA
11861 GenTree* Compiler::gtFoldExprCompare(GenTree* tree)
11863 GenTree* op1 = tree->gtOp.gtOp1;
11864 GenTree* op2 = tree->gtOp.gtOp2;
11866 assert(tree->OperIsCompare());
11868 /* Filter out cases that cannot be folded here */
11870 /* Do not fold floats or doubles (e.g. NaN != Nan) */
11872 if (varTypeIsFloating(op1->TypeGet()))
11877 /* Currently we can only fold when the two subtrees exactly match */
11879 if ((tree->gtFlags & GTF_SIDE_EFFECT) || GenTree::Compare(op1, op2, true) == false)
11881 return tree; /* return unfolded tree */
11886 switch (tree->gtOper)
11891 cons = gtNewIconNode(true); /* Folds to GT_CNS_INT(true) */
11897 cons = gtNewIconNode(false); /* Folds to GT_CNS_INT(false) */
11901 assert(!"Unexpected relOp");
11905 /* The node has beeen folded into 'cons' */
11909 fgMorphTreeDone(cons);
11913 cons->gtNext = tree->gtNext;
11914 cons->gtPrev = tree->gtPrev;
11920 //------------------------------------------------------------------------
11921 // gtCreateHandleCompare: generate a type handle comparison
11924 // oper -- comparison operation (equal/not equal)
11925 // op1 -- first operand
11926 // op2 -- second operand
11927 // typeCheckInliningResult -- indicates how the comparison should happen
11930 // Type comparison tree
11933 GenTree* Compiler::gtCreateHandleCompare(genTreeOps oper,
11936 CorInfoInlineTypeCheck typeCheckInliningResult)
11938 // If we can compare pointers directly, just emit the binary operation
11939 if (typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_PASS)
11941 return gtNewOperNode(oper, TYP_INT, op1, op2);
11944 assert(typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_USE_HELPER);
11946 // Emit a call to a runtime helper
11947 GenTreeArgList* helperArgs = gtNewArgList(op1, op2);
11948 GenTree* ret = gtNewHelperCallNode(CORINFO_HELP_ARE_TYPES_EQUIVALENT, TYP_INT, helperArgs);
11951 ret = gtNewOperNode(GT_NE, TYP_INT, ret, gtNewIconNode(0, TYP_INT));
11955 assert(oper == GT_NE);
11956 ret = gtNewOperNode(GT_EQ, TYP_INT, ret, gtNewIconNode(0, TYP_INT));
11962 //------------------------------------------------------------------------
11963 // gtFoldTypeCompare: see if a type comparison can be further simplified
11966 // tree -- tree possibly comparing types
11969 // An alternative tree if folding happens.
11970 // Original tree otherwise.
11974 // typeof(...) == obj.GetType()
11975 // typeof(...) == typeof(...)
11977 // And potentially optimizes away the need to obtain actual
11978 // RuntimeType objects to do the comparison.
11980 GenTree* Compiler::gtFoldTypeCompare(GenTree* tree)
11982 // Only handle EQ and NE
11983 // (maybe relop vs null someday)
11984 const genTreeOps oper = tree->OperGet();
11985 if ((oper != GT_EQ) && (oper != GT_NE))
11990 // Screen for the right kinds of operands
11991 GenTree* const op1 = tree->gtOp.gtOp1;
11992 const TypeProducerKind op1Kind = gtGetTypeProducerKind(op1);
11993 if (op1Kind == TPK_Unknown)
11998 GenTree* const op2 = tree->gtOp.gtOp2;
11999 const TypeProducerKind op2Kind = gtGetTypeProducerKind(op2);
12000 if (op2Kind == TPK_Unknown)
12005 // We must have a handle on one side or the other here to optimize,
12006 // otherwise we can't be sure that optimizing is sound.
12007 const bool op1IsFromHandle = (op1Kind == TPK_Handle);
12008 const bool op2IsFromHandle = (op2Kind == TPK_Handle);
12010 if (!(op1IsFromHandle || op2IsFromHandle))
12015 // If both types are created via handles, we can simply compare
12016 // handles (or the indirection cells for handles) instead of the
12017 // types that they'd create.
12018 if (op1IsFromHandle && op2IsFromHandle)
12020 JITDUMP("Optimizing compare of types-from-handles to instead compare handles\n");
12021 GenTree* op1ClassFromHandle = tree->gtOp.gtOp1->gtCall.gtCallArgs->gtOp.gtOp1;
12022 GenTree* op2ClassFromHandle = tree->gtOp.gtOp2->gtCall.gtCallArgs->gtOp.gtOp1;
12023 GenTree* op1TunneledHandle = nullptr;
12024 GenTree* op2TunneledHandle = nullptr;
12025 CORINFO_CLASS_HANDLE cls1Hnd = NO_CLASS_HANDLE;
12026 CORINFO_CLASS_HANDLE cls2Hnd = NO_CLASS_HANDLE;
12027 unsigned runtimeLookupCount = 0;
12029 // Try and find class handles from op1 and op2
12030 cls1Hnd = gtGetHelperArgClassHandle(op1ClassFromHandle, &runtimeLookupCount, &op1TunneledHandle);
12031 cls2Hnd = gtGetHelperArgClassHandle(op2ClassFromHandle, &runtimeLookupCount, &op2TunneledHandle);
12033 // If we have both class handles, try and resolve the type equality test completely.
12034 bool resolveFailed = false;
12036 if ((cls1Hnd != NO_CLASS_HANDLE) && (cls2Hnd != NO_CLASS_HANDLE))
12038 JITDUMP("Asking runtime to compare %p (%s) and %p (%s) for equality\n", dspPtr(cls1Hnd),
12039 info.compCompHnd->getClassName(cls1Hnd), dspPtr(cls2Hnd), info.compCompHnd->getClassName(cls2Hnd));
12040 TypeCompareState s = info.compCompHnd->compareTypesForEquality(cls1Hnd, cls2Hnd);
12042 if (s != TypeCompareState::May)
12044 // Type comparison result is known.
12045 const bool typesAreEqual = (s == TypeCompareState::Must);
12046 const bool operatorIsEQ = (oper == GT_EQ);
12047 const int compareResult = operatorIsEQ ^ typesAreEqual ? 0 : 1;
12048 JITDUMP("Runtime reports comparison is known at jit time: %u\n", compareResult);
12049 GenTree* result = gtNewIconNode(compareResult);
12051 // Any runtime lookups that fed into this compare are
12052 // now dead code, so they no longer require the runtime context.
12053 assert(lvaGenericsContextUseCount >= runtimeLookupCount);
12054 lvaGenericsContextUseCount -= runtimeLookupCount;
12059 resolveFailed = true;
12065 JITDUMP("Runtime reports comparison is NOT known at jit time\n");
12069 JITDUMP("Could not find handle for %s%s\n", (cls1Hnd == NO_CLASS_HANDLE) ? " cls1" : "",
12070 (cls2Hnd == NO_CLASS_HANDLE) ? " cls2" : "");
12073 // We can't answer the equality comparison definitively at jit
12074 // time, but can still simplfy the comparison.
12076 // Find out how we can compare the two handles.
12077 // NOTE: We're potentially passing NO_CLASS_HANDLE, but the runtime knows what to do with it here.
12078 CorInfoInlineTypeCheck inliningKind =
12079 info.compCompHnd->canInlineTypeCheck(cls1Hnd, CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN);
12081 // If the first type needs helper, check the other type: it might be okay with a simple compare.
12082 if (inliningKind == CORINFO_INLINE_TYPECHECK_USE_HELPER)
12084 inliningKind = info.compCompHnd->canInlineTypeCheck(cls2Hnd, CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN);
12087 assert(inliningKind == CORINFO_INLINE_TYPECHECK_PASS || inliningKind == CORINFO_INLINE_TYPECHECK_USE_HELPER);
12089 // If we successfully tunneled through both operands, compare
12090 // the tunneled values, otherwise compare the original values.
12092 if ((op1TunneledHandle != nullptr) && (op2TunneledHandle != nullptr))
12094 compare = gtCreateHandleCompare(oper, op1TunneledHandle, op2TunneledHandle, inliningKind);
12098 compare = gtCreateHandleCompare(oper, op1ClassFromHandle, op2ClassFromHandle, inliningKind);
12101 // Drop any now-irrelvant flags
12102 compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
12107 // Just one operand creates a type from a handle.
12109 // If the other operand is fetching the type from an object,
12110 // we can sometimes optimize the type compare into a simpler
12111 // method table comparison.
12113 // TODO: if other operand is null...
12114 if ((op1Kind != TPK_GetType) && (op2Kind != TPK_GetType))
12119 GenTree* const opHandle = op1IsFromHandle ? op1 : op2;
12120 GenTree* const opOther = op1IsFromHandle ? op2 : op1;
12122 // Tunnel through the handle operand to get at the class handle involved.
12123 GenTree* const opHandleArgument = opHandle->gtCall.gtCallArgs->gtOp.gtOp1;
12124 CORINFO_CLASS_HANDLE clsHnd = gtGetHelperArgClassHandle(opHandleArgument);
12126 // If we couldn't find the class handle, give up.
12127 if (clsHnd == NO_CLASS_HANDLE)
12132 // Ask the VM if this type can be equality tested by a simple method
12133 // table comparison.
12134 CorInfoInlineTypeCheck typeCheckInliningResult =
12135 info.compCompHnd->canInlineTypeCheck(clsHnd, CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE);
12136 if (typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_NONE)
12141 // We're good to go.
12142 JITDUMP("Optimizing compare of obj.GetType()"
12143 " and type-from-handle to compare method table pointer\n");
12145 // opHandleArgument is the method table we're looking for.
12146 GenTree* const knownMT = opHandleArgument;
12148 // Fetch object method table from the object itself.
12149 GenTree* objOp = nullptr;
12151 // Note we may see intrinsified or regular calls to GetType
12152 if (opOther->OperGet() == GT_INTRINSIC)
12154 objOp = opOther->gtUnOp.gtOp1;
12158 assert(opOther->OperGet() == GT_CALL);
12159 objOp = opOther->gtCall.gtCallObjp;
12162 GenTree* const objMT = gtNewOperNode(GT_IND, TYP_I_IMPL, objOp);
12164 // Update various flags
12165 objMT->gtFlags |= GTF_EXCEPT;
12166 compCurBB->bbFlags |= BBF_HAS_VTABREF;
12167 optMethodFlags |= OMF_HAS_VTABLEREF;
12169 // Compare the two method tables
12170 GenTree* const compare = gtCreateHandleCompare(oper, objMT, knownMT, typeCheckInliningResult);
12172 // Drop any now irrelevant flags
12173 compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
12179 //------------------------------------------------------------------------
12180 // gtGetHelperArgClassHandle: find the compile time class handle from
12181 // a helper call argument tree
12184 // tree - tree that passes the handle to the helper
12185 // runtimeLookupCount [optional, in/out] - incremented if tree was a runtime lookup
12186 // handleTree [optional, out] - set to the literal operand tree for indirect handles
12189 // The compile time class handle if known.
12191 CORINFO_CLASS_HANDLE Compiler::gtGetHelperArgClassHandle(GenTree* tree,
12192 unsigned* runtimeLookupCount,
12193 GenTree** handleTree)
12195 CORINFO_CLASS_HANDLE result = NO_CLASS_HANDLE;
12197 // Walk through any wrapping nop.
12198 if ((tree->gtOper == GT_NOP) && (tree->gtType == TYP_I_IMPL))
12200 tree = tree->gtOp.gtOp1;
12203 // The handle could be a literal constant
12204 if ((tree->OperGet() == GT_CNS_INT) && (tree->TypeGet() == TYP_I_IMPL))
12206 assert(tree->IsIconHandle(GTF_ICON_CLASS_HDL));
12207 result = (CORINFO_CLASS_HANDLE)tree->gtIntCon.gtCompileTimeHandle;
12209 // Or the result of a runtime lookup
12210 else if (tree->OperGet() == GT_RUNTIMELOOKUP)
12212 result = tree->AsRuntimeLookup()->GetClassHandle();
12214 if (runtimeLookupCount != nullptr)
12216 *runtimeLookupCount = *runtimeLookupCount + 1;
12219 // Or something reached indirectly
12220 else if (tree->gtOper == GT_IND)
12222 // The handle indirs we are looking for will be marked as non-faulting.
12223 // Certain others (eg from refanytype) may not be.
12224 if (tree->gtFlags & GTF_IND_NONFAULTING)
12226 GenTree* handleTreeInternal = tree->gtOp.gtOp1;
12228 if ((handleTreeInternal->OperGet() == GT_CNS_INT) && (handleTreeInternal->TypeGet() == TYP_I_IMPL))
12230 // These handle constants should be class handles.
12231 assert(handleTreeInternal->IsIconHandle(GTF_ICON_CLASS_HDL));
12232 result = (CORINFO_CLASS_HANDLE)handleTreeInternal->gtIntCon.gtCompileTimeHandle;
12234 if (handleTree != nullptr)
12236 *handleTree = handleTreeInternal;
12245 /*****************************************************************************
12247 * Some binary operators can be folded even if they have only one
12248 * operand constant - e.g. boolean operators, add with 0
12249 * multiply with 1, etc
12252 GenTree* Compiler::gtFoldExprSpecial(GenTree* tree)
12254 GenTree* op1 = tree->gtOp.gtOp1;
12255 GenTree* op2 = tree->gtOp.gtOp2;
12256 genTreeOps oper = tree->OperGet();
12262 assert(tree->OperKind() & GTK_BINOP);
12264 /* Filter out operators that cannot be folded here */
12265 if (oper == GT_CAST)
12270 /* We only consider TYP_INT for folding
12271 * Do not fold pointer arithmetic (e.g. addressing modes!) */
12273 if (oper != GT_QMARK && !varTypeIsIntOrI(tree->gtType))
12278 /* Find out which is the constant node */
12280 if (op1->IsCnsIntOrI())
12285 else if (op2->IsCnsIntOrI())
12295 /* Get the constant value */
12297 val = cons->gtIntConCommon.IconValue();
12299 /* Here op is the non-constant operand, val is the constant,
12300 first is true if the constant is op1 */
12308 // Optimize boxed value classes; these are always false. This IL is
12309 // generated when a generic value is tested against null:
12310 // <T> ... foo(T x) { ... if ((object)x == null) ...
12311 if (val == 0 && op->IsBoxedValue())
12313 JITDUMP("\nAttempting to optimize BOX(valueType) %s null [%06u]\n", GenTree::OpName(oper),
12316 // We don't expect GT_GT with signed compares, and we
12317 // can't predict the result if we do see it, since the
12318 // boxed object addr could have its high bit set.
12319 if ((oper == GT_GT) && !tree->IsUnsigned())
12321 JITDUMP(" bailing; unexpected signed compare via GT_GT\n");
12325 // The tree under the box must be side effect free
12326 // since we will drop it if we optimize.
12327 assert(!gtTreeHasSideEffects(op->gtBox.gtOp.gtOp1, GTF_SIDE_EFFECT));
12329 // See if we can optimize away the box and related statements.
12330 GenTree* boxSourceTree = gtTryRemoveBoxUpstreamEffects(op);
12331 bool didOptimize = (boxSourceTree != nullptr);
12333 // If optimization succeeded, remove the box.
12336 // Set up the result of the compare.
12337 int compareResult = 0;
12340 // GT_GT(null, box) == false
12341 // GT_GT(box, null) == true
12342 compareResult = (op1 == op);
12344 else if (oper == GT_EQ)
12346 // GT_EQ(box, null) == false
12347 // GT_EQ(null, box) == false
12352 assert(oper == GT_NE);
12353 // GT_NE(box, null) == true
12354 // GT_NE(null, box) == true
12358 JITDUMP("\nSuccess: replacing BOX(valueType) %s null with %d\n", GenTree::OpName(oper),
12361 op = gtNewIconNode(compareResult);
12365 fgMorphTreeDone(op);
12369 op->gtNext = tree->gtNext;
12370 op->gtPrev = tree->gtPrev;
12394 /* Multiply by zero - return the 'zero' node, but not if side effects */
12395 if (!(op->gtFlags & GTF_SIDE_EFFECT))
12405 if ((op2 == cons) && (val == 1) && !(op1->OperKind() & GTK_CONST))
12412 if ((op2 == cons) && (val == 0) && !(op1->OperKind() & GTK_CONST))
12421 /* AND with zero - return the 'zero' node, but not if side effects */
12423 if (!(op->gtFlags & GTF_SIDE_EFFECT))
12431 /* The GTF_BOOLEAN flag is set for nodes that are part
12432 * of a boolean expression, thus all their children
12433 * are known to evaluate to only 0 or 1 */
12435 if (tree->gtFlags & GTF_BOOLEAN)
12438 /* The constant value must be 1
12439 * AND with 1 stays the same */
12451 else if (tree->gtFlags & GTF_BOOLEAN)
12453 /* The constant value must be 1 - OR with 1 is 1 */
12457 /* OR with one - return the 'one' node, but not if side effects */
12459 if (!(op->gtFlags & GTF_SIDE_EFFECT))
12478 else if (!(op->gtFlags & GTF_SIDE_EFFECT))
12488 assert(op1 == cons && op2 == op && op2->gtOper == GT_COLON);
12489 assert(op2->gtOp.gtOp1 && op2->gtOp.gtOp2);
12491 assert(val == 0 || val == 1);
12493 GenTree* opToDelete;
12496 op = op2->AsColon()->ThenNode();
12497 opToDelete = op2->AsColon()->ElseNode();
12501 op = op2->AsColon()->ElseNode();
12502 opToDelete = op2->AsColon()->ThenNode();
12505 // Clear colon flags only if the qmark itself is not conditionaly executed
12506 if ((tree->gtFlags & GTF_COLON_COND) == 0)
12508 fgWalkTreePre(&op, gtClearColonCond);
12518 /* The node is not foldable */
12524 /* The node has beeen folded into 'op' */
12526 // If there was an assigment update, we just morphed it into
12527 // a use, update the flags appropriately
12528 if (op->gtOper == GT_LCL_VAR)
12530 assert(tree->OperIs(GT_ASG) || (op->gtFlags & (GTF_VAR_USEASG | GTF_VAR_DEF)) == 0);
12532 op->gtFlags &= ~(GTF_VAR_USEASG | GTF_VAR_DEF);
12535 op->gtNext = tree->gtNext;
12536 op->gtPrev = tree->gtPrev;
12541 //------------------------------------------------------------------------
12542 // gtTryRemoveBoxUpstreamEffects: given an unused value type box,
12543 // try and remove the upstream allocation and unnecessary parts of
12547 // op - the box node to optimize
12548 // options - controls whether and how trees are modified
12552 // A tree representing the original value to box, if removal
12553 // is successful/possible (but see note). nullptr if removal fails.
12556 // Value typed box gets special treatment because it has associated
12557 // side effects that can be removed if the box result is not used.
12559 // By default (options == BR_REMOVE_AND_NARROW) this method will
12560 // try and remove unnecessary trees and will try and reduce remaning
12561 // operations to the minimal set, possibly narrowing the width of
12562 // loads from the box source if it is a struct.
12564 // To perform a trial removal, pass BR_DONT_REMOVE. This can be
12565 // useful to determine if this optimization should only be
12566 // performed if some other conditions hold true.
12568 // To remove but not alter the access to the box source, pass
12569 // BR_REMOVE_BUT_NOT_NARROW.
12571 // To remove and return the tree for the type handle used for
12572 // the boxed newobj, pass BR_REMOVE_BUT_NOT_NARROW_WANT_TYPE_HANDLE.
12573 // This can be useful when the only part of the box that is "live"
12576 // If removal fails, is is possible that a subsequent pass may be
12577 // able to optimize. Blocking side effects may now be minimized
12578 // (null or bounds checks might have been removed) or might be
12579 // better known (inline return placeholder updated with the actual
12580 // return expression). So the box is perhaps best left as is to
12581 // help trigger this re-examination.
12583 GenTree* Compiler::gtTryRemoveBoxUpstreamEffects(GenTree* op, BoxRemovalOptions options)
12585 assert(op->IsBoxedValue());
12587 // grab related parts for the optimization
12588 GenTreeBox* box = op->AsBox();
12589 GenTree* asgStmt = box->gtAsgStmtWhenInlinedBoxValue;
12590 GenTree* copyStmt = box->gtCopyStmtWhenInlinedBoxValue;
12592 assert(asgStmt->gtOper == GT_STMT);
12593 assert(copyStmt->gtOper == GT_STMT);
12595 JITDUMP("gtTryRemoveBoxUpstreamEffects: %s to %s of BOX (valuetype)"
12596 " [%06u] (assign/newobj [%06u] copy [%06u])\n",
12597 (options == BR_DONT_REMOVE) ? "checking if it is possible" : "attempting",
12598 (options == BR_MAKE_LOCAL_COPY) ? "make local unboxed version" : "remove side effects", dspTreeID(op),
12599 dspTreeID(asgStmt), dspTreeID(copyStmt));
12601 // If we don't recognize the form of the assign, bail.
12602 GenTree* asg = asgStmt->gtStmt.gtStmtExpr;
12603 if (asg->gtOper != GT_ASG)
12605 JITDUMP(" bailing; unexpected assignment op %s\n", GenTree::OpName(asg->gtOper));
12609 // If we're eventually going to return the type handle, remember it now.
12610 GenTree* boxTypeHandle = nullptr;
12611 if ((options == BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE) || (options == BR_DONT_REMOVE_WANT_TYPE_HANDLE))
12613 GenTree* asgSrc = asg->gtOp.gtOp2;
12614 genTreeOps asgSrcOper = asgSrc->OperGet();
12616 // Allocation may be via AllocObj or via helper call, depending
12617 // on when this is invoked and whether the jit is using AllocObj
12618 // for R2R allocations.
12619 if (asgSrcOper == GT_ALLOCOBJ)
12621 GenTreeAllocObj* allocObj = asgSrc->AsAllocObj();
12622 boxTypeHandle = allocObj->gtOp.gtOp1;
12624 else if (asgSrcOper == GT_CALL)
12626 GenTreeCall* newobjCall = asgSrc->AsCall();
12627 GenTree* newobjArgs = newobjCall->gtCallArgs;
12629 // In R2R expansions the handle may not be an explicit operand to the helper,
12630 // so we can't remove the box.
12631 if (newobjArgs == nullptr)
12633 assert(newobjCall->IsHelperCall(this, CORINFO_HELP_READYTORUN_NEW));
12634 JITDUMP(" bailing; newobj via R2R helper\n");
12638 boxTypeHandle = newobjArgs->AsArgList()->Current();
12645 assert(boxTypeHandle != nullptr);
12648 // If we don't recognize the form of the copy, bail.
12649 GenTree* copy = copyStmt->gtStmt.gtStmtExpr;
12650 if (copy->gtOper != GT_ASG)
12652 // GT_RET_EXPR is a tolerable temporary failure.
12653 // The jit will revisit this optimization after
12654 // inlining is done.
12655 if (copy->gtOper == GT_RET_EXPR)
12657 JITDUMP(" bailing; must wait for replacement of copy %s\n", GenTree::OpName(copy->gtOper));
12661 // Anything else is a missed case we should
12662 // figure out how to handle. One known case
12663 // is GT_COMMAs enclosing the GT_ASG we are
12665 JITDUMP(" bailing; unexpected copy op %s\n", GenTree::OpName(copy->gtOper));
12670 // Handle case where we are optimizing the box into a local copy
12671 if (options == BR_MAKE_LOCAL_COPY)
12673 // Drill into the box to get at the box temp local and the box type
12674 GenTree* boxTemp = box->BoxOp();
12675 assert(boxTemp->IsLocal());
12676 const unsigned boxTempLcl = boxTemp->AsLclVar()->GetLclNum();
12677 assert(lvaTable[boxTempLcl].lvType == TYP_REF);
12678 CORINFO_CLASS_HANDLE boxClass = lvaTable[boxTempLcl].lvClassHnd;
12679 assert(boxClass != nullptr);
12681 // Verify that the copyDst has the expected shape
12682 // (blk|obj|ind (add (boxTempLcl, ptr-size)))
12684 // The shape here is constrained to the patterns we produce
12685 // over in impImportAndPushBox for the inlined box case.
12686 GenTree* copyDst = copy->gtOp.gtOp1;
12688 if (!copyDst->OperIs(GT_BLK, GT_IND, GT_OBJ))
12690 JITDUMP("Unexpected copy dest operator %s\n", GenTree::OpName(copyDst->gtOper));
12694 GenTree* copyDstAddr = copyDst->gtOp.gtOp1;
12695 if (copyDstAddr->OperGet() != GT_ADD)
12697 JITDUMP("Unexpected copy dest address tree\n");
12701 GenTree* copyDstAddrOp1 = copyDstAddr->gtOp.gtOp1;
12702 if ((copyDstAddrOp1->OperGet() != GT_LCL_VAR) || (copyDstAddrOp1->gtLclVarCommon.gtLclNum != boxTempLcl))
12704 JITDUMP("Unexpected copy dest address 1st addend\n");
12708 GenTree* copyDstAddrOp2 = copyDstAddr->gtOp.gtOp2;
12709 if (!copyDstAddrOp2->IsIntegralConst(TARGET_POINTER_SIZE))
12711 JITDUMP("Unexpected copy dest address 2nd addend\n");
12715 // Screening checks have all passed. Do the transformation.
12717 // Retype the box temp to be a struct
12718 JITDUMP("Retyping box temp V%02u to struct %s\n", boxTempLcl, eeGetClassName(boxClass));
12719 lvaTable[boxTempLcl].lvType = TYP_UNDEF;
12720 const bool isUnsafeValueClass = false;
12721 lvaSetStruct(boxTempLcl, boxClass, isUnsafeValueClass);
12722 var_types boxTempType = lvaTable[boxTempLcl].lvType;
12724 // Remove the newobj and assigment to box temp
12725 JITDUMP("Bashing NEWOBJ [%06u] to NOP\n", dspTreeID(asg));
12726 asg->gtBashToNOP();
12728 // Update the copy from the value to be boxed to the box temp
12729 GenTree* newDst = gtNewOperNode(GT_ADDR, TYP_BYREF, gtNewLclvNode(boxTempLcl, boxTempType));
12730 copyDst->gtOp.gtOp1 = newDst;
12732 // Return the address of the now-struct typed box temp
12733 GenTree* retValue = gtNewOperNode(GT_ADDR, TYP_BYREF, gtNewLclvNode(boxTempLcl, boxTempType));
12738 // If the copy is a struct copy, make sure we know how to isolate
12739 // any source side effects.
12740 GenTree* copySrc = copy->gtOp.gtOp2;
12742 // If the copy source is from a pending inline, wait for it to resolve.
12743 if (copySrc->gtOper == GT_RET_EXPR)
12745 JITDUMP(" bailing; must wait for replacement of copy source %s\n", GenTree::OpName(copySrc->gtOper));
12749 bool hasSrcSideEffect = false;
12750 bool isStructCopy = false;
12752 if (gtTreeHasSideEffects(copySrc, GTF_SIDE_EFFECT))
12754 hasSrcSideEffect = true;
12756 if (varTypeIsStruct(copySrc->gtType))
12758 isStructCopy = true;
12760 if ((copySrc->gtOper != GT_OBJ) && (copySrc->gtOper != GT_IND) && (copySrc->gtOper != GT_FIELD))
12762 // We don't know how to handle other cases, yet.
12763 JITDUMP(" bailing; unexpected copy source struct op with side effect %s\n",
12764 GenTree::OpName(copySrc->gtOper));
12770 // If this was a trial removal, we're done.
12771 if (options == BR_DONT_REMOVE)
12776 if (options == BR_DONT_REMOVE_WANT_TYPE_HANDLE)
12778 return boxTypeHandle;
12781 // Otherwise, proceed with the optimization.
12783 // Change the assignment expression to a NOP.
12784 JITDUMP("\nBashing NEWOBJ [%06u] to NOP\n", dspTreeID(asg));
12785 asg->gtBashToNOP();
12787 // Change the copy expression so it preserves key
12788 // source side effects.
12789 JITDUMP("\nBashing COPY [%06u]", dspTreeID(copy));
12791 if (!hasSrcSideEffect)
12793 // If there were no copy source side effects just bash
12794 // the copy to a NOP.
12795 copy->gtBashToNOP();
12796 JITDUMP(" to NOP; no source side effects.\n");
12798 else if (!isStructCopy)
12800 // For scalar types, go ahead and produce the
12801 // value as the copy is fairly cheap and likely
12802 // the optimizer can trim things down to just the
12803 // minimal side effect parts.
12804 copyStmt->gtStmt.gtStmtExpr = copySrc;
12805 JITDUMP(" to scalar read via [%06u]\n", dspTreeID(copySrc));
12809 // For struct types read the first byte of the
12810 // source struct; there's no need to read the
12811 // entire thing, and no place to put it.
12812 assert(copySrc->gtOper == GT_OBJ || copySrc->gtOper == GT_IND || copySrc->gtOper == GT_FIELD);
12813 copyStmt->gtStmt.gtStmtExpr = copySrc;
12815 if (options == BR_REMOVE_AND_NARROW || options == BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE)
12817 JITDUMP(" to read first byte of struct via modified [%06u]\n", dspTreeID(copySrc));
12818 copySrc->ChangeOper(GT_IND);
12819 copySrc->gtType = TYP_BYTE;
12823 JITDUMP(" to read entire struct via modified [%06u]\n", dspTreeID(copySrc));
12827 if (fgStmtListThreaded)
12829 fgSetStmtSeq(asgStmt);
12830 fgSetStmtSeq(copyStmt);
12833 // Box effects were successfully optimized.
12835 if (options == BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE)
12837 return boxTypeHandle;
12845 //------------------------------------------------------------------------
12846 // gtOptimizeEnumHasFlag: given the operands for a call to Enum.HasFlag,
12847 // try and optimize the call to a simple and/compare tree.
12850 // thisOp - first argument to the call
12851 // flagOp - second argument to the call
12854 // A new cmp/amd tree if successful. nullptr on failure.
12857 // If successful, may allocate new temps and modify connected
12860 GenTree* Compiler::gtOptimizeEnumHasFlag(GenTree* thisOp, GenTree* flagOp)
12862 JITDUMP("Considering optimizing call to Enum.HasFlag....\n");
12864 // Operands must be boxes
12865 if (!thisOp->IsBoxedValue() || !flagOp->IsBoxedValue())
12867 JITDUMP("bailing, need both inputs to be BOXes\n");
12871 // Operands must have same type
12872 bool isExactThis = false;
12873 bool isNonNullThis = false;
12874 CORINFO_CLASS_HANDLE thisHnd = gtGetClassHandle(thisOp, &isExactThis, &isNonNullThis);
12876 if (thisHnd == nullptr)
12878 JITDUMP("bailing, can't find type for 'this' operand\n");
12882 // A boxed thisOp should have exact type and non-null instance
12883 assert(isExactThis);
12884 assert(isNonNullThis);
12886 bool isExactFlag = false;
12887 bool isNonNullFlag = false;
12888 CORINFO_CLASS_HANDLE flagHnd = gtGetClassHandle(flagOp, &isExactFlag, &isNonNullFlag);
12890 if (flagHnd == nullptr)
12892 JITDUMP("bailing, can't find type for 'flag' operand\n");
12896 // A boxed flagOp should have exact type and non-null instance
12897 assert(isExactFlag);
12898 assert(isNonNullFlag);
12900 if (flagHnd != thisHnd)
12902 JITDUMP("bailing, operand types differ\n");
12906 // If we have a shared type instance we can't safely check type
12907 // equality, so bail.
12908 DWORD classAttribs = info.compCompHnd->getClassAttribs(thisHnd);
12909 if (classAttribs & CORINFO_FLG_SHAREDINST)
12911 JITDUMP("bailing, have shared instance type\n");
12915 // Simulate removing the box for thisOP. We need to know that it can
12916 // be safely removed before we can optimize.
12917 GenTree* thisVal = gtTryRemoveBoxUpstreamEffects(thisOp, BR_DONT_REMOVE);
12918 if (thisVal == nullptr)
12920 // Note we may fail here if the this operand comes from
12921 // a call. We should be able to retry this post-inlining.
12922 JITDUMP("bailing, can't undo box of 'this' operand\n");
12926 GenTree* flagVal = gtTryRemoveBoxUpstreamEffects(flagOp, BR_REMOVE_BUT_NOT_NARROW);
12927 if (flagVal == nullptr)
12929 // Note we may fail here if the flag operand comes from
12930 // a call. We should be able to retry this post-inlining.
12931 JITDUMP("bailing, can't undo box of 'flag' operand\n");
12935 // Yes, both boxes can be cleaned up. Optimize.
12936 JITDUMP("Optimizing call to Enum.HasFlag\n");
12938 // Undo the boxing of thisOp and prepare to operate directly
12939 // on the original enum values.
12940 thisVal = gtTryRemoveBoxUpstreamEffects(thisOp, BR_REMOVE_BUT_NOT_NARROW);
12942 // Our trial removal above should guarantee successful removal here.
12943 assert(thisVal != nullptr);
12945 // We should have a consistent view of the type
12946 var_types type = thisVal->TypeGet();
12947 assert(type == flagVal->TypeGet());
12949 // The thisVal and flagVal trees come from earlier statements.
12951 // Unless they are invariant values, we need to evaluate them both
12952 // to temps at those points to safely transmit the values here.
12954 // Also we need to use the flag twice, so we need two trees for it.
12955 GenTree* thisValOpt = nullptr;
12956 GenTree* flagValOpt = nullptr;
12957 GenTree* flagValOptCopy = nullptr;
12959 if (thisVal->IsIntegralConst())
12961 thisValOpt = gtClone(thisVal);
12962 assert(thisValOpt != nullptr);
12966 const unsigned thisTmp = lvaGrabTemp(true DEBUGARG("Enum:HasFlag this temp"));
12967 GenTree* thisAsg = gtNewTempAssign(thisTmp, thisVal);
12968 GenTree* thisAsgStmt = thisOp->AsBox()->gtCopyStmtWhenInlinedBoxValue;
12969 thisAsgStmt->gtStmt.gtStmtExpr = thisAsg;
12970 thisValOpt = gtNewLclvNode(thisTmp, type);
12973 if (flagVal->IsIntegralConst())
12975 flagValOpt = gtClone(flagVal);
12976 assert(flagValOpt != nullptr);
12977 flagValOptCopy = gtClone(flagVal);
12978 assert(flagValOptCopy != nullptr);
12982 const unsigned flagTmp = lvaGrabTemp(true DEBUGARG("Enum:HasFlag flag temp"));
12983 GenTree* flagAsg = gtNewTempAssign(flagTmp, flagVal);
12984 GenTree* flagAsgStmt = flagOp->AsBox()->gtCopyStmtWhenInlinedBoxValue;
12985 flagAsgStmt->gtStmt.gtStmtExpr = flagAsg;
12986 flagValOpt = gtNewLclvNode(flagTmp, type);
12987 flagValOptCopy = gtNewLclvNode(flagTmp, type);
12990 // Turn the call into (thisValTmp & flagTmp) == flagTmp.
12991 GenTree* andTree = gtNewOperNode(GT_AND, type, thisValOpt, flagValOpt);
12992 GenTree* cmpTree = gtNewOperNode(GT_EQ, TYP_INT, andTree, flagValOptCopy);
12994 JITDUMP("Optimized call to Enum.HasFlag\n");
12999 /*****************************************************************************
13001 * Fold the given constant tree.
13005 #pragma warning(push)
13006 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
13008 GenTree* Compiler::gtFoldExprConst(GenTree* tree)
13010 unsigned kind = tree->OperKind();
13012 SSIZE_T i1, i2, itemp;
13013 INT64 lval1, lval2, ltemp;
13016 var_types switchType;
13017 FieldSeqNode* fieldSeq = FieldSeqStore::NotAField(); // default unless we override it when folding
13019 assert(kind & (GTK_UNOP | GTK_BINOP));
13021 GenTree* op1 = tree->gtOp.gtOp1;
13022 GenTree* op2 = tree->gtGetOp2IfPresent();
13024 if (!opts.OptEnabled(CLFLG_CONSTANTFOLD))
13029 if (tree->OperGet() == GT_NOP)
13034 #ifdef FEATURE_SIMD
13035 if (tree->OperGet() == GT_SIMD)
13039 #endif // FEATURE_SIMD
13041 if (tree->gtOper == GT_ALLOCOBJ)
13046 if (tree->gtOper == GT_RUNTIMELOOKUP)
13051 if (kind & GTK_UNOP)
13053 assert(op1->OperKind() & GTK_CONST);
13055 switch (op1->gtType)
13059 /* Fold constant INT unary operator */
13061 if (!op1->gtIntCon.ImmedValCanBeFolded(this, tree->OperGet()))
13066 i1 = (int)op1->gtIntCon.gtIconVal;
13068 // If we fold a unary oper, then the folded constant
13069 // is considered a ConstantIndexField if op1 was one
13072 if ((op1->gtIntCon.gtFieldSeq != nullptr) && op1->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
13074 fieldSeq = op1->gtIntCon.gtFieldSeq;
13077 switch (tree->gtOper)
13088 i1 = ((i1 >> 24) & 0xFF) | ((i1 >> 8) & 0xFF00) | ((i1 << 8) & 0xFF0000) |
13089 ((i1 << 24) & 0xFF000000);
13093 i1 = ((i1 >> 8) & 0xFF) | ((i1 << 8) & 0xFF00);
13097 // assert (genActualType(tree->CastToType()) == tree->gtType);
13098 switch (tree->CastToType())
13101 itemp = INT32(INT8(i1));
13105 itemp = INT32(INT16(i1));
13107 if (tree->gtOverflow() && ((itemp != i1) || ((tree->gtFlags & GTF_UNSIGNED) && i1 < 0)))
13115 itemp = INT32(UINT16(i1));
13116 if (tree->gtOverflow())
13128 itemp = INT32(UINT8(i1));
13129 if (tree->gtOverflow())
13140 if (!(tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && i1 < 0)
13147 if ((tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && i1 < 0)
13154 if (tree->IsUnsigned())
13156 lval1 = UINT64(UINT32(i1));
13160 if (tree->gtOverflow() && (i1 < 0))
13164 lval1 = UINT64(INT32(i1));
13169 if (tree->IsUnsigned())
13171 lval1 = INT64(UINT32(i1));
13175 lval1 = INT64(INT32(i1));
13180 if (tree->gtFlags & GTF_UNSIGNED)
13182 f1 = forceCastToFloat(UINT32(i1));
13186 f1 = forceCastToFloat(INT32(i1));
13192 if (tree->gtFlags & GTF_UNSIGNED)
13194 d1 = (double)UINT32(i1);
13198 d1 = (double)INT32(i1);
13203 assert(!"BAD_TYP");
13216 /* Fold constant LONG unary operator */
13218 if (!op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13223 lval1 = op1->gtIntConCommon.LngValue();
13225 switch (tree->gtOper)
13236 lval1 = ((lval1 >> 56) & 0xFF) | ((lval1 >> 40) & 0xFF00) | ((lval1 >> 24) & 0xFF0000) |
13237 ((lval1 >> 8) & 0xFF000000) | ((lval1 << 8) & 0xFF00000000) |
13238 ((lval1 << 24) & 0xFF0000000000) | ((lval1 << 40) & 0xFF000000000000) |
13239 ((lval1 << 56) & 0xFF00000000000000);
13243 assert(genActualType(tree->CastToType()) == tree->gtType);
13244 switch (tree->CastToType())
13247 i1 = INT32(INT8(lval1));
13248 goto CHECK_INT_OVERFLOW;
13251 i1 = INT32(INT16(lval1));
13252 goto CHECK_INT_OVERFLOW;
13255 i1 = INT32(UINT16(lval1));
13256 goto CHECK_UINT_OVERFLOW;
13259 i1 = INT32(UINT8(lval1));
13260 goto CHECK_UINT_OVERFLOW;
13265 CHECK_INT_OVERFLOW:
13266 if (tree->gtOverflow())
13272 if ((tree->gtFlags & GTF_UNSIGNED) && i1 < 0)
13280 i1 = UINT32(lval1);
13282 CHECK_UINT_OVERFLOW:
13283 if (tree->gtOverflow() && UINT32(i1) != lval1)
13290 if (!(tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && lval1 < 0)
13297 if ((tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && lval1 < 0)
13305 if ((tree->gtFlags & GTF_UNSIGNED) && lval1 < 0)
13307 d1 = FloatingPointUtils::convertUInt64ToDouble((unsigned __int64)lval1);
13311 d1 = (double)lval1;
13314 if (tree->CastToType() == TYP_FLOAT)
13316 f1 = forceCastToFloat(d1); // truncate precision
13321 assert(!"BAD_TYP");
13334 assert(op1->gtOper == GT_CNS_DBL);
13336 /* Fold constant DOUBLE unary operator */
13338 d1 = op1->gtDblCon.gtDconVal;
13340 switch (tree->gtOper)
13348 if (tree->gtOverflowEx())
13353 assert(genActualType(tree->CastToType()) == tree->gtType);
13355 if ((op1->gtType == TYP_FLOAT && !_finite(forceCastToFloat(d1))) ||
13356 (op1->gtType == TYP_DOUBLE && !_finite(d1)))
13358 // The floating point constant is not finite. The ECMA spec says, in
13359 // III 3.27, that "...if overflow occurs converting a floating point type
13360 // to an integer, ..., the value returned is unspecified." However, it would
13361 // at least be desirable to have the same value returned for casting an overflowing
13362 // constant to an int as would obtained by passing that constant as a parameter
13363 // then casting that parameter to an int type. We will assume that the C compiler's
13364 // cast logic will yield the desired result (and trust testing to tell otherwise).
13365 // Cross-compilation is an issue here; if that becomes an important scenario, we should
13366 // capture the target-specific values of overflow casts to the various integral types as
13367 // constants in a target-specific function.
13368 CLANG_FORMAT_COMMENT_ANCHOR;
13370 // Don't fold conversions of +inf/-inf to integral value on all platforms
13371 // as the value returned by JIT helper doesn't match with the C compiler's cast result.
13372 // We want the behavior to be same with or without folding.
13376 if (d1 <= -1.0 && varTypeIsUnsigned(tree->CastToType()))
13378 // Don't fold conversions of these cases becasue the result is unspecified per ECMA spec
13379 // and the native math doing the fold doesn't match the run-time computation on all
13381 // We want the behavior to be same with or without folding.
13385 switch (tree->CastToType())
13388 i1 = INT32(INT8(d1));
13392 i1 = INT32(INT16(d1));
13396 i1 = INT32(UINT16(d1));
13400 i1 = INT32(UINT8(d1));
13408 i1 = forceCastToUInt32(d1);
13416 lval1 = FloatingPointUtils::convertDoubleToUInt64(d1);
13420 d1 = forceCastToFloat(d1);
13424 if (op1->gtType == TYP_FLOAT)
13426 d1 = forceCastToFloat(d1); // truncate precision
13428 goto CNS_DOUBLE; // redundant cast
13431 assert(!"BAD_TYP");
13442 /* not a foldable typ - e.g. RET const */
13447 /* We have a binary operator */
13449 assert(kind & GTK_BINOP);
13451 assert(op1->OperKind() & GTK_CONST);
13452 assert(op2->OperKind() & GTK_CONST);
13454 if (tree->gtOper == GT_COMMA)
13459 if (tree->OperIsAnyList())
13464 switchType = op1->gtType;
13466 // Normally we will just switch on op1 types, but for the case where
13467 // only op2 is a GC type and op1 is not a GC type, we use the op2 type.
13468 // This makes us handle this as a case of folding for GC type.
13470 if (varTypeIsGC(op2->gtType) && !varTypeIsGC(op1->gtType))
13472 switchType = op2->gtType;
13475 switch (switchType)
13478 /*-------------------------------------------------------------------------
13479 * Fold constant REF of BYREF binary operator
13480 * These can only be comparisons or null pointers
13485 /* String nodes are an RVA at this point */
13487 if (op1->gtOper == GT_CNS_STR || op2->gtOper == GT_CNS_STR)
13496 i1 = op1->gtIntConCommon.IconValue();
13497 i2 = op2->gtIntConCommon.IconValue();
13499 switch (tree->gtOper)
13510 noway_assert(tree->gtType != TYP_REF);
13511 // We only fold a GT_ADD that involves a null reference.
13512 if (((op1->TypeGet() == TYP_REF) && (i1 == 0)) || ((op2->TypeGet() == TYP_REF) && (i2 == 0)))
13517 printf("\nFolding operator with constant nodes into a constant:\n");
13521 // Fold into GT_IND of null byref
13522 tree->ChangeOperConst(GT_CNS_INT);
13523 tree->gtType = TYP_BYREF;
13524 tree->gtIntCon.gtIconVal = 0;
13525 tree->gtIntCon.gtFieldSeq = FieldSeqStore::NotAField();
13526 if (vnStore != nullptr)
13528 fgValueNumberTreeConst(tree);
13533 printf("\nFolded to null byref:\n");
13546 /*-------------------------------------------------------------------------
13547 * Fold constant INT binary operator
13552 if (tree->OperIsCompare() && (tree->gtType == TYP_BYTE))
13554 tree->gtType = TYP_INT;
13557 assert(tree->gtType == TYP_INT || varTypeIsGC(tree->TypeGet()) || tree->gtOper == GT_MKREFANY);
13559 // No GC pointer types should be folded here...
13561 assert(!varTypeIsGC(op1->gtType) && !varTypeIsGC(op2->gtType));
13563 if (!op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13568 if (!op2->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13573 i1 = op1->gtIntConCommon.IconValue();
13574 i2 = op2->gtIntConCommon.IconValue();
13576 switch (tree->gtOper)
13579 i1 = (INT32(i1) == INT32(i2));
13582 i1 = (INT32(i1) != INT32(i2));
13586 if (tree->gtFlags & GTF_UNSIGNED)
13588 i1 = (UINT32(i1) < UINT32(i2));
13592 i1 = (INT32(i1) < INT32(i2));
13597 if (tree->gtFlags & GTF_UNSIGNED)
13599 i1 = (UINT32(i1) <= UINT32(i2));
13603 i1 = (INT32(i1) <= INT32(i2));
13608 if (tree->gtFlags & GTF_UNSIGNED)
13610 i1 = (UINT32(i1) >= UINT32(i2));
13614 i1 = (INT32(i1) >= INT32(i2));
13619 if (tree->gtFlags & GTF_UNSIGNED)
13621 i1 = (UINT32(i1) > UINT32(i2));
13625 i1 = (INT32(i1) > INT32(i2));
13631 if (tree->gtOverflow())
13633 if (tree->gtFlags & GTF_UNSIGNED)
13635 if (INT64(UINT32(itemp)) != INT64(UINT32(i1)) + INT64(UINT32(i2)))
13642 if (INT64(INT32(itemp)) != INT64(INT32(i1)) + INT64(INT32(i2)))
13649 fieldSeq = GetFieldSeqStore()->Append(op1->gtIntCon.gtFieldSeq, op2->gtIntCon.gtFieldSeq);
13653 if (tree->gtOverflow())
13655 if (tree->gtFlags & GTF_UNSIGNED)
13657 if (INT64(UINT32(itemp)) != ((INT64)((UINT32)i1) - (INT64)((UINT32)i2)))
13664 if (INT64(INT32(itemp)) != INT64(INT32(i1)) - INT64(INT32(i2)))
13674 if (tree->gtOverflow())
13676 if (tree->gtFlags & GTF_UNSIGNED)
13678 if (INT64(UINT32(itemp)) != ((INT64)((UINT32)i1) * (INT64)((UINT32)i2)))
13685 if (INT64(INT32(itemp)) != INT64(INT32(i1)) * INT64(INT32(i2)))
13691 // For the very particular case of the "constant array index" pseudo-field, we
13692 // assume that multiplication is by the field width, and preserves that field.
13693 // This could obviously be made more robust by a more complicated set of annotations...
13694 if ((op1->gtIntCon.gtFieldSeq != nullptr) && op1->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
13696 assert(op2->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField());
13697 fieldSeq = op1->gtIntCon.gtFieldSeq;
13699 else if ((op2->gtIntCon.gtFieldSeq != nullptr) &&
13700 op2->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
13702 assert(op1->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField());
13703 fieldSeq = op2->gtIntCon.gtFieldSeq;
13719 i1 <<= (i2 & 0x1f);
13722 i1 >>= (i2 & 0x1f);
13725 /* logical shift -> make it unsigned to not propagate the sign bit */
13726 i1 = UINT32(i1) >> (i2 & 0x1f);
13729 i1 = (i1 << (i2 & 0x1f)) | (UINT32(i1) >> ((32 - i2) & 0x1f));
13732 i1 = (i1 << ((32 - i2) & 0x1f)) | (UINT32(i1) >> (i2 & 0x1f));
13735 /* DIV and MOD can generate an INT 0 - if division by 0
13736 * or overflow - when dividing MIN by -1 */
13742 if (INT32(i2) == 0)
13744 // Division by zero:
13745 // We have to evaluate this expression and throw an exception
13748 else if ((INT32(i2) == -1) && (UINT32(i1) == 0x80000000))
13750 // Overflow Division:
13751 // We have to evaluate this expression and throw an exception
13755 if (tree->gtOper == GT_DIV)
13757 i1 = INT32(i1) / INT32(i2);
13759 else if (tree->gtOper == GT_MOD)
13761 i1 = INT32(i1) % INT32(i2);
13763 else if (tree->gtOper == GT_UDIV)
13765 i1 = UINT32(i1) / UINT32(i2);
13769 assert(tree->gtOper == GT_UMOD);
13770 i1 = UINT32(i1) % UINT32(i2);
13778 /* We get here after folding to a GT_CNS_INT type
13779 * change the node to the new type / value and make sure the node sizes are OK */
13786 printf("\nFolding operator with constant nodes into a constant:\n");
13791 #ifdef _TARGET_64BIT_
13792 // Some operations are performed as 64 bit instead of 32 bit so the upper 32 bits
13793 // need to be discarded. Since constant values are stored as ssize_t and the node
13794 // has TYP_INT the result needs to be sign extended rather than zero extended.
13796 #endif // _TARGET_64BIT_
13798 /* Also all conditional folding jumps here since the node hanging from
13799 * GT_JTRUE has to be a GT_CNS_INT - value 0 or 1 */
13801 tree->ChangeOperConst(GT_CNS_INT);
13802 tree->gtType = TYP_INT;
13803 tree->gtIntCon.gtIconVal = i1;
13804 tree->gtIntCon.gtFieldSeq = fieldSeq;
13805 if (vnStore != nullptr)
13807 fgValueNumberTreeConst(tree);
13812 printf("Bashed to int constant:\n");
13818 /* This operation is going to cause an overflow exception. Morph into
13819 an overflow helper. Put a dummy constant value for code generation.
13821 We could remove all subsequent trees in the current basic block,
13822 unless this node is a child of GT_COLON
13824 NOTE: Since the folded value is not constant we should not change the
13825 "tree" node - otherwise we confuse the logic that checks if the folding
13826 was successful - instead use one of the operands, e.g. op1
13830 // Don't fold overflow operations if not global morph phase.
13831 // The reason for this is that this optimization is replacing a gentree node
13832 // with another new gentree node. Say a GT_CALL(arglist) has one 'arg'
13833 // involving overflow arithmetic. During assertion prop, it is possible
13834 // that the 'arg' could be constant folded and the result could lead to an
13835 // overflow. In such a case 'arg' will get replaced with GT_COMMA node
13836 // but fgMorphArgs() - see the logic around "if(lateArgsComputed)" - doesn't
13837 // update args table. For this reason this optimization is enabled only
13838 // for global morphing phase.
13840 // TODO-CQ: Once fgMorphArgs() is fixed this restriction could be removed.
13841 CLANG_FORMAT_COMMENT_ANCHOR;
13843 if (!fgGlobalMorph)
13845 assert(tree->gtOverflow());
13849 op1 = gtNewLconNode(0);
13850 if (vnStore != nullptr)
13852 op1->gtVNPair.SetBoth(vnStore->VNZeroForType(TYP_LONG));
13857 // Don't fold overflow operations if not global morph phase.
13858 // The reason for this is that this optimization is replacing a gentree node
13859 // with another new gentree node. Say a GT_CALL(arglist) has one 'arg'
13860 // involving overflow arithmetic. During assertion prop, it is possible
13861 // that the 'arg' could be constant folded and the result could lead to an
13862 // overflow. In such a case 'arg' will get replaced with GT_COMMA node
13863 // but fgMorphArgs() - see the logic around "if(lateArgsComputed)" - doesn't
13864 // update args table. For this reason this optimization is enabled only
13865 // for global morphing phase.
13867 // TODO-CQ: Once fgMorphArgs() is fixed this restriction could be removed.
13869 if (!fgGlobalMorph)
13871 assert(tree->gtOverflow());
13875 op1 = gtNewIconNode(0);
13876 if (vnStore != nullptr)
13878 op1->gtVNPair.SetBoth(vnStore->VNZeroForType(TYP_INT));
13886 printf("\nFolding binary operator with constant nodes into a comma throw:\n");
13890 /* We will change the cast to a GT_COMMA and attach the exception helper as gtOp.gtOp1.
13891 * The constant expression zero becomes op2. */
13893 assert(tree->gtOverflow());
13894 assert(tree->gtOper == GT_ADD || tree->gtOper == GT_SUB || tree->gtOper == GT_CAST ||
13895 tree->gtOper == GT_MUL);
13899 op1 = gtNewHelperCallNode(CORINFO_HELP_OVERFLOW, TYP_VOID,
13900 gtNewArgList(gtNewIconNode(compCurBB->bbTryIndex)));
13902 // op1 is a call to the JIT helper that throws an Overflow exception
13903 // attach the ExcSet for VNF_OverflowExc(Void) to this call
13905 if (vnStore != nullptr)
13908 vnStore->VNPWithExc(ValueNumPair(ValueNumStore::VNForVoid(), ValueNumStore::VNForVoid()),
13909 vnStore->VNPExcSetSingleton(
13910 vnStore->VNPairForFunc(TYP_REF, VNF_OverflowExc, vnStore->VNPForVoid())));
13913 tree = gtNewOperNode(GT_COMMA, tree->gtType, op1, op2);
13917 /*-------------------------------------------------------------------------
13918 * Fold constant LONG binary operator
13923 // No GC pointer types should be folded here...
13925 assert(!varTypeIsGC(op1->gtType) && !varTypeIsGC(op2->gtType));
13927 // op1 is known to be a TYP_LONG, op2 is normally a TYP_LONG, unless we have a shift operator in which case
13930 assert((op2->gtType == TYP_LONG) || (op2->gtType == TYP_INT));
13932 if (!op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13937 if (!op2->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13942 lval1 = op1->gtIntConCommon.LngValue();
13944 // For the shift operators we can have a op2 that is a TYP_INT and thus will be GT_CNS_INT
13945 if (op2->OperGet() == GT_CNS_INT)
13947 lval2 = op2->gtIntConCommon.IconValue();
13951 lval2 = op2->gtIntConCommon.LngValue();
13954 switch (tree->gtOper)
13957 i1 = (lval1 == lval2);
13960 i1 = (lval1 != lval2);
13964 if (tree->gtFlags & GTF_UNSIGNED)
13966 i1 = (UINT64(lval1) < UINT64(lval2));
13970 i1 = (lval1 < lval2);
13975 if (tree->gtFlags & GTF_UNSIGNED)
13977 i1 = (UINT64(lval1) <= UINT64(lval2));
13981 i1 = (lval1 <= lval2);
13986 if (tree->gtFlags & GTF_UNSIGNED)
13988 i1 = (UINT64(lval1) >= UINT64(lval2));
13992 i1 = (lval1 >= lval2);
13997 if (tree->gtFlags & GTF_UNSIGNED)
13999 i1 = (UINT64(lval1) > UINT64(lval2));
14003 i1 = (lval1 > lval2);
14008 ltemp = lval1 + lval2;
14011 /* For the SIGNED case - If there is one positive and one negative operand, there can be no overflow
14012 * If both are positive, the result has to be positive, and similary for negatives.
14014 * For the UNSIGNED case - If a UINT32 operand is bigger than the result then OVF */
14016 if (tree->gtOverflow())
14018 if (tree->gtFlags & GTF_UNSIGNED)
14020 if ((UINT64(lval1) > UINT64(ltemp)) || (UINT64(lval2) > UINT64(ltemp)))
14025 else if (((lval1 < 0) == (lval2 < 0)) && ((lval1 < 0) != (ltemp < 0)))
14034 ltemp = lval1 - lval2;
14035 if (tree->gtOverflow())
14037 if (tree->gtFlags & GTF_UNSIGNED)
14039 if (UINT64(lval2) > UINT64(lval1))
14046 /* If both operands are +ve or both are -ve, there can be no
14047 overflow. Else use the logic for : lval1 + (-lval2) */
14049 if ((lval1 < 0) != (lval2 < 0))
14051 if (lval2 == INT64_MIN)
14056 goto LNG_ADD_CHKOVF;
14064 ltemp = lval1 * lval2;
14066 if (tree->gtOverflow() && lval2 != 0)
14069 if (tree->gtFlags & GTF_UNSIGNED)
14071 UINT64 ultemp = ltemp;
14072 UINT64 ulval1 = lval1;
14073 UINT64 ulval2 = lval2;
14074 if ((ultemp / ulval2) != ulval1)
14081 // This does a multiply and then reverses it. This test works great except for MIN_INT *
14082 //-1. In that case we mess up the sign on ltmp. Make sure to double check the sign.
14083 // if either is 0, then no overflow
14084 if (lval1 != 0) // lval2 checked above.
14086 if (((lval1 < 0) == (lval2 < 0)) && (ltemp < 0))
14090 if (((lval1 < 0) != (lval2 < 0)) && (ltemp > 0))
14095 // TODO-Amd64-Unix: Remove the code that disables optimizations for this method when the
14097 // optimizer is fixed and/or the method implementation is refactored in a simpler code.
14098 // There is a bug in the clang-3.5 optimizer. The issue is that in release build the
14099 // optimizer is mistyping (or just wrongly decides to use 32 bit operation for a corner
14100 // case of MIN_LONG) the args of the (ltemp / lval2) to int (it does a 32 bit div
14101 // operation instead of 64 bit.). For the case of lval1 and lval2 equal to MIN_LONG
14102 // (0x8000000000000000) this results in raising a SIGFPE.
14103 // Optimizations disabled for now. See compiler.h.
14104 if ((ltemp / lval2) != lval1)
14126 lval1 <<= (lval2 & 0x3f);
14129 lval1 >>= (lval2 & 0x3f);
14132 /* logical shift -> make it unsigned to not propagate the sign bit */
14133 lval1 = UINT64(lval1) >> (lval2 & 0x3f);
14136 lval1 = (lval1 << (lval2 & 0x3f)) | (UINT64(lval1) >> ((64 - lval2) & 0x3f));
14139 lval1 = (lval1 << ((64 - lval2) & 0x3f)) | (UINT64(lval1) >> (lval2 & 0x3f));
14142 // Both DIV and IDIV on x86 raise an exception for min_int (and min_long) / -1. So we preserve
14143 // that behavior here.
14150 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
14162 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
14174 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
14178 lval1 = UINT64(lval1) / UINT64(lval2);
14186 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
14190 lval1 = UINT64(lval1) % UINT64(lval2);
14198 if (fieldSeq != FieldSeqStore::NotAField())
14206 printf("\nFolding long operator with constant nodes into a constant:\n");
14210 assert((GenTree::s_gtNodeSizes[GT_CNS_NATIVELONG] == TREE_NODE_SZ_SMALL) ||
14211 (tree->gtDebugFlags & GTF_DEBUG_NODE_LARGE));
14213 tree->ChangeOperConst(GT_CNS_NATIVELONG);
14214 tree->gtIntConCommon.SetLngValue(lval1);
14215 if (vnStore != nullptr)
14217 fgValueNumberTreeConst(tree);
14223 printf("Bashed to long constant:\n");
14229 /*-------------------------------------------------------------------------
14230 * Fold constant FLOAT or DOUBLE binary operator
14236 if (tree->gtOverflowEx())
14241 assert(op1->gtOper == GT_CNS_DBL);
14242 d1 = op1->gtDblCon.gtDconVal;
14244 assert(varTypeIsFloating(op2->gtType));
14245 assert(op2->gtOper == GT_CNS_DBL);
14246 d2 = op2->gtDblCon.gtDconVal;
14248 /* Special case - check if we have NaN operands.
14249 * For comparisons if not an unordered operation always return 0.
14250 * For unordered operations (i.e. the GTF_RELOP_NAN_UN flag is set)
14251 * the result is always true - return 1. */
14253 if (_isnan(d1) || _isnan(d2))
14258 printf("Double operator(s) is NaN\n");
14261 if (tree->OperKind() & GTK_RELOP)
14263 if (tree->gtFlags & GTF_RELOP_NAN_UN)
14265 /* Unordered comparison with NaN always succeeds */
14271 /* Normal comparison with NaN always fails */
14278 switch (tree->gtOper)
14300 // Floating point arithmetic should be done in declared
14301 // precision while doing constant folding. For this reason though TYP_FLOAT
14302 // constants are stored as double constants, while performing float arithmetic,
14303 // double constants should be converted to float. Here is an example case
14304 // where performing arithmetic in double precision would lead to incorrect
14308 // float a = float.MaxValue;
14309 // float b = a*a; This will produce +inf in single precision and 1.1579207543382391e+077 in double
14311 // flaot c = b/b; This will produce NaN in single precision and 1 in double precision.
14313 if (op1->TypeGet() == TYP_FLOAT)
14315 f1 = forceCastToFloat(d1);
14316 f2 = forceCastToFloat(d2);
14317 d1 = forceCastToFloat(f1 + f2);
14326 if (op1->TypeGet() == TYP_FLOAT)
14328 f1 = forceCastToFloat(d1);
14329 f2 = forceCastToFloat(d2);
14330 d1 = forceCastToFloat(f1 - f2);
14339 if (op1->TypeGet() == TYP_FLOAT)
14341 f1 = forceCastToFloat(d1);
14342 f2 = forceCastToFloat(d2);
14343 d1 = forceCastToFloat(f1 * f2);
14356 if (op1->TypeGet() == TYP_FLOAT)
14358 f1 = forceCastToFloat(d1);
14359 f2 = forceCastToFloat(d2);
14360 d1 = forceCastToFloat(f1 / f2);
14377 printf("\nFolding fp operator with constant nodes into a fp constant:\n");
14382 assert((GenTree::s_gtNodeSizes[GT_CNS_DBL] == TREE_NODE_SZ_SMALL) ||
14383 (tree->gtDebugFlags & GTF_DEBUG_NODE_LARGE));
14385 tree->ChangeOperConst(GT_CNS_DBL);
14386 tree->gtDblCon.gtDconVal = d1;
14387 if (vnStore != nullptr)
14389 fgValueNumberTreeConst(tree);
14394 printf("Bashed to fp constant:\n");
14401 /* not a foldable typ */
14405 //-------------------------------------------------------------------------
14409 /* Make sure no side effect flags are set on this constant node */
14411 tree->gtFlags &= ~GTF_ALL_EFFECT;
14416 #pragma warning(pop)
14419 //------------------------------------------------------------------------
14420 // gtNewTempAssign: Create an assignment of the given value to a temp.
14423 // tmp - local number for a compiler temp
14424 // val - value to assign to the temp
14425 // pAfterStmt - statement to insert any additional statements after
14426 // ilOffset - il offset for new statements
14427 // block - block to insert any additional statements in
14430 // Normally a new assignment node.
14431 // However may return a nop node if val is simply a reference to the temp.
14434 // Self-assignments may be represented via NOPs.
14436 // May update the type of the temp, if it was previously unknown.
14438 // May set compFloatingPointUsed.
14440 GenTree* Compiler::gtNewTempAssign(
14441 unsigned tmp, GenTree* val, GenTree** pAfterStmt, IL_OFFSETX ilOffset, BasicBlock* block)
14443 // Self-assignment is a nop.
14444 if (val->OperGet() == GT_LCL_VAR && val->gtLclVarCommon.gtLclNum == tmp)
14446 return gtNewNothingNode();
14449 LclVarDsc* varDsc = lvaTable + tmp;
14451 if (varDsc->TypeGet() == TYP_I_IMPL && val->TypeGet() == TYP_BYREF)
14453 impBashVarAddrsToI(val);
14456 var_types valTyp = val->TypeGet();
14457 if (val->OperGet() == GT_LCL_VAR && lvaTable[val->gtLclVar.gtLclNum].lvNormalizeOnLoad())
14459 valTyp = lvaGetRealType(val->gtLclVar.gtLclNum);
14460 val->gtType = valTyp;
14462 var_types dstTyp = varDsc->TypeGet();
14464 /* If the variable's lvType is not yet set then set it here */
14465 if (dstTyp == TYP_UNDEF)
14467 varDsc->lvType = dstTyp = genActualType(valTyp);
14468 if (varTypeIsGC(dstTyp))
14470 varDsc->lvStructGcCount = 1;
14473 else if (varTypeIsSIMD(dstTyp))
14475 varDsc->lvSIMDType = 1;
14481 /* Make sure the actual types match */
14482 if (genActualType(valTyp) != genActualType(dstTyp))
14484 // Plus some other exceptions that are apparently legal:
14485 // 1) TYP_REF or BYREF = TYP_I_IMPL
14487 if (varTypeIsGC(dstTyp) && (valTyp == TYP_I_IMPL))
14491 // 2) TYP_DOUBLE = TYP_FLOAT or TYP_FLOAT = TYP_DOUBLE
14492 else if (varTypeIsFloating(dstTyp) && varTypeIsFloating(valTyp))
14500 assert(!"Incompatible types for gtNewTempAssign");
14505 // Floating Point assignments can be created during inlining
14506 // see "Zero init inlinee locals:" in fgInlinePrependStatements
14507 // thus we may need to set compFloatingPointUsed to true here.
14509 if (varTypeIsFloating(dstTyp) && (compFloatingPointUsed == false))
14511 compFloatingPointUsed = true;
14514 /* Create the assignment node */
14517 GenTree* dest = gtNewLclvNode(tmp, dstTyp);
14518 dest->gtFlags |= GTF_VAR_DEF;
14520 // With first-class structs, we should be propagating the class handle on all non-primitive
14521 // struct types. We don't have a convenient way to do that for all SIMD temps, since some
14522 // internal trees use SIMD types that are not used by the input IL. In this case, we allow
14523 // a null type handle and derive the necessary information about the type from its varType.
14524 CORINFO_CLASS_HANDLE structHnd = gtGetStructHandleIfPresent(val);
14525 if (varTypeIsStruct(valTyp) && ((structHnd != NO_CLASS_HANDLE) || (varTypeIsSIMD(valTyp))))
14527 // The struct value may be be a child of a GT_COMMA.
14528 GenTree* valx = val->gtEffectiveVal(/*commaOnly*/ true);
14530 if (structHnd != NO_CLASS_HANDLE)
14532 lvaSetStruct(tmp, structHnd, false);
14536 assert(valx->gtOper != GT_OBJ);
14538 dest->gtFlags |= GTF_DONT_CSE;
14539 valx->gtFlags |= GTF_DONT_CSE;
14540 asg = impAssignStruct(dest, val, structHnd, (unsigned)CHECK_SPILL_NONE, pAfterStmt, ilOffset, block);
14544 asg = gtNewAssignNode(dest, val);
14547 if (compRationalIRForm)
14549 Rationalizer::RewriteAssignmentIntoStoreLcl(asg->AsOp());
14555 /*****************************************************************************
14557 * Create a helper call to access a COM field (iff 'assg' is non-zero this is
14558 * an assignment and 'assg' is the new value).
14561 GenTree* Compiler::gtNewRefCOMfield(GenTree* objPtr,
14562 CORINFO_RESOLVED_TOKEN* pResolvedToken,
14563 CORINFO_ACCESS_FLAGS access,
14564 CORINFO_FIELD_INFO* pFieldInfo,
14566 CORINFO_CLASS_HANDLE structType,
14569 assert(pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER ||
14570 pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_ADDR_HELPER ||
14571 pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_ADDR_HELPER);
14573 /* If we can't access it directly, we need to call a helper function */
14574 GenTreeArgList* args = nullptr;
14575 var_types helperType = TYP_BYREF;
14577 if (pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER)
14579 if (access & CORINFO_ACCESS_SET)
14581 assert(assg != nullptr);
14582 // helper needs pointer to struct, not struct itself
14583 if (pFieldInfo->helper == CORINFO_HELP_SETFIELDSTRUCT)
14585 assert(structType != nullptr);
14586 assg = impGetStructAddr(assg, structType, (unsigned)CHECK_SPILL_ALL, true);
14588 else if (lclTyp == TYP_DOUBLE && assg->TypeGet() == TYP_FLOAT)
14590 assg = gtNewCastNode(TYP_DOUBLE, assg, false, TYP_DOUBLE);
14592 else if (lclTyp == TYP_FLOAT && assg->TypeGet() == TYP_DOUBLE)
14594 assg = gtNewCastNode(TYP_FLOAT, assg, false, TYP_FLOAT);
14597 args = gtNewArgList(assg);
14598 helperType = TYP_VOID;
14600 else if (access & CORINFO_ACCESS_GET)
14602 helperType = lclTyp;
14604 // The calling convention for the helper does not take into
14605 // account optimization of primitive structs.
14606 if ((pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT) && !varTypeIsStruct(lclTyp))
14608 helperType = TYP_STRUCT;
14613 if (pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT || pFieldInfo->helper == CORINFO_HELP_SETFIELDSTRUCT)
14615 assert(pFieldInfo->structType != nullptr);
14616 args = gtNewListNode(gtNewIconEmbClsHndNode(pFieldInfo->structType), args);
14619 GenTree* fieldHnd = impTokenToHandle(pResolvedToken);
14620 if (fieldHnd == nullptr)
14621 { // compDonotInline()
14625 args = gtNewListNode(fieldHnd, args);
14627 // If it's a static field, we shouldn't have an object node
14628 // If it's an instance field, we have an object node
14629 assert((pFieldInfo->fieldAccessor != CORINFO_FIELD_STATIC_ADDR_HELPER) ^ (objPtr == nullptr));
14631 if (objPtr != nullptr)
14633 args = gtNewListNode(objPtr, args);
14636 GenTreeCall* call = gtNewHelperCallNode(pFieldInfo->helper, genActualType(helperType), args);
14638 #if FEATURE_MULTIREG_RET
14639 if (varTypeIsStruct(call))
14641 // Initialize Return type descriptor of call node.
14642 ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc();
14643 retTypeDesc->InitializeStructReturnType(this, structType);
14645 #endif // FEATURE_MULTIREG_RET
14647 GenTree* result = call;
14649 if (pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER)
14651 if (access & CORINFO_ACCESS_GET)
14653 if (pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT)
14655 if (!varTypeIsStruct(lclTyp))
14657 // get the result as primitive type
14658 result = impGetStructAddr(result, structType, (unsigned)CHECK_SPILL_ALL, true);
14659 result = gtNewOperNode(GT_IND, lclTyp, result);
14662 else if (varTypeIsIntegral(lclTyp) && genTypeSize(lclTyp) < genTypeSize(TYP_INT))
14664 // The helper does not extend the small return types.
14665 result = gtNewCastNode(genActualType(lclTyp), result, false, lclTyp);
14671 // OK, now do the indirection
14672 if (access & CORINFO_ACCESS_GET)
14674 if (varTypeIsStruct(lclTyp))
14676 result = gtNewObjNode(structType, result);
14680 result = gtNewOperNode(GT_IND, lclTyp, result);
14682 result->gtFlags |= (GTF_EXCEPT | GTF_GLOB_REF);
14684 else if (access & CORINFO_ACCESS_SET)
14686 if (varTypeIsStruct(lclTyp))
14688 result = impAssignStructPtr(result, assg, structType, (unsigned)CHECK_SPILL_ALL);
14692 result = gtNewOperNode(GT_IND, lclTyp, result);
14693 result->gtFlags |= (GTF_EXCEPT | GTF_GLOB_REF | GTF_IND_TGTANYWHERE);
14694 result = gtNewAssignNode(result, assg);
14702 /*****************************************************************************
14704 * Return true if the given node (excluding children trees) contains side effects.
14705 * Note that it does not recurse, and children need to be handled separately.
14706 * It may return false even if the node has GTF_SIDE_EFFECT (because of its children).
14708 * Similar to OperMayThrow() (but handles GT_CALLs specially), but considers
14712 bool Compiler::gtNodeHasSideEffects(GenTree* tree, unsigned flags)
14714 if (flags & GTF_ASG)
14716 // TODO-Cleanup: This only checks for GT_ASG but according to OperRequiresAsgFlag there
14717 // are many more opers that are considered to have an assignment side effect: atomic ops
14718 // (GT_CMPXCHG & co.), GT_MEMORYBARRIER (not classified as an atomic op) and HW intrinsic
14719 // memory stores. Atomic ops have special handling in gtExtractSideEffList but the others
14720 // will simply be dropped is they are ever subject to an "extract side effects" operation.
14721 // It is possible that the reason no bugs have yet been observed in this area is that the
14722 // other nodes are likely to always be tree roots.
14723 if (tree->OperIs(GT_ASG))
14729 // Are there only GTF_CALL side effects remaining? (and no other side effect kinds)
14730 if (flags & GTF_CALL)
14732 if (tree->OperGet() == GT_CALL)
14734 GenTreeCall* const call = tree->AsCall();
14735 const bool ignoreExceptions = (flags & GTF_EXCEPT) == 0;
14736 const bool ignoreCctors = (flags & GTF_IS_IN_CSE) != 0; // We can CSE helpers that run cctors.
14737 if (!call->HasSideEffects(this, ignoreExceptions, ignoreCctors))
14739 // If this call is otherwise side effect free, check its arguments.
14740 for (GenTreeArgList* args = call->gtCallArgs; args != nullptr; args = args->Rest())
14742 if (gtTreeHasSideEffects(args->Current(), flags))
14747 // I'm a little worried that args that assign to temps that are late args will look like
14748 // side effects...but better to be conservative for now.
14749 for (GenTreeArgList* args = call->gtCallLateArgs; args != nullptr; args = args->Rest())
14751 if (gtTreeHasSideEffects(args->Current(), flags))
14761 // Otherwise the GT_CALL is considered to have side-effects.
14766 if (flags & GTF_EXCEPT)
14768 if (tree->OperMayThrow(this))
14774 // Expressions declared as CSE by (e.g.) hoisting code are considered to have relevant side
14775 // effects (if we care about GTF_MAKE_CSE).
14776 if ((flags & GTF_MAKE_CSE) && (tree->gtFlags & GTF_MAKE_CSE))
14784 /*****************************************************************************
14785 * Returns true if the expr tree has any side effects.
14788 bool Compiler::gtTreeHasSideEffects(GenTree* tree, unsigned flags /* = GTF_SIDE_EFFECT*/)
14790 // These are the side effect flags that we care about for this tree
14791 unsigned sideEffectFlags = tree->gtFlags & flags;
14793 // Does this tree have any Side-effect flags set that we care about?
14794 if (sideEffectFlags == 0)
14800 if (sideEffectFlags == GTF_CALL)
14802 if (tree->OperGet() == GT_CALL)
14804 // Generally all trees that contain GT_CALL nodes are considered to have side-effects.
14806 if (tree->gtCall.gtCallType == CT_HELPER)
14808 // If this node is a helper call we may not care about the side-effects.
14809 // Note that gtNodeHasSideEffects checks the side effects of the helper itself
14810 // as well as the side effects of its arguments.
14811 return gtNodeHasSideEffects(tree, flags);
14814 else if (tree->OperGet() == GT_INTRINSIC)
14816 if (gtNodeHasSideEffects(tree, flags))
14821 if (gtNodeHasSideEffects(tree->gtOp.gtOp1, flags))
14826 if ((tree->gtOp.gtOp2 != nullptr) && gtNodeHasSideEffects(tree->gtOp.gtOp2, flags))
14838 GenTree* Compiler::gtBuildCommaList(GenTree* list, GenTree* expr)
14840 // 'list' starts off as null,
14841 // and when it is null we haven't started the list yet.
14843 if (list != nullptr)
14845 // Create a GT_COMMA that appends 'expr' in front of the remaining set of expressions in (*list)
14846 GenTree* result = gtNewOperNode(GT_COMMA, TYP_VOID, expr, list);
14848 // Set the flags in the comma node
14849 result->gtFlags |= (list->gtFlags & GTF_ALL_EFFECT);
14850 result->gtFlags |= (expr->gtFlags & GTF_ALL_EFFECT);
14852 // 'list' and 'expr' should have valuenumbers defined for both or for neither one (unless we are remorphing,
14853 // in which case a prior transform involving either node may have discarded or otherwise invalidated the value
14855 assert((list->gtVNPair.BothDefined() == expr->gtVNPair.BothDefined()) || !fgGlobalMorph);
14857 // Set the ValueNumber 'gtVNPair' for the new GT_COMMA node
14859 if (list->gtVNPair.BothDefined() && expr->gtVNPair.BothDefined())
14861 // The result of a GT_COMMA node is op2, the normal value number is op2vnp
14862 // But we also need to include the union of side effects from op1 and op2.
14863 // we compute this value into exceptions_vnp.
14864 ValueNumPair op1vnp;
14865 ValueNumPair op1Xvnp = ValueNumStore::VNPForEmptyExcSet();
14866 ValueNumPair op2vnp;
14867 ValueNumPair op2Xvnp = ValueNumStore::VNPForEmptyExcSet();
14869 vnStore->VNPUnpackExc(expr->gtVNPair, &op1vnp, &op1Xvnp);
14870 vnStore->VNPUnpackExc(list->gtVNPair, &op2vnp, &op2Xvnp);
14872 ValueNumPair exceptions_vnp = ValueNumStore::VNPForEmptyExcSet();
14874 exceptions_vnp = vnStore->VNPExcSetUnion(exceptions_vnp, op1Xvnp);
14875 exceptions_vnp = vnStore->VNPExcSetUnion(exceptions_vnp, op2Xvnp);
14877 result->gtVNPair = vnStore->VNPWithExc(op2vnp, exceptions_vnp);
14884 // The 'expr' will start the list of expressions
14889 //------------------------------------------------------------------------
14890 // gtExtractSideEffList: Extracts side effects from the given expression.
14893 // expr - the expression tree to extract side effects from
14894 // pList - pointer to a (possibly null) GT_COMMA list that
14895 // will contain the extracted side effects
14896 // flags - side effect flags to be considered
14897 // ignoreRoot - ignore side effects on the expression root node
14900 // Side effects are prepended to the GT_COMMA list such that op1 of
14901 // each comma node holds the side effect tree and op2 points to the
14902 // next comma node. The original side effect execution order is preserved.
14904 void Compiler::gtExtractSideEffList(GenTree* expr,
14906 unsigned flags /* = GTF_SIDE_EFFECT*/,
14907 bool ignoreRoot /* = false */)
14909 class SideEffectExtractor final : public GenTreeVisitor<SideEffectExtractor>
14912 const unsigned m_flags;
14913 ArrayStack<GenTree*> m_sideEffects;
14918 UseExecutionOrder = true
14921 SideEffectExtractor(Compiler* compiler, unsigned flags)
14922 : GenTreeVisitor(compiler), m_flags(flags), m_sideEffects(compiler->getAllocator(CMK_SideEffects))
14926 fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
14928 GenTree* node = *use;
14930 bool treeHasSideEffects = m_compiler->gtTreeHasSideEffects(node, m_flags);
14932 if (treeHasSideEffects)
14934 if (m_compiler->gtNodeHasSideEffects(node, m_flags))
14936 m_sideEffects.Push(node);
14937 return Compiler::WALK_SKIP_SUBTREES;
14940 // TODO-Cleanup: These have GTF_ASG set but for some reason gtNodeHasSideEffects ignores
14941 // them. See the related gtNodeHasSideEffects comment as well.
14942 // Also, these nodes must always be preserved, no matter what side effect flags are passed
14943 // in. But then it should never be the case that gtExtractSideEffList gets called without
14944 // specifying GTF_ASG so there doesn't seem to be any reason to be inconsistent with
14945 // gtNodeHasSideEffects and make this check unconditionally.
14946 if (node->OperIsAtomicOp())
14948 m_sideEffects.Push(node);
14949 return Compiler::WALK_SKIP_SUBTREES;
14952 if ((m_flags & GTF_EXCEPT) != 0)
14954 // Special case - GT_ADDR of GT_IND nodes of TYP_STRUCT have to be kept together.
14955 if (node->OperIs(GT_ADDR) && node->gtGetOp1()->OperIsIndir() &&
14956 (node->gtGetOp1()->TypeGet() == TYP_STRUCT))
14959 if (m_compiler->verbose)
14961 printf("Keep the GT_ADDR and GT_IND together:\n");
14964 m_sideEffects.Push(node);
14965 return Compiler::WALK_SKIP_SUBTREES;
14969 // Generally all GT_CALL nodes are considered to have side-effects.
14970 // So if we get here it must be a helper call that we decided it does
14971 // not have side effects that we needed to keep.
14972 assert(!node->OperIs(GT_CALL) || (node->AsCall()->gtCallType == CT_HELPER));
14975 if ((m_flags & GTF_IS_IN_CSE) != 0)
14977 // If we're doing CSE then we also need to unmark CSE nodes. This will fail for CSE defs,
14978 // those need to be extracted as if they're side effects.
14979 if (!UnmarkCSE(node))
14981 m_sideEffects.Push(node);
14982 return Compiler::WALK_SKIP_SUBTREES;
14985 // The existence of CSE defs and uses is not propagated up the tree like side
14986 // effects are. We need to continue visiting the tree as if it has side effects.
14987 treeHasSideEffects = true;
14990 return treeHasSideEffects ? Compiler::WALK_CONTINUE : Compiler::WALK_SKIP_SUBTREES;
14994 bool UnmarkCSE(GenTree* node)
14996 assert(m_compiler->optValnumCSE_phase);
14998 if (m_compiler->optUnmarkCSE(node))
15000 // The call to optUnmarkCSE(node) should have cleared any CSE info.
15001 assert(!IS_CSE_INDEX(node->gtCSEnum));
15006 assert(IS_CSE_DEF(node->gtCSEnum));
15008 if (m_compiler->verbose)
15010 printf("Preserving the CSE def #%02d at ", GET_CSE_INDEX(node->gtCSEnum));
15011 m_compiler->printTreeID(node);
15019 assert(!expr->OperIs(GT_STMT));
15021 SideEffectExtractor extractor(this, flags);
15025 for (GenTree* op : expr->Operands())
15027 extractor.WalkTree(&op, nullptr);
15032 extractor.WalkTree(&expr, nullptr);
15035 GenTree* list = *pList;
15037 // The extractor returns side effects in execution order but gtBuildCommaList prepends
15038 // to the comma-based side effect list so we have to build the list in reverse order.
15039 // This is also why the list cannot be built while traversing the tree.
15040 // The number of side effects is usually small (<= 4), less than the ArrayStack's
15041 // built-in size, so memory allocation is avoided.
15042 while (extractor.m_sideEffects.Height() > 0)
15044 list = gtBuildCommaList(list, extractor.m_sideEffects.Pop());
15050 /*****************************************************************************
15052 * For debugging only - displays a tree node list and makes sure all the
15053 * links are correctly set.
15058 void dispNodeList(GenTree* list, bool verbose)
15060 GenTree* last = nullptr;
15070 next = list->gtNext;
15074 printf("%08X -> %08X -> %08X\n", last, list, next);
15077 assert(!last || last->gtNext == list);
15079 assert(next == nullptr || next->gtPrev == list);
15089 printf(""); // null string means flush
15092 /*****************************************************************************
15093 * Callback to assert that the nodes of a qmark-colon subtree are marked
15097 Compiler::fgWalkResult Compiler::gtAssertColonCond(GenTree** pTree, fgWalkData* data)
15099 assert(data->pCallbackData == nullptr);
15101 assert((*pTree)->gtFlags & GTF_COLON_COND);
15103 return WALK_CONTINUE;
15107 /*****************************************************************************
15108 * Callback to mark the nodes of a qmark-colon subtree that are conditionally
15113 Compiler::fgWalkResult Compiler::gtMarkColonCond(GenTree** pTree, fgWalkData* data)
15115 assert(data->pCallbackData == nullptr);
15117 (*pTree)->gtFlags |= GTF_COLON_COND;
15119 return WALK_CONTINUE;
15122 /*****************************************************************************
15123 * Callback to clear the conditionally executed flags of nodes that no longer
15124 will be conditionally executed. Note that when we find another colon we must
15125 stop, as the nodes below this one WILL be conditionally executed. This callback
15126 is called when folding a qmark condition (ie the condition is constant).
15130 Compiler::fgWalkResult Compiler::gtClearColonCond(GenTree** pTree, fgWalkData* data)
15132 GenTree* tree = *pTree;
15134 assert(data->pCallbackData == nullptr);
15136 if (tree->OperGet() == GT_COLON)
15138 // Nodes below this will be conditionally executed.
15139 return WALK_SKIP_SUBTREES;
15142 tree->gtFlags &= ~GTF_COLON_COND;
15143 return WALK_CONTINUE;
15146 struct FindLinkData
15148 GenTree* nodeToFind;
15152 /*****************************************************************************
15154 * Callback used by the tree walker to implement fgFindLink()
15156 static Compiler::fgWalkResult gtFindLinkCB(GenTree** pTree, Compiler::fgWalkData* cbData)
15158 FindLinkData* data = (FindLinkData*)cbData->pCallbackData;
15159 if (*pTree == data->nodeToFind)
15161 data->result = pTree;
15162 return Compiler::WALK_ABORT;
15165 return Compiler::WALK_CONTINUE;
15168 GenTree** Compiler::gtFindLink(GenTree* stmt, GenTree* node)
15170 assert(stmt->gtOper == GT_STMT);
15172 FindLinkData data = {node, nullptr};
15174 fgWalkResult result = fgWalkTreePre(&stmt->gtStmt.gtStmtExpr, gtFindLinkCB, &data);
15176 if (result == WALK_ABORT)
15178 assert(data.nodeToFind == *data.result);
15179 return data.result;
15187 /*****************************************************************************
15189 * Callback that checks if a tree node has oper type GT_CATCH_ARG
15192 static Compiler::fgWalkResult gtFindCatchArg(GenTree** pTree, Compiler::fgWalkData* /* data */)
15194 return ((*pTree)->OperGet() == GT_CATCH_ARG) ? Compiler::WALK_ABORT : Compiler::WALK_CONTINUE;
15197 /*****************************************************************************/
15198 bool Compiler::gtHasCatchArg(GenTree* tree)
15200 if (((tree->gtFlags & GTF_ORDER_SIDEEFF) != 0) && (fgWalkTreePre(&tree, gtFindCatchArg) == WALK_ABORT))
15207 //------------------------------------------------------------------------
15208 // gtHasCallOnStack:
15211 // parentStack: a context (stack of parent nodes)
15214 // returns true if any of the parent nodes are a GT_CALL
15217 // We have a stack of parent nodes. This generally requires that
15218 // we are performing a recursive tree walk using struct fgWalkData
15220 //------------------------------------------------------------------------
15221 /* static */ bool Compiler::gtHasCallOnStack(GenTreeStack* parentStack)
15223 for (int i = 0; i < parentStack->Height(); i++)
15225 GenTree* node = parentStack->Index(i);
15226 if (node->OperGet() == GT_CALL)
15234 //------------------------------------------------------------------------
15235 // gtGetTypeProducerKind: determine if a tree produces a runtime type, and
15239 // tree - tree to examine
15242 // TypeProducerKind for the tree.
15245 // Checks to see if this tree returns a RuntimeType value, and if so,
15246 // how that value is determined.
15248 // Currently handles these cases
15249 // 1) The result of Object::GetType
15250 // 2) The result of typeof(...)
15251 // 3) A null reference
15252 // 4) Tree is otherwise known to have type RuntimeType
15254 // The null reference case is surprisingly common because operator
15255 // overloading turns the otherwise innocuous
15260 // into a method call.
15262 Compiler::TypeProducerKind Compiler::gtGetTypeProducerKind(GenTree* tree)
15264 if (tree->gtOper == GT_CALL)
15266 if (tree->gtCall.gtCallType == CT_HELPER)
15268 if (gtIsTypeHandleToRuntimeTypeHelper(tree->AsCall()))
15273 else if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC)
15275 if (info.compCompHnd->getIntrinsicID(tree->gtCall.gtCallMethHnd) == CORINFO_INTRINSIC_Object_GetType)
15277 return TPK_GetType;
15281 else if ((tree->gtOper == GT_INTRINSIC) && (tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType))
15283 return TPK_GetType;
15285 else if ((tree->gtOper == GT_CNS_INT) && (tree->gtIntCon.gtIconVal == 0))
15291 bool isExact = false;
15292 bool isNonNull = false;
15293 CORINFO_CLASS_HANDLE clsHnd = gtGetClassHandle(tree, &isExact, &isNonNull);
15295 if (clsHnd != NO_CLASS_HANDLE && clsHnd == info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE))
15300 return TPK_Unknown;
15303 //------------------------------------------------------------------------
15304 // gtIsTypeHandleToRuntimeTypeHelperCall -- see if tree is constructing
15305 // a RuntimeType from a handle
15308 // tree - tree to examine
15313 bool Compiler::gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call)
15315 return call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE) ||
15316 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL);
15319 //------------------------------------------------------------------------
15320 // gtIsTypeHandleToRuntimeTypeHandleHelperCall -- see if tree is constructing
15321 // a RuntimeTypeHandle from a handle
15324 // tree - tree to examine
15325 // pHelper - optional pointer to a variable that receives the type of the helper
15330 bool Compiler::gtIsTypeHandleToRuntimeTypeHandleHelper(GenTreeCall* call, CorInfoHelpFunc* pHelper)
15332 CorInfoHelpFunc helper = CORINFO_HELP_UNDEF;
15334 if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE))
15336 helper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE;
15338 else if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL))
15340 helper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL;
15343 if (pHelper != nullptr)
15348 return helper != CORINFO_HELP_UNDEF;
15351 bool Compiler::gtIsActiveCSE_Candidate(GenTree* tree)
15353 return (optValnumCSE_phase && IS_CSE_INDEX(tree->gtCSEnum));
15356 /*****************************************************************************/
15358 struct ComplexityStruct
15360 unsigned m_numNodes;
15361 unsigned m_nodeLimit;
15362 ComplexityStruct(unsigned nodeLimit) : m_numNodes(0), m_nodeLimit(nodeLimit)
15367 static Compiler::fgWalkResult ComplexityExceedsWalker(GenTree** pTree, Compiler::fgWalkData* data)
15369 ComplexityStruct* pComplexity = (ComplexityStruct*)data->pCallbackData;
15370 if (++pComplexity->m_numNodes > pComplexity->m_nodeLimit)
15372 return Compiler::WALK_ABORT;
15376 return Compiler::WALK_CONTINUE;
15380 bool Compiler::gtComplexityExceeds(GenTree** tree, unsigned limit)
15382 ComplexityStruct complexity(limit);
15383 if (fgWalkTreePre(tree, &ComplexityExceedsWalker, &complexity) == WALK_ABORT)
15393 bool GenTree::IsPhiNode()
15395 return (OperGet() == GT_PHI_ARG) || (OperGet() == GT_PHI) || IsPhiDefn();
15398 bool GenTree::IsPhiDefn()
15400 bool res = ((OperGet() == GT_ASG) && (gtOp.gtOp2 != nullptr) && (gtOp.gtOp2->OperGet() == GT_PHI)) ||
15401 ((OperGet() == GT_STORE_LCL_VAR) && (gtOp.gtOp1 != nullptr) && (gtOp.gtOp1->OperGet() == GT_PHI));
15402 assert(!res || OperGet() == GT_STORE_LCL_VAR || gtOp.gtOp1->OperGet() == GT_LCL_VAR);
15406 bool GenTree::IsPhiDefnStmt()
15408 if (OperGet() != GT_STMT)
15412 GenTree* asg = gtStmt.gtStmtExpr;
15413 return asg->IsPhiDefn();
15416 // IsPartialLclFld: Check for a GT_LCL_FLD whose type is a different size than the lclVar.
15419 // comp - the Compiler object.
15422 // Returns "true" iff 'this' is a GT_LCL_FLD or GT_STORE_LCL_FLD on which the type
15423 // is not the same size as the type of the GT_LCL_VAR
15425 bool GenTree::IsPartialLclFld(Compiler* comp)
15427 return ((gtOper == GT_LCL_FLD) &&
15428 (comp->lvaTable[this->gtLclVarCommon.gtLclNum].lvExactSize != genTypeSize(gtType)));
15431 bool GenTree::DefinesLocal(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, bool* pIsEntire)
15433 GenTreeBlk* blkNode = nullptr;
15434 if (OperIs(GT_ASG))
15436 if (gtOp.gtOp1->IsLocal())
15438 GenTreeLclVarCommon* lclVarTree = gtOp.gtOp1->AsLclVarCommon();
15439 *pLclVarTree = lclVarTree;
15440 if (pIsEntire != nullptr)
15442 if (lclVarTree->IsPartialLclFld(comp))
15444 *pIsEntire = false;
15453 else if (gtOp.gtOp1->OperGet() == GT_IND)
15455 GenTree* indArg = gtOp.gtOp1->gtOp.gtOp1;
15456 return indArg->DefinesLocalAddr(comp, genTypeSize(gtOp.gtOp1->TypeGet()), pLclVarTree, pIsEntire);
15458 else if (gtOp.gtOp1->OperIsBlk())
15460 blkNode = gtOp.gtOp1->AsBlk();
15463 else if (OperIsBlk())
15465 blkNode = this->AsBlk();
15467 if (blkNode != nullptr)
15469 GenTree* destAddr = blkNode->Addr();
15470 unsigned width = blkNode->gtBlkSize;
15471 // Do we care about whether this assigns the entire variable?
15472 if (pIsEntire != nullptr && width == 0)
15474 assert(blkNode->gtOper == GT_DYN_BLK);
15475 GenTree* blockWidth = blkNode->AsDynBlk()->gtDynamicSize;
15476 if (blockWidth->IsCnsIntOrI())
15478 if (blockWidth->IsIconHandle())
15480 // If it's a handle, it must be a class handle. We only create such block operations
15481 // for initialization of struct types, so the type of the argument(s) will match this
15482 // type, by construction, and be "entire".
15483 assert(blockWidth->IsIconHandle(GTF_ICON_CLASS_HDL));
15484 width = comp->info.compCompHnd->getClassSize(
15485 CORINFO_CLASS_HANDLE(blockWidth->gtIntConCommon.IconValue()));
15489 ssize_t swidth = blockWidth->AsIntConCommon()->IconValue();
15490 assert(swidth >= 0);
15491 // cpblk of size zero exists in the wild (in yacc-generated code in SQL) and is valid IL.
15496 width = unsigned(swidth);
15500 return destAddr->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
15506 // Returns true if this GenTree defines a result which is based on the address of a local.
15507 bool GenTree::DefinesLocalAddr(Compiler* comp, unsigned width, GenTreeLclVarCommon** pLclVarTree, bool* pIsEntire)
15509 if (OperGet() == GT_ADDR || OperGet() == GT_LCL_VAR_ADDR)
15511 GenTree* addrArg = this;
15512 if (OperGet() == GT_ADDR)
15514 addrArg = gtOp.gtOp1;
15517 if (addrArg->IsLocal() || addrArg->OperIsLocalAddr())
15519 GenTreeLclVarCommon* addrArgLcl = addrArg->AsLclVarCommon();
15520 *pLclVarTree = addrArgLcl;
15521 if (pIsEntire != nullptr)
15523 unsigned lclOffset = 0;
15524 if (addrArg->OperIsLocalField())
15526 lclOffset = addrArg->gtLclFld.gtLclOffs;
15529 if (lclOffset != 0)
15531 // We aren't updating the bytes at [0..lclOffset-1] so *pIsEntire should be set to false
15532 *pIsEntire = false;
15536 unsigned lclNum = addrArgLcl->GetLclNum();
15537 unsigned varWidth = comp->lvaLclExactSize(lclNum);
15538 if (comp->lvaTable[lclNum].lvNormalizeOnStore())
15540 // It's normalize on store, so use the full storage width -- writing to low bytes won't
15541 // necessarily yield a normalized value.
15542 varWidth = genTypeStSz(var_types(comp->lvaTable[lclNum].lvType)) * sizeof(int);
15544 *pIsEntire = (varWidth == width);
15549 else if (addrArg->OperGet() == GT_IND)
15551 // A GT_ADDR of a GT_IND can both be optimized away, recurse using the child of the GT_IND
15552 return addrArg->gtOp.gtOp1->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
15555 else if (OperGet() == GT_ADD)
15557 if (gtOp.gtOp1->IsCnsIntOrI())
15559 // If we just adding a zero then we allow an IsEntire match against width
15560 // otherwise we change width to zero to disallow an IsEntire Match
15561 return gtOp.gtOp2->DefinesLocalAddr(comp, gtOp.gtOp1->IsIntegralConst(0) ? width : 0, pLclVarTree,
15564 else if (gtOp.gtOp2->IsCnsIntOrI())
15566 // If we just adding a zero then we allow an IsEntire match against width
15567 // otherwise we change width to zero to disallow an IsEntire Match
15568 return gtOp.gtOp1->DefinesLocalAddr(comp, gtOp.gtOp2->IsIntegralConst(0) ? width : 0, pLclVarTree,
15572 // Post rationalization we could have GT_IND(GT_LEA(..)) trees.
15573 else if (OperGet() == GT_LEA)
15575 // This method gets invoked during liveness computation and therefore it is critical
15576 // that we don't miss 'use' of any local. The below logic is making the assumption
15577 // that in case of LEA(base, index, offset) - only base can be a GT_LCL_VAR_ADDR
15578 // and index is not.
15579 CLANG_FORMAT_COMMENT_ANCHOR;
15582 GenTree* index = gtOp.gtOp2;
15583 if (index != nullptr)
15585 assert(!index->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire));
15590 GenTree* base = gtOp.gtOp1;
15591 if (base != nullptr)
15593 // Lea could have an Indir as its base.
15594 if (base->OperGet() == GT_IND)
15596 base = base->gtOp.gtOp1->gtEffectiveVal(/*commas only*/ true);
15598 return base->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
15605 //------------------------------------------------------------------------
15606 // IsLocalExpr: Determine if this is a LclVarCommon node and return some
15607 // additional info about it in the two out parameters.
15610 // comp - The Compiler instance
15611 // pLclVarTree - An "out" argument that returns the local tree as a
15612 // LclVarCommon, if it is indeed local.
15613 // pFldSeq - An "out" argument that returns the value numbering field
15614 // sequence for the node, if any.
15617 // Returns true, and sets the out arguments accordingly, if this is
15618 // a LclVarCommon node.
15620 bool GenTree::IsLocalExpr(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, FieldSeqNode** pFldSeq)
15622 if (IsLocal()) // Note that this covers "GT_LCL_FLD."
15624 *pLclVarTree = AsLclVarCommon();
15625 if (OperGet() == GT_LCL_FLD)
15627 // Otherwise, prepend this field to whatever we've already accumulated outside in.
15628 *pFldSeq = comp->GetFieldSeqStore()->Append(AsLclFld()->gtFieldSeq, *pFldSeq);
15638 // If this tree evaluates some sum of a local address and some constants,
15639 // return the node for the local being addressed
15641 GenTreeLclVarCommon* GenTree::IsLocalAddrExpr()
15643 if (OperGet() == GT_ADDR)
15645 return gtOp.gtOp1->IsLocal() ? gtOp.gtOp1->AsLclVarCommon() : nullptr;
15647 else if (OperIsLocalAddr())
15649 return this->AsLclVarCommon();
15651 else if (OperGet() == GT_ADD)
15653 if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
15655 return gtOp.gtOp2->IsLocalAddrExpr();
15657 else if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
15659 return gtOp.gtOp1->IsLocalAddrExpr();
15666 bool GenTree::IsLocalAddrExpr(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, FieldSeqNode** pFldSeq)
15668 if (OperGet() == GT_ADDR)
15670 assert(!comp->compRationalIRForm);
15671 GenTree* addrArg = gtOp.gtOp1;
15672 if (addrArg->IsLocal()) // Note that this covers "GT_LCL_FLD."
15674 *pLclVarTree = addrArg->AsLclVarCommon();
15675 if (addrArg->OperGet() == GT_LCL_FLD)
15677 // Otherwise, prepend this field to whatever we've already accumulated outside in.
15678 *pFldSeq = comp->GetFieldSeqStore()->Append(addrArg->AsLclFld()->gtFieldSeq, *pFldSeq);
15687 else if (OperIsLocalAddr())
15689 *pLclVarTree = this->AsLclVarCommon();
15690 if (this->OperGet() == GT_LCL_FLD_ADDR)
15692 *pFldSeq = comp->GetFieldSeqStore()->Append(this->AsLclFld()->gtFieldSeq, *pFldSeq);
15696 else if (OperGet() == GT_ADD)
15698 if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
15700 if (gtOp.gtOp1->AsIntCon()->gtFieldSeq == nullptr)
15704 // Otherwise, prepend this field to whatever we've already accumulated outside in.
15705 *pFldSeq = comp->GetFieldSeqStore()->Append(gtOp.gtOp1->AsIntCon()->gtFieldSeq, *pFldSeq);
15706 return gtOp.gtOp2->IsLocalAddrExpr(comp, pLclVarTree, pFldSeq);
15708 else if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
15710 if (gtOp.gtOp2->AsIntCon()->gtFieldSeq == nullptr)
15714 // Otherwise, prepend this field to whatever we've already accumulated outside in.
15715 *pFldSeq = comp->GetFieldSeqStore()->Append(gtOp.gtOp2->AsIntCon()->gtFieldSeq, *pFldSeq);
15716 return gtOp.gtOp1->IsLocalAddrExpr(comp, pLclVarTree, pFldSeq);
15723 //------------------------------------------------------------------------
15724 // IsLclVarUpdateTree: Determine whether this is an assignment tree of the
15725 // form Vn = Vn 'oper' 'otherTree' where Vn is a lclVar
15728 // pOtherTree - An "out" argument in which 'otherTree' will be returned.
15729 // pOper - An "out" argument in which 'oper' will be returned.
15732 // If the tree is of the above form, the lclNum of the variable being
15733 // updated is returned, and 'pOtherTree' and 'pOper' are set.
15734 // Otherwise, returns BAD_VAR_NUM.
15737 // 'otherTree' can have any shape.
15738 // We avoid worrying about whether the op is commutative by only considering the
15739 // first operand of the rhs. It is expected that most trees of this form will
15740 // already have the lclVar on the lhs.
15741 // TODO-CQ: Evaluate whether there are missed opportunities due to this, or
15742 // whether gtSetEvalOrder will already have put the lclVar on the lhs in
15743 // the cases of interest.
15745 unsigned GenTree::IsLclVarUpdateTree(GenTree** pOtherTree, genTreeOps* pOper)
15747 unsigned lclNum = BAD_VAR_NUM;
15748 if (OperIs(GT_ASG))
15750 GenTree* lhs = gtOp.gtOp1;
15751 if (lhs->OperGet() == GT_LCL_VAR)
15753 unsigned lhsLclNum = lhs->AsLclVarCommon()->gtLclNum;
15754 GenTree* rhs = gtOp.gtOp2;
15755 if (rhs->OperIsBinary() && (rhs->gtOp.gtOp1->gtOper == GT_LCL_VAR) &&
15756 (rhs->gtOp.gtOp1->AsLclVarCommon()->gtLclNum == lhsLclNum))
15758 lclNum = lhsLclNum;
15759 *pOtherTree = rhs->gtOp.gtOp2;
15760 *pOper = rhs->gtOper;
15767 //------------------------------------------------------------------------
15768 // canBeContained: check whether this tree node may be a subcomponent of its parent for purposes
15769 // of code generation.
15771 // Return value: returns true if it is possible to contain this node and false otherwise.
15772 bool GenTree::canBeContained() const
15781 // It is not possible for nodes that do not produce values or that are not containable values
15782 // to be contained.
15783 if (((OperKind() & (GTK_NOVALUE | GTK_NOCONTAIN)) != 0) || (OperIsHWIntrinsic() && !isContainableHWIntrinsic()))
15791 //------------------------------------------------------------------------
15792 // isContained: check whether this tree node is a subcomponent of its parent for codegen purposes
15795 // Returns true if there is no code generated explicitly for this node.
15796 // Essentially, it will be rolled into the code generation for the parent.
15799 // This method relies upon the value of the GTF_CONTAINED flag.
15800 // Therefore this method is only valid after Lowering.
15801 // Also note that register allocation or other subsequent phases may cause
15802 // nodes to become contained (or not) and therefore this property may change.
15804 bool GenTree::isContained() const
15807 const bool isMarkedContained = ((gtFlags & GTF_CONTAINED) != 0);
15810 if (!canBeContained())
15812 assert(!isMarkedContained);
15815 // these actually produce a register (the flags reg, we just don't model it)
15816 // and are a separate instruction from the branch that consumes the result.
15817 // They can only produce a result if the child is a SIMD equality comparison.
15818 else if (OperKind() & GTK_RELOP)
15820 // We have to cast away const-ness since AsOp() method is non-const.
15821 GenTree* childNode = const_cast<GenTree*>(this)->AsOp()->gtOp1;
15822 assert((isMarkedContained == false) || childNode->IsSIMDEqualityOrInequality());
15825 // these either produce a result in register or set flags reg.
15826 else if (IsSIMDEqualityOrInequality())
15828 assert(!isMarkedContained);
15831 // if it's contained it can't be unused.
15832 if (isMarkedContained)
15834 assert(!IsUnusedValue());
15837 return isMarkedContained;
15840 // return true if node is contained and an indir
15841 bool GenTree::isContainedIndir() const
15843 return isIndir() && isContained();
15846 bool GenTree::isIndirAddrMode()
15848 return isIndir() && AsIndir()->Addr()->OperIsAddrMode() && AsIndir()->Addr()->isContained();
15851 bool GenTree::isIndir() const
15853 return OperGet() == GT_IND || OperGet() == GT_STOREIND;
15856 bool GenTreeIndir::HasBase()
15858 return Base() != nullptr;
15861 bool GenTreeIndir::HasIndex()
15863 return Index() != nullptr;
15866 GenTree* GenTreeIndir::Base()
15868 GenTree* addr = Addr();
15870 if (isIndirAddrMode())
15872 GenTree* result = addr->AsAddrMode()->Base();
15873 if (result != nullptr)
15875 result = result->gtEffectiveVal();
15881 return addr; // TODO: why do we return 'addr' here, but we return 'nullptr' in the equivalent Index() case?
15885 GenTree* GenTreeIndir::Index()
15887 if (isIndirAddrMode())
15889 GenTree* result = Addr()->AsAddrMode()->Index();
15890 if (result != nullptr)
15892 result = result->gtEffectiveVal();
15902 unsigned GenTreeIndir::Scale()
15906 return Addr()->AsAddrMode()->gtScale;
15914 ssize_t GenTreeIndir::Offset()
15916 if (isIndirAddrMode())
15918 return Addr()->AsAddrMode()->Offset();
15920 else if (Addr()->gtOper == GT_CLS_VAR_ADDR)
15922 return static_cast<ssize_t>(reinterpret_cast<intptr_t>(Addr()->gtClsVar.gtClsVarHnd));
15924 else if (Addr()->IsCnsIntOrI() && Addr()->isContained())
15926 return Addr()->AsIntConCommon()->IconValue();
15934 //------------------------------------------------------------------------
15935 // GenTreeIntConCommon::ImmedValNeedsReloc: does this immediate value needs recording a relocation with the VM?
15938 // comp - Compiler instance
15941 // True if this immediate value requires us to record a relocation for it; false otherwise.
15943 bool GenTreeIntConCommon::ImmedValNeedsReloc(Compiler* comp)
15945 return comp->opts.compReloc && (gtOper == GT_CNS_INT) && IsIconHandle();
15948 //------------------------------------------------------------------------
15949 // ImmedValCanBeFolded: can this immediate value be folded for op?
15952 // comp - Compiler instance
15953 // op - Tree operator
15956 // True if this immediate value can be folded for op; false otherwise.
15958 bool GenTreeIntConCommon::ImmedValCanBeFolded(Compiler* comp, genTreeOps op)
15960 // In general, immediate values that need relocations can't be folded.
15961 // There are cases where we do want to allow folding of handle comparisons
15962 // (e.g., typeof(T) == typeof(int)).
15963 return !ImmedValNeedsReloc(comp) || (op == GT_EQ) || (op == GT_NE);
15966 #ifdef _TARGET_AMD64_
15967 // Returns true if this absolute address fits within the base of an addr mode.
15968 // On Amd64 this effectively means, whether an absolute indirect address can
15969 // be encoded as 32-bit offset relative to IP or zero.
15970 bool GenTreeIntConCommon::FitsInAddrBase(Compiler* comp)
15973 // Early out if PC-rel encoding of absolute addr is disabled.
15974 if (!comp->opts.compEnablePCRelAddr)
15980 if (comp->opts.compReloc)
15982 // During Ngen JIT is always asked to generate relocatable code.
15983 // Hence JIT will try to encode only icon handles as pc-relative offsets.
15984 return IsIconHandle() && (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue()));
15988 // During Jitting, we are allowed to generate non-relocatable code.
15989 // On Amd64 we can encode an absolute indirect addr as an offset relative to zero or RIP.
15990 // An absolute indir addr that can fit within 32-bits can ben encoded as an offset relative
15991 // to zero. All other absolute indir addr could be attempted to be encoded as RIP relative
15992 // based on reloc hint provided by VM. RIP relative encoding is preferred over relative
15993 // to zero, because the former is one byte smaller than the latter. For this reason
15994 // we check for reloc hint first and then whether addr fits in 32-bits next.
15996 // VM starts off with an initial state to allow both data and code address to be encoded as
15997 // pc-relative offsets. Hence JIT will attempt to encode all absolute addresses as pc-relative
15998 // offsets. It is possible while jitting a method, an address could not be encoded as a
15999 // pc-relative offset. In that case VM will note the overflow and will trigger re-jitting
16000 // of the method with reloc hints turned off for all future methods. Second time around
16001 // jitting will succeed since JIT will not attempt to encode data addresses as pc-relative
16002 // offsets. Note that JIT will always attempt to relocate code addresses (.e.g call addr).
16003 // After an overflow, VM will assume any relocation recorded is for a code address and will
16004 // emit jump thunk if it cannot be encoded as pc-relative offset.
16005 return (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue())) || FitsInI32();
16009 // Returns true if this icon value is encoded as addr needs recording a relocation with VM
16010 bool GenTreeIntConCommon::AddrNeedsReloc(Compiler* comp)
16012 if (comp->opts.compReloc)
16014 // During Ngen JIT is always asked to generate relocatable code.
16015 // Hence JIT will try to encode only icon handles as pc-relative offsets.
16016 return IsIconHandle() && (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue()));
16020 return IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue());
16024 #elif defined(_TARGET_X86_)
16025 // Returns true if this absolute address fits within the base of an addr mode.
16026 // On x86 all addresses are 4-bytes and can be directly encoded in an addr mode.
16027 bool GenTreeIntConCommon::FitsInAddrBase(Compiler* comp)
16030 // Early out if PC-rel encoding of absolute addr is disabled.
16031 if (!comp->opts.compEnablePCRelAddr)
16037 return IsCnsIntOrI();
16040 // Returns true if this icon value is encoded as addr needs recording a relocation with VM
16041 bool GenTreeIntConCommon::AddrNeedsReloc(Compiler* comp)
16043 // If generating relocatable code, icons should be reported for recording relocatons.
16044 return comp->opts.compReloc && IsIconHandle();
16046 #endif //_TARGET_X86_
16048 bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pObj, GenTree** pStatic, FieldSeqNode** pFldSeq)
16050 FieldSeqNode* newFldSeq = nullptr;
16051 GenTree* baseAddr = nullptr;
16052 bool mustBeStatic = false;
16054 FieldSeqNode* statStructFldSeq = nullptr;
16055 if (TypeGet() == TYP_REF)
16057 // Recognize struct static field patterns...
16058 if (OperGet() == GT_IND)
16060 GenTree* addr = gtOp.gtOp1;
16061 GenTreeIntCon* icon = nullptr;
16062 if (addr->OperGet() == GT_CNS_INT)
16064 icon = addr->AsIntCon();
16066 else if (addr->OperGet() == GT_ADD)
16068 // op1 should never be a field sequence (or any other kind of handle)
16069 assert((addr->gtOp.gtOp1->gtOper != GT_CNS_INT) || !addr->gtOp.gtOp1->IsIconHandle());
16070 if (addr->gtOp.gtOp2->OperGet() == GT_CNS_INT)
16072 icon = addr->gtOp.gtOp2->AsIntCon();
16075 if (icon != nullptr && !icon->IsIconHandle(GTF_ICON_STR_HDL) // String handles are a source of TYP_REFs.
16076 && icon->gtFieldSeq != nullptr &&
16077 icon->gtFieldSeq->m_next == nullptr // A static field should be a singleton
16078 // TODO-Review: A pseudoField here indicates an issue - this requires investigation
16079 // See test case src\ddsuites\src\clr\x86\CoreMangLib\Dev\Globalization\CalendarRegressions.exe
16080 && !(FieldSeqStore::IsPseudoField(icon->gtFieldSeq->m_fieldHnd)) &&
16081 icon->gtFieldSeq != FieldSeqStore::NotAField()) // Ignore non-fields.
16083 statStructFldSeq = icon->gtFieldSeq;
16087 addr = addr->gtEffectiveVal();
16089 // Perhaps it's a direct indirection of a helper call or a cse with a zero offset annotation.
16090 if ((addr->OperGet() == GT_CALL) || (addr->OperGet() == GT_LCL_VAR))
16092 FieldSeqNode* zeroFieldSeq = nullptr;
16093 if (comp->GetZeroOffsetFieldMap()->Lookup(addr, &zeroFieldSeq))
16095 if (zeroFieldSeq->m_next == nullptr)
16097 statStructFldSeq = zeroFieldSeq;
16103 else if (OperGet() == GT_CLS_VAR)
16105 GenTreeClsVar* clsVar = AsClsVar();
16106 if (clsVar->gtFieldSeq != nullptr && clsVar->gtFieldSeq->m_next == nullptr)
16108 statStructFldSeq = clsVar->gtFieldSeq;
16111 else if (OperIsLocal())
16113 // If we have a GT_LCL_VAR, it can be result of a CSE substitution
16114 // If it is then the CSE assignment will have a ValueNum that
16115 // describes the RHS of the CSE assignment.
16117 // The CSE could be a pointer to a boxed struct
16119 GenTreeLclVarCommon* lclVar = AsLclVarCommon();
16120 ValueNum vn = gtVNPair.GetLiberal();
16121 if (vn != ValueNumStore::NoVN)
16123 // Is the ValueNum a MapSelect involving a SharedStatic helper?
16124 VNFuncApp funcApp1;
16125 if (comp->vnStore->GetVNFunc(vn, &funcApp1) && (funcApp1.m_func == VNF_MapSelect) &&
16126 (comp->vnStore->IsSharedStatic(funcApp1.m_args[1])))
16128 ValueNum mapVN = funcApp1.m_args[0];
16129 // Is this new 'mapVN' ValueNum, a MapSelect involving a handle?
16130 VNFuncApp funcApp2;
16131 if (comp->vnStore->GetVNFunc(mapVN, &funcApp2) && (funcApp2.m_func == VNF_MapSelect) &&
16132 (comp->vnStore->IsVNHandle(funcApp2.m_args[1])))
16134 ValueNum fldHndVN = funcApp2.m_args[1];
16135 // Is this new 'fldHndVN' VNhandle a FieldHandle?
16136 unsigned flags = comp->vnStore->GetHandleFlags(fldHndVN);
16137 if (flags == GTF_ICON_FIELD_HDL)
16139 CORINFO_FIELD_HANDLE fieldHnd =
16140 CORINFO_FIELD_HANDLE(comp->vnStore->ConstantValue<ssize_t>(fldHndVN));
16142 // Record this field sequence in 'statStructFldSeq' as it is likely to be a Boxed Struct
16144 statStructFldSeq = comp->GetFieldSeqStore()->CreateSingleton(fieldHnd);
16151 if (statStructFldSeq != nullptr)
16153 assert(statStructFldSeq->m_next == nullptr);
16154 // Is this a pointer to a boxed struct?
16155 if (comp->gtIsStaticFieldPtrToBoxedStruct(TYP_REF, statStructFldSeq->m_fieldHnd))
16157 *pFldSeq = comp->GetFieldSeqStore()->Append(statStructFldSeq, *pFldSeq);
16166 *pStatic = nullptr;
16169 else if (OperGet() == GT_ADD)
16171 // If one operator is a field sequence/handle, the other operator must not also be a field sequence/handle.
16172 if ((gtOp.gtOp1->OperGet() == GT_CNS_INT) && gtOp.gtOp1->IsIconHandle())
16174 assert((gtOp.gtOp2->gtOper != GT_CNS_INT) || !gtOp.gtOp2->IsIconHandle());
16175 newFldSeq = gtOp.gtOp1->AsIntCon()->gtFieldSeq;
16176 baseAddr = gtOp.gtOp2;
16178 else if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
16180 assert((gtOp.gtOp1->gtOper != GT_CNS_INT) || !gtOp.gtOp1->IsIconHandle());
16181 newFldSeq = gtOp.gtOp2->AsIntCon()->gtFieldSeq;
16182 baseAddr = gtOp.gtOp1;
16187 // Check if "this" has a zero-offset annotation.
16188 if (!comp->GetZeroOffsetFieldMap()->Lookup(this, &newFldSeq))
16190 // If not, this is not a field address.
16196 mustBeStatic = true;
16200 // If not we don't have a field seq, it's not a field address.
16201 if (newFldSeq == nullptr || newFldSeq == FieldSeqStore::NotAField())
16206 // Prepend this field to whatever we've already accumulated (outside-in).
16207 *pFldSeq = comp->GetFieldSeqStore()->Append(newFldSeq, *pFldSeq);
16209 // Is it a static or instance field?
16210 if (!FieldSeqStore::IsPseudoField(newFldSeq->m_fieldHnd) &&
16211 comp->info.compCompHnd->isFieldStatic(newFldSeq->m_fieldHnd))
16213 // It is a static field. We're done.
16215 *pStatic = baseAddr;
16218 else if ((baseAddr != nullptr) && !mustBeStatic)
16220 // It's an instance field...but it must be for a struct field, since we've not yet encountered
16221 // a "TYP_REF" address. Analyze the reset of the address.
16222 return baseAddr->gtEffectiveVal()->IsFieldAddr(comp, pObj, pStatic, pFldSeq);
16229 bool Compiler::gtIsStaticFieldPtrToBoxedStruct(var_types fieldNodeType, CORINFO_FIELD_HANDLE fldHnd)
16231 if (fieldNodeType != TYP_REF)
16235 noway_assert(fldHnd != nullptr);
16236 CorInfoType cit = info.compCompHnd->getFieldType(fldHnd);
16237 var_types fieldTyp = JITtype2varType(cit);
16238 return fieldTyp != TYP_REF;
16241 #ifdef FEATURE_SIMD
16242 //------------------------------------------------------------------------
16243 // gtGetSIMDZero: Get a zero value of the appropriate SIMD type.
16246 // var_types - The simdType
16247 // baseType - The base type we need
16248 // simdHandle - The handle for the SIMD type
16251 // A node generating the appropriate Zero, if we are able to discern it,
16252 // otherwise null (note that this shouldn't happen, but callers should
16253 // be tolerant of this case).
16255 GenTree* Compiler::gtGetSIMDZero(var_types simdType, var_types baseType, CORINFO_CLASS_HANDLE simdHandle)
16257 bool found = false;
16258 bool isHWSIMD = true;
16259 noway_assert(m_simdHandleCache != nullptr);
16261 // First, determine whether this is Vector<T>.
16262 if (simdType == getSIMDVectorType())
16267 found = (simdHandle == m_simdHandleCache->SIMDFloatHandle);
16270 found = (simdHandle == m_simdHandleCache->SIMDDoubleHandle);
16273 found = (simdHandle == m_simdHandleCache->SIMDIntHandle);
16276 found = (simdHandle == m_simdHandleCache->SIMDUShortHandle);
16279 found = (simdHandle == m_simdHandleCache->SIMDUByteHandle);
16282 found = (simdHandle == m_simdHandleCache->SIMDShortHandle);
16285 found = (simdHandle == m_simdHandleCache->SIMDByteHandle);
16288 found = (simdHandle == m_simdHandleCache->SIMDLongHandle);
16291 found = (simdHandle == m_simdHandleCache->SIMDUIntHandle);
16294 found = (simdHandle == m_simdHandleCache->SIMDULongHandle);
16307 // We must still have isHWSIMD set to true, and the only non-HW types left are the fixed types.
16314 if (simdHandle == m_simdHandleCache->SIMDVector2Handle)
16318 #if defined(_TARGET_ARM64_) && defined(FEATURE_HW_INTRINSICS)
16321 assert(simdHandle == m_simdHandleCache->Vector64FloatHandle);
16325 assert(simdHandle == m_simdHandleCache->Vector64IntHandle);
16328 assert(simdHandle == m_simdHandleCache->Vector64UShortHandle);
16331 assert(simdHandle == m_simdHandleCache->Vector64UByteHandle);
16334 assert(simdHandle == m_simdHandleCache->Vector64ShortHandle);
16337 assert(simdHandle == m_simdHandleCache->Vector64ByteHandle);
16340 assert(simdHandle == m_simdHandleCache->Vector64UIntHandle);
16342 #endif // defined(_TARGET_ARM64_) && defined(FEATURE_HW_INTRINSICS)
16349 assert((baseType == TYP_FLOAT) && (simdHandle == m_simdHandleCache->SIMDVector3Handle));
16357 if (simdHandle == m_simdHandleCache->SIMDVector4Handle)
16361 #if defined(FEATURE_HW_INTRINSICS)
16364 assert(simdHandle == m_simdHandleCache->Vector128FloatHandle);
16368 assert(simdHandle == m_simdHandleCache->Vector128DoubleHandle);
16371 assert(simdHandle == m_simdHandleCache->Vector128IntHandle);
16374 assert(simdHandle == m_simdHandleCache->Vector128UShortHandle);
16377 assert(simdHandle == m_simdHandleCache->Vector128UByteHandle);
16380 assert(simdHandle == m_simdHandleCache->Vector128ShortHandle);
16383 assert(simdHandle == m_simdHandleCache->Vector128ByteHandle);
16386 assert(simdHandle == m_simdHandleCache->Vector128LongHandle);
16389 assert(simdHandle == m_simdHandleCache->Vector128UIntHandle);
16392 assert(simdHandle == m_simdHandleCache->Vector128ULongHandle);
16394 #endif // defined(FEATURE_HW_INTRINSICS)
16401 #if defined(_TARGET_XARCH4_) && defined(FEATURE_HW_INTRINSICS)
16406 assert(simdHandle == m_simdHandleCache->Vector256FloatHandle);
16409 assert(simdHandle == m_simdHandleCache->Vector256DoubleHandle);
16412 assert(simdHandle == m_simdHandleCache->Vector256IntHandle);
16415 assert(simdHandle == m_simdHandleCache->Vector256UShortHandle);
16418 assert(simdHandle == m_simdHandleCache->Vector256UByteHandle);
16421 assert(simdHandle == m_simdHandleCache->Vector256ShortHandle);
16424 assert(simdHandle == m_simdHandleCache->Vector256ByteHandle);
16427 assert(simdHandle == m_simdHandleCache->Vector256LongHandle);
16430 assert(simdHandle == m_simdHandleCache->Vector256UIntHandle);
16433 assert(simdHandle == m_simdHandleCache->Vector256ULongHandle);
16439 #endif // _TARGET_XARCH_ && FEATURE_HW_INTRINSICS
16445 unsigned size = genTypeSize(simdType);
16448 #if defined(_TARGET_XARCH_) && defined(FEATURE_HW_INTRINSICS)
16452 return gtNewSimdHWIntrinsicNode(simdType, NI_Base_Vector128_Zero, baseType, size);
16454 return gtNewSimdHWIntrinsicNode(simdType, NI_Base_Vector256_Zero, baseType, size);
16458 #endif // _TARGET_XARCH_ && FEATURE_HW_INTRINSICS
16459 JITDUMP("Coudn't find the matching SIMD type for %s<%s> in gtGetSIMDZero\n", varTypeName(simdType),
16460 varTypeName(baseType));
16464 return gtNewSIMDVectorZero(simdType, baseType, size);
16468 #endif // FEATURE_SIMD
16470 CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleIfPresent(GenTree* tree)
16472 CORINFO_CLASS_HANDLE structHnd = NO_CLASS_HANDLE;
16473 tree = tree->gtEffectiveVal();
16474 if (varTypeIsStruct(tree->gtType))
16476 switch (tree->gtOper)
16481 structHnd = impGetRefAnyClass();
16484 structHnd = tree->gtObj.gtClass;
16487 structHnd = tree->gtCall.gtRetClsHnd;
16490 structHnd = tree->gtRetExpr.gtRetClsHnd;
16493 structHnd = tree->gtArgPlace.gtArgPlaceClsHnd;
16496 structHnd = tree->gtIndex.gtStructElemClass;
16498 case GT_INDEX_ADDR:
16499 structHnd = tree->AsIndexAddr()->gtStructElemClass;
16502 info.compCompHnd->getFieldType(tree->gtField.gtFldHnd, &structHnd);
16505 structHnd = gtGetStructHandleIfPresent(tree->gtGetOp1());
16508 #ifdef FEATURE_SIMD
16509 if (varTypeIsSIMD(tree))
16511 structHnd = gtGetStructHandleForSIMD(tree->gtType, TYP_FLOAT);
16516 structHnd = lvaTable[tree->AsLclVarCommon()->gtLclNum].lvVerTypeInfo.GetClassHandle();
16519 structHnd = gtGetStructHandleIfPresent(tree->gtOp.gtOp1);
16522 #ifdef FEATURE_SIMD
16523 if (varTypeIsSIMD(tree))
16525 structHnd = gtGetStructHandleForSIMD(tree->gtType, TYP_FLOAT);
16531 if (TryGetArrayInfo(tree->AsIndir(), &arrInfo))
16533 structHnd = EncodeElemType(arrInfo.m_elemType, arrInfo.m_elemStructType);
16537 #ifdef FEATURE_SIMD
16539 structHnd = gtGetStructHandleForSIMD(tree->gtType, tree->AsSIMD()->gtSIMDBaseType);
16541 #endif // FEATURE_SIMD
16542 #ifdef FEATURE_HW_INTRINSICS
16543 case GT_HWIntrinsic:
16544 structHnd = gtGetStructHandleForHWSIMD(tree->gtType, tree->AsHWIntrinsic()->gtSIMDBaseType);
16553 CORINFO_CLASS_HANDLE Compiler::gtGetStructHandle(GenTree* tree)
16555 CORINFO_CLASS_HANDLE structHnd = gtGetStructHandleIfPresent(tree);
16556 assert(structHnd != NO_CLASS_HANDLE);
16560 //------------------------------------------------------------------------
16561 // gtGetClassHandle: find class handle for a ref type
16564 // tree -- tree to find handle for
16565 // pIsExact [out] -- whether handle is exact type
16566 // pIsNonNull [out] -- whether tree value is known not to be null
16569 // nullptr if class handle is unknown,
16570 // otherwise the class handle.
16571 // *pIsExact set true if tree type is known to be exactly the handle type,
16572 // otherwise actual type may be a subtype.
16573 // *pIsNonNull set true if tree value is known not to be null,
16574 // otherwise a null value is possible.
16576 CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, bool* pIsNonNull)
16578 // Set default values for our out params.
16579 *pIsNonNull = false;
16581 CORINFO_CLASS_HANDLE objClass = nullptr;
16583 // Bail out if we're just importing and not generating code, since
16584 // the jit uses TYP_REF for CORINFO_TYPE_VAR locals and args, but
16585 // these may not be ref types.
16586 if (compIsForImportOnly())
16591 // Bail out if the tree is not a ref type.
16592 var_types treeType = tree->TypeGet();
16593 if (treeType != TYP_REF)
16598 // Tunnel through commas.
16599 GenTree* obj = tree->gtEffectiveVal(false);
16600 const genTreeOps objOp = obj->OperGet();
16606 // gtEffectiveVal above means we shouldn't see commas here.
16607 assert(!"unexpected GT_COMMA");
16613 // For locals, pick up type info from the local table.
16614 const unsigned objLcl = obj->AsLclVar()->GetLclNum();
16616 objClass = lvaTable[objLcl].lvClassHnd;
16617 *pIsExact = lvaTable[objLcl].lvClassIsExact;
16623 // For fields, get the type from the field handle.
16624 CORINFO_FIELD_HANDLE fieldHnd = obj->gtField.gtFldHnd;
16626 if (fieldHnd != nullptr)
16628 objClass = gtGetFieldClassHandle(fieldHnd, pIsExact, pIsNonNull);
16636 // If we see a RET_EXPR, recurse through to examine the
16637 // return value expression.
16638 GenTree* retExpr = tree->gtRetExpr.gtInlineCandidate;
16639 objClass = gtGetClassHandle(retExpr, pIsExact, pIsNonNull);
16645 GenTreeCall* call = tree->AsCall();
16646 if (call->IsInlineCandidate())
16648 // For inline candidates, we've already cached the return
16649 // type class handle in the inline info.
16650 InlineCandidateInfo* inlInfo = call->gtInlineCandidateInfo;
16651 assert(inlInfo != nullptr);
16653 // Grab it as our first cut at a return type.
16654 assert(inlInfo->methInfo.args.retType == CORINFO_TYPE_CLASS);
16655 objClass = inlInfo->methInfo.args.retTypeClass;
16657 // If the method is shared, the above may not capture
16658 // the most precise return type information (that is,
16659 // it may represent a shared return type and as such,
16660 // have instances of __Canon). See if we can use the
16661 // context to get at something more definite.
16663 // For now, we do this here on demand rather than when
16664 // processing the call, but we could/should apply
16665 // similar sharpening to the argument and local types
16667 const unsigned retClassFlags = info.compCompHnd->getClassAttribs(objClass);
16668 if (retClassFlags & CORINFO_FLG_SHAREDINST)
16670 CORINFO_CONTEXT_HANDLE context = inlInfo->exactContextHnd;
16672 if (context != nullptr)
16674 CORINFO_CLASS_HANDLE exactClass = nullptr;
16676 if (((size_t)context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
16678 exactClass = (CORINFO_CLASS_HANDLE)((size_t)context & ~CORINFO_CONTEXTFLAGS_MASK);
16682 CORINFO_METHOD_HANDLE exactMethod =
16683 (CORINFO_METHOD_HANDLE)((size_t)context & ~CORINFO_CONTEXTFLAGS_MASK);
16684 exactClass = info.compCompHnd->getMethodClass(exactMethod);
16687 // Grab the signature in this context.
16688 CORINFO_SIG_INFO sig;
16689 eeGetMethodSig(call->gtCallMethHnd, &sig, exactClass);
16690 assert(sig.retType == CORINFO_TYPE_CLASS);
16691 objClass = sig.retTypeClass;
16695 else if (call->gtCallType == CT_USER_FUNC)
16697 // For user calls, we can fetch the approximate return
16698 // type info from the method handle. Unfortunately
16699 // we've lost the exact context, so this is the best
16700 // we can do for now.
16701 CORINFO_METHOD_HANDLE method = call->gtCallMethHnd;
16702 CORINFO_CLASS_HANDLE exactClass = nullptr;
16703 CORINFO_SIG_INFO sig;
16704 eeGetMethodSig(method, &sig, exactClass);
16705 if (sig.retType == CORINFO_TYPE_VOID)
16707 // This is a constructor call.
16708 const unsigned methodFlags = info.compCompHnd->getMethodAttribs(method);
16709 assert((methodFlags & CORINFO_FLG_CONSTRUCTOR) != 0);
16710 objClass = info.compCompHnd->getMethodClass(method);
16712 *pIsNonNull = true;
16716 assert(sig.retType == CORINFO_TYPE_CLASS);
16717 objClass = sig.retTypeClass;
16720 else if (call->gtCallType == CT_HELPER)
16722 objClass = gtGetHelperCallClassHandle(call, pIsExact, pIsNonNull);
16730 GenTreeIntrinsic* intrinsic = obj->AsIntrinsic();
16732 if (intrinsic->gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType)
16734 CORINFO_CLASS_HANDLE runtimeType = info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE);
16735 assert(runtimeType != NO_CLASS_HANDLE);
16737 objClass = runtimeType;
16739 *pIsNonNull = true;
16747 // For literal strings, we know the class and that the
16748 // value is not null.
16749 objClass = impGetStringClass();
16751 *pIsNonNull = true;
16757 GenTreeIndir* indir = obj->AsIndir();
16759 if (indir->HasBase() && !indir->HasIndex())
16761 // indir(addr(lcl)) --> lcl
16763 // This comes up during constrained callvirt on ref types.
16765 GenTree* base = indir->Base();
16766 GenTreeLclVarCommon* lcl = base->IsLocalAddrExpr();
16768 if ((lcl != nullptr) && (base->OperGet() != GT_ADD))
16770 const unsigned objLcl = lcl->GetLclNum();
16771 objClass = lvaTable[objLcl].lvClassHnd;
16772 *pIsExact = lvaTable[objLcl].lvClassIsExact;
16774 else if (base->OperGet() == GT_ARR_ELEM)
16776 // indir(arr_elem(...)) -> array element type
16778 GenTree* array = base->AsArrElem()->gtArrObj;
16780 objClass = gtGetArrayElementClassHandle(array);
16782 *pIsNonNull = false;
16784 else if (base->OperGet() == GT_ADD)
16786 // This could be a static field access.
16788 // See if op1 is a static field base helper call
16789 // and if so, op2 will have the field info.
16790 GenTree* op1 = base->gtOp.gtOp1;
16791 GenTree* op2 = base->gtOp.gtOp2;
16793 const bool op1IsStaticFieldBase = gtIsStaticGCBaseHelperCall(op1);
16795 if (op1IsStaticFieldBase && (op2->OperGet() == GT_CNS_INT))
16797 FieldSeqNode* fieldSeq = op2->AsIntCon()->gtFieldSeq;
16799 if (fieldSeq != nullptr)
16801 while (fieldSeq->m_next != nullptr)
16803 fieldSeq = fieldSeq->m_next;
16806 assert(!fieldSeq->IsPseudoField());
16808 // No benefit to calling gtGetFieldClassHandle here, as
16809 // the exact field being accessed can vary.
16810 CORINFO_FIELD_HANDLE fieldHnd = fieldSeq->m_fieldHnd;
16811 CORINFO_CLASS_HANDLE fieldClass = nullptr;
16812 CorInfoType fieldCorType = info.compCompHnd->getFieldType(fieldHnd, &fieldClass);
16814 assert(fieldCorType == CORINFO_TYPE_CLASS);
16815 objClass = fieldClass;
16826 // Box should just wrap a local var reference which has
16827 // the type we're looking for. Also box only represents a
16828 // non-nullable value type so result cannot be null.
16829 GenTreeBox* box = obj->AsBox();
16830 GenTree* boxTemp = box->BoxOp();
16831 assert(boxTemp->IsLocal());
16832 const unsigned boxTempLcl = boxTemp->AsLclVar()->GetLclNum();
16833 objClass = lvaTable[boxTempLcl].lvClassHnd;
16834 *pIsExact = lvaTable[boxTempLcl].lvClassIsExact;
16835 *pIsNonNull = true;
16841 GenTree* array = obj->AsIndex()->Arr();
16843 objClass = gtGetArrayElementClassHandle(array);
16845 *pIsNonNull = false;
16858 //------------------------------------------------------------------------
16859 // gtGetHelperCallClassHandle: find class handle for return value of a
16863 // call - helper call to examine
16864 // pIsExact - [OUT] true if type is known exactly
16865 // pIsNonNull - [OUT] true if return value is not null
16868 // nullptr if helper call result is not a ref class, or the class handle
16869 // is unknown, otherwise the class handle.
16871 CORINFO_CLASS_HANDLE Compiler::gtGetHelperCallClassHandle(GenTreeCall* call, bool* pIsExact, bool* pIsNonNull)
16873 assert(call->gtCallType == CT_HELPER);
16875 *pIsNonNull = false;
16877 CORINFO_CLASS_HANDLE objClass = nullptr;
16878 const CorInfoHelpFunc helper = eeGetHelperNum(call->gtCallMethHnd);
16882 case CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE:
16883 case CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL:
16885 // Note for some runtimes these helpers return exact types.
16887 // But in those cases the types are also sealed, so there's no
16888 // need to claim exactness here.
16889 const bool helperResultNonNull = (helper == CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE);
16890 CORINFO_CLASS_HANDLE runtimeType = info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE);
16892 assert(runtimeType != NO_CLASS_HANDLE);
16894 objClass = runtimeType;
16895 *pIsNonNull = helperResultNonNull;
16899 case CORINFO_HELP_CHKCASTCLASS:
16900 case CORINFO_HELP_CHKCASTANY:
16901 case CORINFO_HELP_CHKCASTARRAY:
16902 case CORINFO_HELP_CHKCASTINTERFACE:
16903 case CORINFO_HELP_CHKCASTCLASS_SPECIAL:
16904 case CORINFO_HELP_ISINSTANCEOFINTERFACE:
16905 case CORINFO_HELP_ISINSTANCEOFARRAY:
16906 case CORINFO_HELP_ISINSTANCEOFCLASS:
16907 case CORINFO_HELP_ISINSTANCEOFANY:
16909 // Fetch the class handle from the helper call arglist
16910 GenTreeArgList* args = call->gtCallArgs;
16911 GenTree* typeArg = args->Current();
16912 CORINFO_CLASS_HANDLE castHnd = gtGetHelperArgClassHandle(typeArg);
16914 // We generally assume the type being cast to is the best type
16915 // for the result, unless it is an interface type.
16917 // TODO-CQ: when we have default interface methods then
16918 // this might not be the best assumption. We could also
16919 // explore calling something like mergeClasses to identify
16920 // the more specific class. A similar issue arises when
16921 // typing the temp in impCastClassOrIsInstToTree, when we
16922 // expand the cast inline.
16923 if (castHnd != nullptr)
16925 DWORD attrs = info.compCompHnd->getClassAttribs(castHnd);
16927 if ((attrs & CORINFO_FLG_INTERFACE) != 0)
16933 // If we don't have a good estimate for the type we can use the
16934 // type from the value being cast instead.
16935 if (castHnd == nullptr)
16937 GenTree* valueArg = args->Rest()->Current();
16938 castHnd = gtGetClassHandle(valueArg, pIsExact, pIsNonNull);
16941 // We don't know at jit time if the cast will succeed or fail, but if it
16942 // fails at runtime then an exception is thrown for cast helpers, or the
16943 // result is set null for instance helpers.
16945 // So it safe to claim the result has the cast type.
16946 // Note we don't know for sure that it is exactly this type.
16947 if (castHnd != nullptr)
16949 objClass = castHnd;
16962 //------------------------------------------------------------------------
16963 // gtGetArrayElementClassHandle: find class handle for elements of an array
16967 // array -- array to find handle for
16970 // nullptr if element class handle is unknown, otherwise the class handle.
16972 CORINFO_CLASS_HANDLE Compiler::gtGetArrayElementClassHandle(GenTree* array)
16974 bool isArrayExact = false;
16975 bool isArrayNonNull = false;
16976 CORINFO_CLASS_HANDLE arrayClassHnd = gtGetClassHandle(array, &isArrayExact, &isArrayNonNull);
16978 if (arrayClassHnd != nullptr)
16980 // We know the class of the reference
16981 DWORD attribs = info.compCompHnd->getClassAttribs(arrayClassHnd);
16983 if ((attribs & CORINFO_FLG_ARRAY) != 0)
16985 // We know for sure it is an array
16986 CORINFO_CLASS_HANDLE elemClassHnd = nullptr;
16987 CorInfoType arrayElemType = info.compCompHnd->getChildType(arrayClassHnd, &elemClassHnd);
16989 if (arrayElemType == CORINFO_TYPE_CLASS)
16991 // We know it is an array of ref types
16992 return elemClassHnd;
17000 //------------------------------------------------------------------------
17001 // gtGetFieldClassHandle: find class handle for a field
17004 // fieldHnd - field handle for field in question
17005 // pIsExact - [OUT] true if type is known exactly
17006 // pIsNonNull - [OUT] true if field value is not null
17009 // nullptr if helper call result is not a ref class, or the class handle
17010 // is unknown, otherwise the class handle.
17012 // May examine runtime state of static field instances.
17014 CORINFO_CLASS_HANDLE Compiler::gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldHnd, bool* pIsExact, bool* pIsNonNull)
17016 CORINFO_CLASS_HANDLE fieldClass = nullptr;
17017 CorInfoType fieldCorType = info.compCompHnd->getFieldType(fieldHnd, &fieldClass);
17019 if (fieldCorType == CORINFO_TYPE_CLASS)
17021 // Optionally, look at the actual type of the field's value
17022 bool queryForCurrentClass = true;
17023 INDEBUG(queryForCurrentClass = (JitConfig.JitQueryCurrentStaticFieldClass() > 0););
17025 if (queryForCurrentClass)
17029 const char* fieldClassName = nullptr;
17030 const char* fieldName = eeGetFieldName(fieldHnd, &fieldClassName);
17031 JITDUMP("Querying runtime about current class of field %s.%s (declared as %s)\n", fieldClassName, fieldName,
17032 eeGetClassName(fieldClass));
17035 // Is this a fully initialized init-only static field?
17037 // Note we're not asking for speculative results here, yet.
17038 CORINFO_CLASS_HANDLE currentClass = info.compCompHnd->getStaticFieldCurrentClass(fieldHnd);
17040 if (currentClass != NO_CLASS_HANDLE)
17042 // Yes! We know the class exactly and can rely on this to always be true.
17043 fieldClass = currentClass;
17045 *pIsNonNull = true;
17046 JITDUMP("Runtime reports field is init-only and initialized and has class %s\n",
17047 eeGetClassName(fieldClass));
17051 JITDUMP("Field's current class not available\n");
17059 //------------------------------------------------------------------------
17060 // gtIsGCStaticBaseHelperCall: true if tree is fetching the gc static base
17061 // for a subsequent static field access
17064 // tree - tree to consider
17067 // true if the tree is a suitable helper call
17070 // Excludes R2R helpers as they specify the target field in a way
17071 // that is opaque to the jit.
17073 bool Compiler::gtIsStaticGCBaseHelperCall(GenTree* tree)
17075 if (tree->OperGet() != GT_CALL)
17080 GenTreeCall* call = tree->AsCall();
17082 if (call->gtCallType != CT_HELPER)
17087 const CorInfoHelpFunc helper = eeGetHelperNum(call->gtCallMethHnd);
17091 // We are looking for a REF type so only need to check for the GC base helpers
17092 case CORINFO_HELP_GETGENERICS_GCSTATIC_BASE:
17093 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE:
17094 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR:
17095 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS:
17096 case CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE:
17097 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE:
17098 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR:
17099 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS:
17108 void GenTree::ParseArrayAddress(
17109 Compiler* comp, ArrayInfo* arrayInfo, GenTree** pArr, ValueNum* pInxVN, FieldSeqNode** pFldSeq)
17112 ValueNum inxVN = ValueNumStore::NoVN;
17113 target_ssize_t offset = 0;
17114 FieldSeqNode* fldSeq = nullptr;
17116 ParseArrayAddressWork(comp, 1, pArr, &inxVN, &offset, &fldSeq);
17118 // If we didn't find an array reference (perhaps it is the constant null?) we will give up.
17119 if (*pArr == nullptr)
17124 // OK, new we have to figure out if any part of the "offset" is a constant contribution to the index.
17125 // First, sum the offsets of any fields in fldSeq.
17126 unsigned fieldOffsets = 0;
17127 FieldSeqNode* fldSeqIter = fldSeq;
17128 // Also, find the first non-pseudo field...
17129 assert(*pFldSeq == nullptr);
17130 while (fldSeqIter != nullptr)
17132 if (fldSeqIter == FieldSeqStore::NotAField())
17134 // TODO-Review: A NotAField here indicates a failure to properly maintain the field sequence
17135 // See test case self_host_tests_x86\jit\regression\CLR-x86-JIT\v1-m12-beta2\ b70992\ b70992.exe
17136 // Safest thing to do here is to drop back to MinOpts
17137 CLANG_FORMAT_COMMENT_ANCHOR;
17140 if (comp->opts.optRepeat)
17142 // We don't guarantee preserving these annotations through the entire optimizer, so
17143 // just conservatively return null if under optRepeat.
17148 noway_assert(!"fldSeqIter is NotAField() in ParseArrayAddress");
17151 if (!FieldSeqStore::IsPseudoField(fldSeqIter->m_fieldHnd))
17153 if (*pFldSeq == nullptr)
17155 *pFldSeq = fldSeqIter;
17157 CORINFO_CLASS_HANDLE fldCls = nullptr;
17158 noway_assert(fldSeqIter->m_fieldHnd != nullptr);
17159 CorInfoType cit = comp->info.compCompHnd->getFieldType(fldSeqIter->m_fieldHnd, &fldCls);
17160 fieldOffsets += comp->compGetTypeSize(cit, fldCls);
17162 fldSeqIter = fldSeqIter->m_next;
17165 // Is there some portion of the "offset" beyond the first-elem offset and the struct field suffix we just computed?
17166 if (!FitsIn<target_ssize_t>(fieldOffsets + arrayInfo->m_elemOffset) ||
17167 !FitsIn<target_ssize_t>(arrayInfo->m_elemSize))
17169 // This seems unlikely, but no harm in being safe...
17170 *pInxVN = comp->GetValueNumStore()->VNForExpr(nullptr, TYP_INT);
17174 target_ssize_t offsetAccountedFor = static_cast<target_ssize_t>(fieldOffsets + arrayInfo->m_elemOffset);
17175 target_ssize_t elemSize = static_cast<target_ssize_t>(arrayInfo->m_elemSize);
17177 target_ssize_t constIndOffset = offset - offsetAccountedFor;
17178 // This should be divisible by the element size...
17179 assert((constIndOffset % elemSize) == 0);
17180 target_ssize_t constInd = constIndOffset / elemSize;
17182 ValueNumStore* vnStore = comp->GetValueNumStore();
17184 if (inxVN == ValueNumStore::NoVN)
17186 // Must be a constant index.
17187 *pInxVN = vnStore->VNForPtrSizeIntCon(constInd);
17192 // Perform ((inxVN / elemSizeVN) + vnForConstInd)
17195 // The value associated with the index value number (inxVN) is the offset into the array,
17196 // which has been scaled by element size. We need to recover the array index from that offset
17197 if (vnStore->IsVNConstant(inxVN))
17199 target_ssize_t index = vnStore->CoercedConstantValue<target_ssize_t>(inxVN);
17200 noway_assert(elemSize > 0 && ((index % elemSize) == 0));
17201 *pInxVN = vnStore->VNForPtrSizeIntCon((index / elemSize) + constInd);
17205 bool canFoldDiv = false;
17207 // If the index VN is a MUL by elemSize, see if we can eliminate it instead of adding
17208 // the division by elemSize.
17210 if (vnStore->GetVNFunc(inxVN, &funcApp) && funcApp.m_func == (VNFunc)GT_MUL)
17212 ValueNum vnForElemSize = vnStore->VNForLongCon(elemSize);
17214 // One of the multiply operand is elemSize, so the resulting
17215 // index VN should simply be the other operand.
17216 if (funcApp.m_args[1] == vnForElemSize)
17218 *pInxVN = funcApp.m_args[0];
17221 else if (funcApp.m_args[0] == vnForElemSize)
17223 *pInxVN = funcApp.m_args[1];
17228 // Perform ((inxVN / elemSizeVN) + vnForConstInd)
17231 ValueNum vnForElemSize = vnStore->VNForPtrSizeIntCon(elemSize);
17232 ValueNum vnForScaledInx =
17233 vnStore->VNForFunc(TYP_I_IMPL, GetVNFuncForOper(GT_DIV, VOK_Default), inxVN, vnForElemSize);
17234 *pInxVN = vnForScaledInx;
17239 ValueNum vnForConstInd = comp->GetValueNumStore()->VNForPtrSizeIntCon(constInd);
17240 VNFunc vnFunc = GetVNFuncForOper(GT_ADD, VOK_Default);
17242 *pInxVN = comp->GetValueNumStore()->VNForFunc(TYP_I_IMPL, vnFunc, *pInxVN, vnForConstInd);
17248 void GenTree::ParseArrayAddressWork(Compiler* comp,
17249 target_ssize_t inputMul,
17252 target_ssize_t* pOffset,
17253 FieldSeqNode** pFldSeq)
17255 if (TypeGet() == TYP_REF)
17257 // This must be the array pointer.
17259 assert(inputMul == 1); // Can't multiply the array pointer by anything.
17266 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, gtIntCon.gtFieldSeq);
17267 assert(!gtIntCon.ImmedValNeedsReloc(comp));
17268 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntCon::gtIconVal had target_ssize_t
17270 *pOffset += (inputMul * (target_ssize_t)(gtIntCon.gtIconVal));
17275 gtOp.gtOp1->ParseArrayAddressWork(comp, inputMul, pArr, pInxVN, pOffset, pFldSeq);
17276 if (OperGet() == GT_SUB)
17278 inputMul = -inputMul;
17280 gtOp.gtOp2->ParseArrayAddressWork(comp, inputMul, pArr, pInxVN, pOffset, pFldSeq);
17285 // If one op is a constant, continue parsing down.
17286 target_ssize_t subMul = 0;
17287 GenTree* nonConst = nullptr;
17288 if (gtOp.gtOp1->IsCnsIntOrI())
17290 // If the other arg is an int constant, and is a "not-a-field", choose
17291 // that as the multiplier, thus preserving constant index offsets...
17292 if (gtOp.gtOp2->OperGet() == GT_CNS_INT &&
17293 gtOp.gtOp2->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField())
17295 assert(!gtOp.gtOp2->gtIntCon.ImmedValNeedsReloc(comp));
17296 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntConCommon::gtIconVal had
17297 // target_ssize_t type.
17298 subMul = (target_ssize_t)gtOp.gtOp2->gtIntConCommon.IconValue();
17299 nonConst = gtOp.gtOp1;
17303 assert(!gtOp.gtOp1->gtIntCon.ImmedValNeedsReloc(comp));
17304 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntConCommon::gtIconVal had
17305 // target_ssize_t type.
17306 subMul = (target_ssize_t)gtOp.gtOp1->gtIntConCommon.IconValue();
17307 nonConst = gtOp.gtOp2;
17310 else if (gtOp.gtOp2->IsCnsIntOrI())
17312 assert(!gtOp.gtOp2->gtIntCon.ImmedValNeedsReloc(comp));
17313 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntConCommon::gtIconVal had
17314 // target_ssize_t type.
17315 subMul = (target_ssize_t)gtOp.gtOp2->gtIntConCommon.IconValue();
17316 nonConst = gtOp.gtOp1;
17318 if (nonConst != nullptr)
17320 nonConst->ParseArrayAddressWork(comp, inputMul * subMul, pArr, pInxVN, pOffset, pFldSeq);
17323 // Otherwise, exit the switch, treat as a contribution to the index.
17328 // If one op is a constant, continue parsing down.
17329 if (gtOp.gtOp2->IsCnsIntOrI())
17331 assert(!gtOp.gtOp2->gtIntCon.ImmedValNeedsReloc(comp));
17332 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntCon::gtIconVal had target_ssize_t
17334 target_ssize_t subMul = target_ssize_t{1} << (target_ssize_t)gtOp.gtOp2->gtIntConCommon.IconValue();
17335 gtOp.gtOp1->ParseArrayAddressWork(comp, inputMul * subMul, pArr, pInxVN, pOffset, pFldSeq);
17338 // Otherwise, exit the switch, treat as a contribution to the index.
17342 // We don't care about exceptions for this purpose.
17343 if ((gtOp.gtOp1->OperGet() == GT_ARR_BOUNDS_CHECK) || gtOp.gtOp1->IsNothingNode())
17345 gtOp.gtOp2->ParseArrayAddressWork(comp, inputMul, pArr, pInxVN, pOffset, pFldSeq);
17353 // If we didn't return above, must be a contribution to the non-constant part of the index VN.
17354 ValueNum vn = comp->GetValueNumStore()->VNLiberalNormalValue(gtVNPair);
17357 ValueNum mulVN = comp->GetValueNumStore()->VNForLongCon(inputMul);
17358 vn = comp->GetValueNumStore()->VNForFunc(TypeGet(), GetVNFuncForOper(GT_MUL, VOK_Default), mulVN, vn);
17360 if (*pInxVN == ValueNumStore::NoVN)
17367 comp->GetValueNumStore()->VNForFunc(TypeGet(), GetVNFuncForOper(GT_ADD, VOK_Default), *pInxVN, vn);
17372 bool GenTree::ParseArrayElemForm(Compiler* comp, ArrayInfo* arrayInfo, FieldSeqNode** pFldSeq)
17376 if (gtFlags & GTF_IND_ARR_INDEX)
17378 bool b = comp->GetArrayInfoMap()->Lookup(this, arrayInfo);
17384 GenTree* addr = AsIndir()->Addr();
17385 return addr->ParseArrayElemAddrForm(comp, arrayInfo, pFldSeq);
17393 bool GenTree::ParseArrayElemAddrForm(Compiler* comp, ArrayInfo* arrayInfo, FieldSeqNode** pFldSeq)
17399 GenTree* arrAddr = nullptr;
17400 GenTree* offset = nullptr;
17401 if (gtOp.gtOp1->TypeGet() == TYP_BYREF)
17403 arrAddr = gtOp.gtOp1;
17404 offset = gtOp.gtOp2;
17406 else if (gtOp.gtOp2->TypeGet() == TYP_BYREF)
17408 arrAddr = gtOp.gtOp2;
17409 offset = gtOp.gtOp1;
17415 if (!offset->ParseOffsetForm(comp, pFldSeq))
17419 return arrAddr->ParseArrayElemAddrForm(comp, arrayInfo, pFldSeq);
17424 GenTree* addrArg = gtOp.gtOp1;
17425 if (addrArg->OperGet() != GT_IND)
17431 // The "Addr" node might be annotated with a zero-offset field sequence.
17432 FieldSeqNode* zeroOffsetFldSeq = nullptr;
17433 if (comp->GetZeroOffsetFieldMap()->Lookup(this, &zeroOffsetFldSeq))
17435 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, zeroOffsetFldSeq);
17437 return addrArg->ParseArrayElemForm(comp, arrayInfo, pFldSeq);
17446 bool GenTree::ParseOffsetForm(Compiler* comp, FieldSeqNode** pFldSeq)
17452 GenTreeIntCon* icon = AsIntCon();
17453 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, icon->gtFieldSeq);
17458 if (!gtOp.gtOp1->ParseOffsetForm(comp, pFldSeq))
17462 return gtOp.gtOp2->ParseOffsetForm(comp, pFldSeq);
17469 void GenTree::LabelIndex(Compiler* comp, bool isConst)
17474 // If we got here, this is a contribution to the constant part of the index.
17477 gtIntCon.gtFieldSeq =
17478 comp->GetFieldSeqStore()->CreateSingleton(FieldSeqStore::ConstantIndexPseudoField);
17483 gtFlags |= GTF_VAR_ARR_INDEX;
17488 gtOp.gtOp1->LabelIndex(comp, isConst);
17489 gtOp.gtOp2->LabelIndex(comp, isConst);
17493 gtOp.gtOp1->LabelIndex(comp, isConst);
17496 case GT_ARR_LENGTH:
17497 gtFlags |= GTF_ARRLEN_ARR_IDX;
17501 // For all other operators, peel off one constant; and then label the other if it's also a constant.
17502 if (OperIsArithmetic() || OperIsCompare())
17504 if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
17506 gtOp.gtOp1->LabelIndex(comp, isConst);
17509 else if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
17511 gtOp.gtOp2->LabelIndex(comp, isConst);
17514 // Otherwise continue downward on both, labeling vars.
17515 gtOp.gtOp1->LabelIndex(comp, false);
17516 gtOp.gtOp2->LabelIndex(comp, false);
17522 // Note that the value of the below field doesn't matter; it exists only to provide a distinguished address.
17525 FieldSeqNode FieldSeqStore::s_notAField(nullptr, nullptr);
17527 // FieldSeqStore methods.
17528 FieldSeqStore::FieldSeqStore(CompAllocator alloc) : m_alloc(alloc), m_canonMap(new (alloc) FieldSeqNodeCanonMap(alloc))
17532 FieldSeqNode* FieldSeqStore::CreateSingleton(CORINFO_FIELD_HANDLE fieldHnd)
17534 FieldSeqNode fsn(fieldHnd, nullptr);
17535 FieldSeqNode* res = nullptr;
17536 if (m_canonMap->Lookup(fsn, &res))
17542 res = m_alloc.allocate<FieldSeqNode>(1);
17544 m_canonMap->Set(fsn, res);
17549 FieldSeqNode* FieldSeqStore::Append(FieldSeqNode* a, FieldSeqNode* b)
17555 else if (a == NotAField())
17557 return NotAField();
17559 else if (b == nullptr)
17563 else if (b == NotAField())
17565 return NotAField();
17566 // Extremely special case for ConstantIndex pseudo-fields -- appending consecutive such
17567 // together collapse to one.
17569 else if (a->m_next == nullptr && a->m_fieldHnd == ConstantIndexPseudoField &&
17570 b->m_fieldHnd == ConstantIndexPseudoField)
17576 FieldSeqNode* tmp = Append(a->m_next, b);
17577 FieldSeqNode fsn(a->m_fieldHnd, tmp);
17578 FieldSeqNode* res = nullptr;
17579 if (m_canonMap->Lookup(fsn, &res))
17585 res = m_alloc.allocate<FieldSeqNode>(1);
17587 m_canonMap->Set(fsn, res);
17594 int FieldSeqStore::FirstElemPseudoFieldStruct;
17595 int FieldSeqStore::ConstantIndexPseudoFieldStruct;
17597 CORINFO_FIELD_HANDLE FieldSeqStore::FirstElemPseudoField =
17598 (CORINFO_FIELD_HANDLE)&FieldSeqStore::FirstElemPseudoFieldStruct;
17599 CORINFO_FIELD_HANDLE FieldSeqStore::ConstantIndexPseudoField =
17600 (CORINFO_FIELD_HANDLE)&FieldSeqStore::ConstantIndexPseudoFieldStruct;
17602 bool FieldSeqNode::IsFirstElemFieldSeq()
17604 // this must be non-null per ISO C++
17605 return m_fieldHnd == FieldSeqStore::FirstElemPseudoField;
17608 bool FieldSeqNode::IsConstantIndexFieldSeq()
17610 // this must be non-null per ISO C++
17611 return m_fieldHnd == FieldSeqStore::ConstantIndexPseudoField;
17614 bool FieldSeqNode::IsPseudoField()
17616 if (this == nullptr)
17620 return m_fieldHnd == FieldSeqStore::FirstElemPseudoField || m_fieldHnd == FieldSeqStore::ConstantIndexPseudoField;
17623 #ifdef FEATURE_SIMD
17624 GenTreeSIMD* Compiler::gtNewSIMDNode(
17625 var_types type, GenTree* op1, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size)
17627 assert(op1 != nullptr);
17628 SetOpLclRelatedToSIMDIntrinsic(op1);
17630 return new (this, GT_SIMD) GenTreeSIMD(type, op1, simdIntrinsicID, baseType, size);
17633 GenTreeSIMD* Compiler::gtNewSIMDNode(
17634 var_types type, GenTree* op1, GenTree* op2, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size)
17636 assert(op1 != nullptr);
17637 SetOpLclRelatedToSIMDIntrinsic(op1);
17638 SetOpLclRelatedToSIMDIntrinsic(op2);
17640 return new (this, GT_SIMD) GenTreeSIMD(type, op1, op2, simdIntrinsicID, baseType, size);
17643 //-------------------------------------------------------------------
17644 // SetOpLclRelatedToSIMDIntrinsic: Determine if the tree has a local var that needs to be set
17645 // as used by a SIMD intrinsic, and if so, set that local var appropriately.
17648 // op - The tree, to be an operand of a new GT_SIMD node, to check.
17650 void Compiler::SetOpLclRelatedToSIMDIntrinsic(GenTree* op)
17654 if (op->OperIsLocal())
17656 setLclRelatedToSIMDIntrinsic(op);
17658 else if ((op->OperGet() == GT_OBJ) && (op->gtOp.gtOp1->OperGet() == GT_ADDR) &&
17659 op->gtOp.gtOp1->gtOp.gtOp1->OperIsLocal())
17661 setLclRelatedToSIMDIntrinsic(op->gtOp.gtOp1->gtOp.gtOp1);
17666 bool GenTree::isCommutativeSIMDIntrinsic()
17668 assert(gtOper == GT_SIMD);
17669 switch (AsSIMD()->gtSIMDIntrinsicID)
17671 case SIMDIntrinsicAdd:
17672 case SIMDIntrinsicBitwiseAnd:
17673 case SIMDIntrinsicBitwiseOr:
17674 case SIMDIntrinsicBitwiseXor:
17675 case SIMDIntrinsicEqual:
17676 case SIMDIntrinsicMax:
17677 case SIMDIntrinsicMin:
17678 case SIMDIntrinsicMul:
17679 case SIMDIntrinsicOpEquality:
17680 case SIMDIntrinsicOpInEquality:
17686 #endif // FEATURE_SIMD
17688 #ifdef FEATURE_HW_INTRINSICS
17689 bool GenTree::isCommutativeHWIntrinsic() const
17691 assert(gtOper == GT_HWIntrinsic);
17693 #ifdef _TARGET_XARCH_
17694 return HWIntrinsicInfo::IsCommutative(AsHWIntrinsic()->gtHWIntrinsicId);
17697 #endif // _TARGET_XARCH_
17700 bool GenTree::isContainableHWIntrinsic() const
17702 assert(gtOper == GT_HWIntrinsic);
17704 #ifdef _TARGET_XARCH_
17705 switch (AsHWIntrinsic()->gtHWIntrinsicId)
17707 case NI_SSE_LoadAlignedVector128:
17708 case NI_SSE_LoadScalarVector128:
17709 case NI_SSE_LoadVector128:
17710 case NI_SSE2_LoadAlignedVector128:
17711 case NI_SSE2_LoadScalarVector128:
17712 case NI_SSE2_LoadVector128:
17713 case NI_AVX_LoadAlignedVector256:
17714 case NI_AVX_LoadVector256:
17726 #endif // _TARGET_XARCH_
17729 bool GenTree::isRMWHWIntrinsic(Compiler* comp)
17731 assert(gtOper == GT_HWIntrinsic);
17732 assert(comp != nullptr);
17734 #ifdef _TARGET_XARCH_
17735 if (!comp->canUseVexEncoding())
17737 return HWIntrinsicInfo::HasRMWSemantics(AsHWIntrinsic()->gtHWIntrinsicId);
17740 switch (AsHWIntrinsic()->gtHWIntrinsicId)
17742 // TODO-XArch-Cleanup: Move this switch block to be table driven.
17744 case NI_SSE42_Crc32:
17745 case NI_SSE42_X64_Crc32:
17746 case NI_FMA_MultiplyAdd:
17747 case NI_FMA_MultiplyAddNegated:
17748 case NI_FMA_MultiplyAddNegatedScalar:
17749 case NI_FMA_MultiplyAddScalar:
17750 case NI_FMA_MultiplyAddSubtract:
17751 case NI_FMA_MultiplySubtract:
17752 case NI_FMA_MultiplySubtractAdd:
17753 case NI_FMA_MultiplySubtractNegated:
17754 case NI_FMA_MultiplySubtractNegatedScalar:
17755 case NI_FMA_MultiplySubtractScalar:
17767 #endif // _TARGET_XARCH_
17770 GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type,
17771 NamedIntrinsic hwIntrinsicID,
17772 var_types baseType,
17775 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, hwIntrinsicID, baseType, size);
17778 GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(
17779 var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned simdSize)
17781 SetOpLclRelatedToSIMDIntrinsic(op1);
17783 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, hwIntrinsicID, baseType, simdSize);
17786 GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(
17787 var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned simdSize)
17789 SetOpLclRelatedToSIMDIntrinsic(op1);
17790 SetOpLclRelatedToSIMDIntrinsic(op2);
17792 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, op2, hwIntrinsicID, baseType, simdSize);
17795 GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type,
17799 NamedIntrinsic hwIntrinsicID,
17800 var_types baseType,
17803 SetOpLclRelatedToSIMDIntrinsic(op1);
17804 SetOpLclRelatedToSIMDIntrinsic(op2);
17805 SetOpLclRelatedToSIMDIntrinsic(op3);
17807 return new (this, GT_HWIntrinsic)
17808 GenTreeHWIntrinsic(type, gtNewArgList(op1, op2, op3), hwIntrinsicID, baseType, size);
17811 GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type,
17816 NamedIntrinsic hwIntrinsicID,
17817 var_types baseType,
17820 SetOpLclRelatedToSIMDIntrinsic(op1);
17821 SetOpLclRelatedToSIMDIntrinsic(op2);
17822 SetOpLclRelatedToSIMDIntrinsic(op3);
17823 SetOpLclRelatedToSIMDIntrinsic(op4);
17825 return new (this, GT_HWIntrinsic)
17826 GenTreeHWIntrinsic(type, gtNewArgList(op1, op2, op3, op4), hwIntrinsicID, baseType, size);
17829 GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID)
17831 SetOpLclRelatedToSIMDIntrinsic(op1);
17833 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, hwIntrinsicID, TYP_UNKNOWN, 0);
17836 GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type,
17839 NamedIntrinsic hwIntrinsicID)
17841 SetOpLclRelatedToSIMDIntrinsic(op1);
17842 SetOpLclRelatedToSIMDIntrinsic(op2);
17844 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, op2, hwIntrinsicID, TYP_UNKNOWN, 0);
17847 GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(
17848 var_types type, GenTree* op1, GenTree* op2, GenTree* op3, NamedIntrinsic hwIntrinsicID)
17850 SetOpLclRelatedToSIMDIntrinsic(op1);
17851 SetOpLclRelatedToSIMDIntrinsic(op2);
17852 SetOpLclRelatedToSIMDIntrinsic(op3);
17854 return new (this, GT_HWIntrinsic)
17855 GenTreeHWIntrinsic(type, gtNewArgList(op1, op2, op3), hwIntrinsicID, TYP_UNKNOWN, 0);
17858 //---------------------------------------------------------------------------------------
17859 // gtNewMustThrowException:
17860 // create a throw node (calling into JIT helper) that must be thrown.
17861 // The result would be a comma node: COMMA(jithelperthrow(void), x) where x's type should be specified.
17864 // helper - JIT helper ID
17865 // type - return type of the node
17868 // pointer to the throw node
17870 GenTree* Compiler::gtNewMustThrowException(unsigned helper, var_types type, CORINFO_CLASS_HANDLE clsHnd)
17872 GenTreeCall* node = gtNewHelperCallNode(helper, TYP_VOID);
17873 node->gtCallMoreFlags |= GTF_CALL_M_DOES_NOT_RETURN;
17874 if (type != TYP_VOID)
17876 unsigned dummyTemp = lvaGrabTemp(true DEBUGARG("dummy temp of must thrown exception"));
17877 if (type == TYP_STRUCT)
17879 lvaSetStruct(dummyTemp, clsHnd, false);
17880 type = lvaTable[dummyTemp].lvType; // struct type is normalized
17884 lvaTable[dummyTemp].lvType = type;
17886 GenTree* dummyNode = gtNewLclvNode(dummyTemp, type);
17887 return gtNewOperNode(GT_COMMA, type, node, dummyNode);
17892 // Returns true for the HW Instrinsic instructions that have MemoryLoad semantics, false otherwise
17893 bool GenTreeHWIntrinsic::OperIsMemoryLoad()
17895 #ifdef _TARGET_XARCH_
17896 // Some xarch instructions have MemoryLoad sematics
17897 HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(gtHWIntrinsicId);
17898 if (category == HW_Category_MemoryLoad)
17902 else if (HWIntrinsicInfo::MaybeMemoryLoad(gtHWIntrinsicId))
17904 // Some AVX intrinsic (without HW_Category_MemoryLoad) also have MemoryLoad semantics
17905 if (category == HW_Category_SIMDScalar)
17907 // Avx2.BroadcastScalarToVector128/256 have vector and pointer overloads both, e.g.,
17908 // Vector128<byte> BroadcastScalarToVector128(Vector128<byte> value)
17909 // Vector128<byte> BroadcastScalarToVector128(byte* source)
17910 // So, we need to check the argument's type is memory-reference (TYP_I_IMPL) or not
17911 assert(HWIntrinsicInfo::lookupNumArgs(this) == 1);
17912 return (gtHWIntrinsicId == NI_AVX2_BroadcastScalarToVector128 ||
17913 gtHWIntrinsicId == NI_AVX2_BroadcastScalarToVector256) &&
17914 gtOp.gtOp1->TypeGet() == TYP_I_IMPL;
17916 else if (category == HW_Category_IMM)
17918 // Do we have less than 3 operands?
17919 if (HWIntrinsicInfo::lookupNumArgs(this) < 3)
17923 else // We have 3 or more operands/args
17925 // All the Avx2.Gather* are "load" instructions
17926 if (HWIntrinsicInfo::isAVX2GatherIntrinsic(gtHWIntrinsicId))
17931 GenTreeArgList* argList = gtOp.gtOp1->AsArgList();
17933 // Avx/Avx2.InsertVector128 have vector and pointer overloads both, e.g.,
17934 // Vector256<sbyte> InsertVector128(Vector256<sbyte> value, Vector128<sbyte> data, byte index)
17935 // Vector256<sbyte> InsertVector128(Vector256<sbyte> value, sbyte* address, byte index)
17936 // So, we need to check the second argument's type is memory-reference (TYP_I_IMPL) or not
17937 if ((gtHWIntrinsicId == NI_AVX_InsertVector128 || gtHWIntrinsicId == NI_AVX2_InsertVector128) &&
17938 (argList->Rest()->Current()->TypeGet() == TYP_I_IMPL)) // Is the type of the second arg TYP_I_IMPL?
17940 // This is Avx/Avx2.InsertVector128
17946 #endif // _TARGET_XARCH_
17950 // Returns true for the HW Instrinsic instructions that have MemoryStore semantics, false otherwise
17951 bool GenTreeHWIntrinsic::OperIsMemoryStore()
17953 #ifdef _TARGET_XARCH_
17954 // Some xarch instructions have MemoryStore sematics
17955 HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(gtHWIntrinsicId);
17956 if (category == HW_Category_MemoryStore)
17960 else if (HWIntrinsicInfo::MaybeMemoryStore(gtHWIntrinsicId) && category == HW_Category_IMM)
17962 // Some AVX intrinsic (without HW_Category_MemoryStore) also have MemoryStore semantics
17964 // Avx/Avx2.InsertVector128 have vector and pointer overloads both, e.g.,
17965 // Vector128<sbyte> ExtractVector128(Vector256<sbyte> value, byte index)
17966 // void ExtractVector128(sbyte* address, Vector256<sbyte> value, byte index)
17967 // So, the 3-argument form is MemoryStore
17968 if ((HWIntrinsicInfo::lookupNumArgs(this) == 3) &&
17969 (gtHWIntrinsicId == NI_AVX_ExtractVector128 || gtHWIntrinsicId == NI_AVX2_ExtractVector128))
17974 #endif // _TARGET_XARCH_
17978 // Returns true for the HW Instrinsic instructions that have MemoryLoad semantics, false otherwise
17979 bool GenTreeHWIntrinsic::OperIsMemoryLoadOrStore()
17981 #ifdef _TARGET_XARCH_
17982 return OperIsMemoryLoad() || OperIsMemoryStore();
17983 #endif // _TARGET_XARCH_
17987 #endif // FEATURE_HW_INTRINSICS
17989 //---------------------------------------------------------------------------------------
17990 // InitializeStructReturnType:
17991 // Initialize the Return Type Descriptor for a method that returns a struct type
17994 // comp - Compiler Instance
17995 // retClsHnd - VM handle to the struct type returned by the method
18000 void ReturnTypeDesc::InitializeStructReturnType(Compiler* comp, CORINFO_CLASS_HANDLE retClsHnd)
18004 #if FEATURE_MULTIREG_RET
18006 assert(retClsHnd != NO_CLASS_HANDLE);
18007 unsigned structSize = comp->info.compCompHnd->getClassSize(retClsHnd);
18009 Compiler::structPassingKind howToReturnStruct;
18010 var_types returnType = comp->getReturnTypeForStruct(retClsHnd, &howToReturnStruct, structSize);
18012 switch (howToReturnStruct)
18014 case Compiler::SPK_EnclosingType:
18015 m_isEnclosingType = true;
18018 case Compiler::SPK_PrimitiveType:
18020 assert(returnType != TYP_UNKNOWN);
18021 assert(!varTypeIsStruct(returnType));
18022 m_regType[0] = returnType;
18026 case Compiler::SPK_ByValueAsHfa:
18028 assert(varTypeIsStruct(returnType));
18029 var_types hfaType = comp->GetHfaType(retClsHnd);
18031 // We should have an hfa struct type
18032 assert(varTypeIsFloating(hfaType));
18034 // Note that the retail build issues a warning about a potential divsion by zero without this Max function
18035 unsigned elemSize = Max((unsigned)1, EA_SIZE_IN_BYTES(emitActualTypeSize(hfaType)));
18037 // The size of this struct should be evenly divisible by elemSize
18038 assert((structSize % elemSize) == 0);
18040 unsigned hfaCount = (structSize / elemSize);
18041 for (unsigned i = 0; i < hfaCount; ++i)
18043 m_regType[i] = hfaType;
18046 if (comp->compFloatingPointUsed == false)
18048 comp->compFloatingPointUsed = true;
18053 case Compiler::SPK_ByValue:
18055 assert(varTypeIsStruct(returnType));
18057 #ifdef UNIX_AMD64_ABI
18059 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
18060 comp->eeGetSystemVAmd64PassStructInRegisterDescriptor(retClsHnd, &structDesc);
18062 assert(structDesc.passedInRegisters);
18063 for (int i = 0; i < structDesc.eightByteCount; i++)
18065 assert(i < MAX_RET_REG_COUNT);
18066 m_regType[i] = comp->GetEightByteType(structDesc, i);
18069 #elif defined(_TARGET_ARM64_)
18071 // a non-HFA struct returned using two registers
18073 assert((structSize > TARGET_POINTER_SIZE) && (structSize <= (2 * TARGET_POINTER_SIZE)));
18075 BYTE gcPtrs[2] = {TYPE_GC_NONE, TYPE_GC_NONE};
18076 comp->info.compCompHnd->getClassGClayout(retClsHnd, &gcPtrs[0]);
18077 for (unsigned i = 0; i < 2; ++i)
18079 m_regType[i] = comp->getJitGCType(gcPtrs[i]);
18082 #else // _TARGET_XXX_
18084 // This target needs support here!
18086 NYI("Unsupported TARGET returning a TYP_STRUCT in InitializeStructReturnType");
18088 #endif // UNIX_AMD64_ABI
18090 break; // for case SPK_ByValue
18093 case Compiler::SPK_ByReference:
18095 // We are returning using the return buffer argument
18096 // There are no return registers
18101 unreached(); // By the contract of getReturnTypeForStruct we should never get here.
18103 } // end of switch (howToReturnStruct)
18105 #endif // FEATURE_MULTIREG_RET
18112 //---------------------------------------------------------------------------------------
18113 // InitializeLongReturnType:
18114 // Initialize the Return Type Descriptor for a method that returns a TYP_LONG
18117 // comp - Compiler Instance
18122 void ReturnTypeDesc::InitializeLongReturnType(Compiler* comp)
18124 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
18126 // Setups up a ReturnTypeDesc for returning a long using two registers
18128 assert(MAX_RET_REG_COUNT >= 2);
18129 m_regType[0] = TYP_INT;
18130 m_regType[1] = TYP_INT;
18132 #else // not (_TARGET_X86_ or _TARGET_ARM_)
18134 m_regType[0] = TYP_LONG;
18136 #endif // _TARGET_X86_ or _TARGET_ARM_
18143 //-------------------------------------------------------------------
18144 // GetABIReturnReg: Return ith return register as per target ABI
18147 // idx - Index of the return register.
18148 // The first return register has an index of 0 and so on.
18151 // Returns ith return register as per target ABI.
18154 // x86 and ARM return long in multiple registers.
18155 // ARM and ARM64 return HFA struct in multiple registers.
18157 regNumber ReturnTypeDesc::GetABIReturnReg(unsigned idx)
18159 unsigned count = GetReturnRegCount();
18160 assert(idx < count);
18162 regNumber resultReg = REG_NA;
18164 #ifdef UNIX_AMD64_ABI
18165 var_types regType0 = GetReturnRegType(0);
18169 if (varTypeIsIntegralOrI(regType0))
18171 resultReg = REG_INTRET;
18175 noway_assert(varTypeIsFloating(regType0));
18176 resultReg = REG_FLOATRET;
18181 var_types regType1 = GetReturnRegType(1);
18183 if (varTypeIsIntegralOrI(regType1))
18185 if (varTypeIsIntegralOrI(regType0))
18187 resultReg = REG_INTRET_1;
18191 resultReg = REG_INTRET;
18196 noway_assert(varTypeIsFloating(regType1));
18198 if (varTypeIsFloating(regType0))
18200 resultReg = REG_FLOATRET_1;
18204 resultReg = REG_FLOATRET;
18209 #elif defined(_TARGET_X86_)
18213 resultReg = REG_LNGRET_LO;
18217 resultReg = REG_LNGRET_HI;
18220 #elif defined(_TARGET_ARM_)
18222 var_types regType = GetReturnRegType(idx);
18223 if (varTypeIsIntegralOrI(regType))
18225 // Ints are returned in one return register.
18226 // Longs are returned in two return registers.
18229 resultReg = REG_LNGRET_LO;
18233 resultReg = REG_LNGRET_HI;
18238 // Floats are returned in one return register (f0).
18239 // Doubles are returned in one return register (d0).
18240 // Structs are returned in four registers with HFAs.
18241 assert(idx < MAX_RET_REG_COUNT); // Up to 4 return registers for HFA's
18242 if (regType == TYP_DOUBLE)
18244 resultReg = (regNumber)((unsigned)(REG_FLOATRET) + idx * 2); // d0, d1, d2 or d3
18248 resultReg = (regNumber)((unsigned)(REG_FLOATRET) + idx); // f0, f1, f2 or f3
18252 #elif defined(_TARGET_ARM64_)
18254 var_types regType = GetReturnRegType(idx);
18255 if (varTypeIsIntegralOrI(regType))
18257 noway_assert(idx < 2); // Up to 2 return registers for 16-byte structs
18258 resultReg = (idx == 0) ? REG_INTRET : REG_INTRET_1; // X0 or X1
18262 noway_assert(idx < 4); // Up to 4 return registers for HFA's
18263 resultReg = (regNumber)((unsigned)(REG_FLOATRET) + idx); // V0, V1, V2 or V3
18266 #endif // TARGET_XXX
18268 assert(resultReg != REG_NA);
18272 //--------------------------------------------------------------------------------
18273 // GetABIReturnRegs: get the mask of return registers as per target arch ABI.
18279 // reg mask of return registers in which the return type is returned.
18282 // This routine can be used when the caller is not particular about the order
18283 // of return registers and wants to know the set of return registers.
18286 regMaskTP ReturnTypeDesc::GetABIReturnRegs()
18288 regMaskTP resultMask = RBM_NONE;
18290 unsigned count = GetReturnRegCount();
18291 for (unsigned i = 0; i < count; ++i)
18293 resultMask |= genRegMask(GetABIReturnReg(i));
18299 //------------------------------------------------------------------------
18300 // The following functions manage the gtRsvdRegs set of temporary registers
18301 // created by LSRA during code generation.
18303 //------------------------------------------------------------------------
18304 // AvailableTempRegCount: return the number of available temporary registers in the (optional) given set
18305 // (typically, RBM_ALLINT or RBM_ALLFLOAT).
18308 // mask - (optional) Check for available temporary registers only in this set.
18311 // Count of available temporary registers in given set.
18313 unsigned GenTree::AvailableTempRegCount(regMaskTP mask /* = (regMaskTP)-1 */) const
18315 return genCountBits(gtRsvdRegs & mask);
18318 //------------------------------------------------------------------------
18319 // GetSingleTempReg: There is expected to be exactly one available temporary register
18320 // in the given mask in the gtRsvdRegs set. Get that register. No future calls to get
18321 // a temporary register are expected. Removes the register from the set, but only in
18322 // DEBUG to avoid doing unnecessary work in non-DEBUG builds.
18325 // mask - (optional) Get an available temporary register only in this set.
18328 // Available temporary register in given mask.
18330 regNumber GenTree::GetSingleTempReg(regMaskTP mask /* = (regMaskTP)-1 */)
18332 regMaskTP availableSet = gtRsvdRegs & mask;
18333 assert(genCountBits(availableSet) == 1);
18334 regNumber tempReg = genRegNumFromMask(availableSet);
18335 INDEBUG(gtRsvdRegs &= ~availableSet;) // Remove the register from the set, so it can't be used again.
18339 //------------------------------------------------------------------------
18340 // ExtractTempReg: Find the lowest number temporary register from the gtRsvdRegs set
18341 // that is also in the optional given mask (typically, RBM_ALLINT or RBM_ALLFLOAT),
18342 // and return it. Remove this register from the temporary register set, so it won't
18343 // be returned again.
18346 // mask - (optional) Extract an available temporary register only in this set.
18349 // Available temporary register in given mask.
18351 regNumber GenTree::ExtractTempReg(regMaskTP mask /* = (regMaskTP)-1 */)
18353 regMaskTP availableSet = gtRsvdRegs & mask;
18354 assert(genCountBits(availableSet) >= 1);
18355 regMaskTP tempRegMask = genFindLowestBit(availableSet);
18356 gtRsvdRegs &= ~tempRegMask;
18357 return genRegNumFromMask(tempRegMask);