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) || ((gtCallMoreFlags & GTF_CALL_M_ALLOC_SIDE_EFFECTS) != 0));
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());
6729 bool helperHasSideEffects;
6730 CorInfoHelpFunc helperTemp =
6731 info.compCompHnd->getNewHelper(pResolvedToken, info.compMethodHnd, &helperHasSideEffects);
6733 if (!usingReadyToRunHelper)
6735 helper = helperTemp;
6738 // TODO: ReadyToRun: When generic dictionary lookups are necessary, replace the lookup call
6739 // and the newfast call with a single call to a dynamic R2R cell that will:
6740 // 1) Load the context
6741 // 2) Perform the generic dictionary lookup and caching, and generate the appropriate stub
6742 // 3) Allocate and return the new object for boxing
6743 // Reason: performance (today, we'll always use the slow helper for the R2R generics case)
6745 GenTreeAllocObj* allocObj =
6746 gtNewAllocObjNode(helper, helperHasSideEffects, pResolvedToken->hClass, TYP_REF, opHandle);
6748 #ifdef FEATURE_READYTORUN_COMPILER
6749 if (usingReadyToRunHelper)
6751 allocObj->gtEntryPoint = lookup;
6758 /*****************************************************************************
6760 * Clones the given tree value and returns a copy of the given tree.
6761 * If 'complexOK' is false, the cloning is only done provided the tree
6762 * is not too complex (whatever that may mean);
6763 * If 'complexOK' is true, we try slightly harder to clone the tree.
6764 * In either case, NULL is returned if the tree cannot be cloned
6766 * Note that there is the function gtCloneExpr() which does a more
6767 * complete job if you can't handle this function failing.
6770 GenTree* Compiler::gtClone(GenTree* tree, bool complexOK)
6774 switch (tree->gtOper)
6778 #if defined(LATE_DISASM)
6779 if (tree->IsIconHandle())
6781 copy = gtNewIconHandleNode(tree->gtIntCon.gtIconVal, tree->gtFlags, tree->gtIntCon.gtFieldSeq);
6782 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6783 copy->gtType = tree->gtType;
6788 copy = new (this, GT_CNS_INT)
6789 GenTreeIntCon(tree->gtType, tree->gtIntCon.gtIconVal, tree->gtIntCon.gtFieldSeq);
6790 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6795 copy = gtNewLconNode(tree->gtLngCon.gtLconVal);
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 = gtNewLclvNode(tree->gtLclVarCommon.gtLclNum, tree->gtType, tree->gtLclVar.gtLclILoffs);
6806 case GT_LCL_FLD_ADDR:
6807 // Remember that the LclVar node has been cloned. The flag will be set
6808 // on 'copy' as well.
6809 tree->gtFlags |= GTF_VAR_CLONED;
6810 copy = new (this, tree->gtOper)
6811 GenTreeLclFld(tree->gtOper, tree->TypeGet(), tree->gtLclFld.gtLclNum, tree->gtLclFld.gtLclOffs);
6812 copy->gtLclFld.gtFieldSeq = tree->gtLclFld.gtFieldSeq;
6816 copy = new (this, GT_CLS_VAR)
6817 GenTreeClsVar(tree->gtType, tree->gtClsVar.gtClsVarHnd, tree->gtClsVar.gtFieldSeq);
6826 if (tree->gtOper == GT_FIELD)
6830 // copied from line 9850
6833 if (tree->gtField.gtFldObj)
6835 objp = gtClone(tree->gtField.gtFldObj, false);
6842 copy = gtNewFieldRef(tree->TypeGet(), tree->gtField.gtFldHnd, objp, tree->gtField.gtFldOffset);
6843 copy->gtField.gtFldMayOverlap = tree->gtField.gtFldMayOverlap;
6844 #ifdef FEATURE_READYTORUN_COMPILER
6845 copy->gtField.gtFieldLookup = tree->gtField.gtFieldLookup;
6848 else if (tree->OperIs(GT_ADD, GT_SUB))
6850 GenTree* op1 = tree->gtOp.gtOp1;
6851 GenTree* op2 = tree->gtOp.gtOp2;
6853 if (op1->OperIsLeaf() && op2->OperIsLeaf())
6866 copy = gtNewOperNode(tree->OperGet(), tree->TypeGet(), op1, op2);
6873 else if (tree->gtOper == GT_ADDR)
6875 GenTree* op1 = gtClone(tree->gtOp.gtOp1);
6880 copy = gtNewOperNode(GT_ADDR, tree->TypeGet(), op1);
6890 copy->gtFlags |= tree->gtFlags & ~GTF_NODE_MASK;
6892 copy->gtDebugFlags |= tree->gtDebugFlags & ~GTF_DEBUG_NODE_MASK;
6893 #endif // defined(DEBUG)
6898 //------------------------------------------------------------------------
6899 // gtCloneExpr: Create a copy of `tree`, adding flags `addFlags`, mapping
6900 // local `varNum` to int constant `varVal` if it appears at
6901 // the root, and mapping uses of local `deepVarNum` to constant
6902 // `deepVarVal` if they occur beyond the root.
6905 // tree - GenTree to create a copy of
6906 // addFlags - GTF_* flags to add to the copied tree nodes
6907 // varNum - lclNum to replace at the root, or ~0 for no root replacement
6908 // varVal - If replacing at root, replace local `varNum` with IntCns `varVal`
6909 // deepVarNum - lclNum to replace uses of beyond the root, or ~0 for no replacement
6910 // deepVarVal - If replacing beyond root, replace `deepVarNum` with IntCns `deepVarVal`
6913 // A copy of the given tree with the replacements and added flags specified.
6916 // Top-level callers should generally call the overload that doesn't have
6917 // the explicit `deepVarNum` and `deepVarVal` parameters; those are used in
6918 // recursive invocations to avoid replacing defs.
6920 GenTree* Compiler::gtCloneExpr(
6921 GenTree* tree, unsigned addFlags, unsigned varNum, int varVal, unsigned deepVarNum, int deepVarVal)
6923 if (tree == nullptr)
6928 /* Figure out what kind of a node we have */
6930 genTreeOps oper = tree->OperGet();
6931 unsigned kind = tree->OperKind();
6934 /* Is this a constant or leaf node? */
6936 if (kind & (GTK_CONST | GTK_LEAF))
6942 #if defined(LATE_DISASM)
6943 if (tree->IsIconHandle())
6945 copy = gtNewIconHandleNode(tree->gtIntCon.gtIconVal, tree->gtFlags, tree->gtIntCon.gtFieldSeq);
6946 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6947 copy->gtType = tree->gtType;
6952 copy = gtNewIconNode(tree->gtIntCon.gtIconVal, tree->gtType);
6953 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6954 copy->gtIntCon.gtFieldSeq = tree->gtIntCon.gtFieldSeq;
6959 copy = gtNewLconNode(tree->gtLngCon.gtLconVal);
6963 copy = gtNewDconNode(tree->gtDblCon.gtDconVal);
6964 copy->gtType = tree->gtType; // keep the same type
6968 copy = gtNewSconNode(tree->gtStrCon.gtSconCPX, tree->gtStrCon.gtScpHnd);
6973 if (tree->gtLclVarCommon.gtLclNum == varNum)
6975 copy = gtNewIconNode(varVal, tree->gtType);
6976 if (tree->gtFlags & GTF_VAR_ARR_INDEX)
6978 copy->LabelIndex(this);
6983 // Remember that the LclVar node has been cloned. The flag will
6984 // be set on 'copy' as well.
6985 tree->gtFlags |= GTF_VAR_CLONED;
6986 copy = gtNewLclvNode(tree->gtLclVar.gtLclNum, tree->gtType, tree->gtLclVar.gtLclILoffs);
6987 copy->AsLclVarCommon()->SetSsaNum(tree->AsLclVarCommon()->GetSsaNum());
6989 copy->gtFlags = tree->gtFlags;
6993 if (tree->gtLclFld.gtLclNum == varNum)
6995 IMPL_LIMITATION("replacing GT_LCL_FLD with a constant");
6999 // Remember that the LclVar node has been cloned. The flag will
7000 // be set on 'copy' as well.
7001 tree->gtFlags |= GTF_VAR_CLONED;
7002 copy = new (this, GT_LCL_FLD)
7003 GenTreeLclFld(tree->TypeGet(), tree->gtLclFld.gtLclNum, tree->gtLclFld.gtLclOffs);
7004 copy->gtLclFld.gtFieldSeq = tree->gtLclFld.gtFieldSeq;
7005 copy->gtFlags = tree->gtFlags;
7010 copy = new (this, GT_CLS_VAR)
7011 GenTreeClsVar(tree->TypeGet(), tree->gtClsVar.gtClsVarHnd, tree->gtClsVar.gtFieldSeq);
7015 // GT_RET_EXPR is unique node, that contains a link to a gtInlineCandidate node,
7016 // that is part of another statement. We cannot clone both here and cannot
7017 // create another GT_RET_EXPR that points to the same gtInlineCandidate.
7018 NO_WAY("Cloning of GT_RET_EXPR node not supported");
7021 case GT_MEMORYBARRIER:
7022 copy = new (this, GT_MEMORYBARRIER) GenTree(GT_MEMORYBARRIER, TYP_VOID);
7026 copy = gtNewArgPlaceHolderNode(tree->gtType, tree->gtArgPlace.gtArgPlaceClsHnd);
7030 copy = new (this, oper) GenTreeFptrVal(tree->gtType, tree->gtFptrVal.gtFptrMethod);
7032 #ifdef FEATURE_READYTORUN_COMPILER
7033 copy->gtFptrVal.gtEntryPoint = tree->gtFptrVal.gtEntryPoint;
7039 copy = new (this, oper) GenTree(oper, tree->gtType);
7042 #if !FEATURE_EH_FUNCLETS
7044 #endif // !FEATURE_EH_FUNCLETS
7046 copy = new (this, oper) GenTreeVal(oper, tree->gtType, tree->gtVal.gtVal1);
7050 copy = new (this, oper) GenTreeLabel(tree->gtLabel.gtLabBB);
7054 NO_WAY("Cloning of node not supported");
7059 /* Is it a 'simple' unary/binary operator? */
7061 if (kind & GTK_SMPOP)
7063 /* If necessary, make sure we allocate a "fat" tree node */
7064 CLANG_FORMAT_COMMENT_ANCHOR;
7066 #if SMALL_TREE_NODES
7069 /* These nodes sometimes get bashed to "fat" ones */
7078 // In the implementation of gtNewLargeOperNode you have
7079 // to give an oper that will create a small node,
7080 // otherwise it asserts.
7082 if (GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL)
7084 copy = gtNewLargeOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1,
7085 tree->OperIsBinary() ? tree->gtOp.gtOp2 : nullptr);
7087 else // Always a large tree
7089 if (tree->OperIsBinary())
7091 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2);
7095 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1);
7102 new (this, LargeOpOpcode()) GenTreeCast(tree->TypeGet(), tree->gtCast.CastOp(), tree->IsUnsigned(),
7103 tree->gtCast.gtCastType DEBUGARG(/*largeNode*/ TRUE));
7106 // The nodes below this are not bashed, so they can be allocated at their individual sizes.
7109 assert((tree->gtOp.gtOp2 == nullptr) || tree->gtOp.gtOp2->OperIsList());
7110 copy = new (this, GT_LIST) GenTreeArgList(tree->gtOp.gtOp1);
7111 copy->gtOp.gtOp2 = tree->gtOp.gtOp2;
7115 copy = new (this, GT_FIELD_LIST) GenTreeFieldList(tree->gtOp.gtOp1, tree->AsFieldList()->gtFieldOffset,
7116 tree->AsFieldList()->gtFieldType, nullptr);
7117 copy->gtOp.gtOp2 = tree->gtOp.gtOp2;
7118 copy->gtFlags = (copy->gtFlags & ~GTF_FIELD_LIST_HEAD) | (tree->gtFlags & GTF_FIELD_LIST_HEAD);
7123 GenTreeIndex* asInd = tree->AsIndex();
7124 copy = new (this, GT_INDEX)
7125 GenTreeIndex(asInd->TypeGet(), asInd->Arr(), asInd->Index(), asInd->gtIndElemSize);
7126 copy->AsIndex()->gtStructElemClass = asInd->gtStructElemClass;
7132 GenTreeIndexAddr* asIndAddr = tree->AsIndexAddr();
7134 copy = new (this, GT_INDEX_ADDR)
7135 GenTreeIndexAddr(asIndAddr->Arr(), asIndAddr->Index(), asIndAddr->gtElemType,
7136 asIndAddr->gtStructElemClass, asIndAddr->gtElemSize, asIndAddr->gtLenOffset,
7137 asIndAddr->gtElemOffset);
7138 copy->AsIndexAddr()->gtIndRngFailBB = asIndAddr->gtIndRngFailBB;
7144 GenTreeAllocObj* asAllocObj = tree->AsAllocObj();
7145 copy = new (this, GT_ALLOCOBJ)
7146 GenTreeAllocObj(tree->TypeGet(), asAllocObj->gtNewHelper, asAllocObj->gtHelperHasSideEffects,
7147 asAllocObj->gtAllocObjClsHnd, asAllocObj->gtOp1);
7151 case GT_RUNTIMELOOKUP:
7153 GenTreeRuntimeLookup* asRuntimeLookup = tree->AsRuntimeLookup();
7155 copy = new (this, GT_RUNTIMELOOKUP)
7156 GenTreeRuntimeLookup(asRuntimeLookup->gtHnd, asRuntimeLookup->gtHndType, asRuntimeLookup->gtOp1);
7161 copy = gtNewArrLen(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtArrLen.ArrLenOffset());
7165 copy = new (this, GT_ARR_INDEX)
7166 GenTreeArrIndex(tree->TypeGet(),
7167 gtCloneExpr(tree->gtArrIndex.ArrObj(), addFlags, deepVarNum, deepVarVal),
7168 gtCloneExpr(tree->gtArrIndex.IndexExpr(), addFlags, deepVarNum, deepVarVal),
7169 tree->gtArrIndex.gtCurrDim, tree->gtArrIndex.gtArrRank,
7170 tree->gtArrIndex.gtArrElemType);
7174 copy = new (this, GT_QMARK) GenTreeQmark(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2, this);
7178 copy = new (this, GT_OBJ)
7179 GenTreeObj(tree->TypeGet(), tree->gtOp.gtOp1, tree->AsObj()->gtClass, tree->gtBlk.gtBlkSize);
7180 copy->AsObj()->CopyGCInfo(tree->AsObj());
7181 copy->gtBlk.gtBlkOpGcUnsafe = tree->gtBlk.gtBlkOpGcUnsafe;
7185 copy = new (this, GT_BLK) GenTreeBlk(GT_BLK, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtBlk.gtBlkSize);
7186 copy->gtBlk.gtBlkOpGcUnsafe = tree->gtBlk.gtBlkOpGcUnsafe;
7190 copy = new (this, GT_DYN_BLK) GenTreeDynBlk(tree->gtOp.gtOp1, tree->gtDynBlk.gtDynamicSize);
7191 copy->gtBlk.gtBlkOpGcUnsafe = tree->gtBlk.gtBlkOpGcUnsafe;
7195 copy = new (this, GT_BOX)
7196 GenTreeBox(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtBox.gtAsgStmtWhenInlinedBoxValue,
7197 tree->gtBox.gtCopyStmtWhenInlinedBoxValue);
7201 copy = new (this, GT_INTRINSIC)
7202 GenTreeIntrinsic(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2,
7203 tree->gtIntrinsic.gtIntrinsicId, tree->gtIntrinsic.gtMethodHandle);
7204 #ifdef FEATURE_READYTORUN_COMPILER
7205 copy->gtIntrinsic.gtEntryPoint = tree->gtIntrinsic.gtEntryPoint;
7211 GenTreeAddrMode* addrModeOp = tree->AsAddrMode();
7212 copy = new (this, GT_LEA)
7213 GenTreeAddrMode(addrModeOp->TypeGet(), addrModeOp->Base(), addrModeOp->Index(), addrModeOp->gtScale,
7214 static_cast<unsigned>(addrModeOp->Offset()));
7221 copy = new (this, oper) GenTreeCopyOrReload(oper, tree->TypeGet(), tree->gtGetOp1());
7228 GenTreeSIMD* simdOp = tree->AsSIMD();
7229 copy = gtNewSIMDNode(simdOp->TypeGet(), simdOp->gtGetOp1(), simdOp->gtGetOp2IfPresent(),
7230 simdOp->gtSIMDIntrinsicID, simdOp->gtSIMDBaseType, simdOp->gtSIMDSize);
7235 #ifdef FEATURE_HW_INTRINSICS
7236 case GT_HWIntrinsic:
7238 GenTreeHWIntrinsic* hwintrinsicOp = tree->AsHWIntrinsic();
7239 copy = new (this, GT_HWIntrinsic)
7240 GenTreeHWIntrinsic(hwintrinsicOp->TypeGet(), hwintrinsicOp->gtGetOp1(),
7241 hwintrinsicOp->gtGetOp2IfPresent(), hwintrinsicOp->gtHWIntrinsicId,
7242 hwintrinsicOp->gtSIMDBaseType, hwintrinsicOp->gtSIMDSize);
7243 copy->AsHWIntrinsic()->gtIndexBaseType = hwintrinsicOp->gtIndexBaseType;
7249 assert(!GenTree::IsExOp(tree->OperKind()) && tree->OperIsSimple());
7250 // We're in the SimpleOp case, so it's always unary or binary.
7251 if (GenTree::OperIsUnary(tree->OperGet()))
7253 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, /*doSimplifications*/ false);
7257 assert(GenTree::OperIsBinary(tree->OperGet()));
7258 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2);
7263 // We're in the SimpleOp case, so it's always unary or binary.
7264 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2);
7267 // Some flags are conceptually part of the gtOper, and should be copied immediately.
7268 if (tree->gtOverflowEx())
7270 copy->gtFlags |= GTF_OVERFLOW;
7273 if (tree->gtOp.gtOp1)
7275 if (tree->gtOper == GT_ASG)
7277 // Don't replace varNum if it appears as the LHS of an assign.
7278 copy->gtOp.gtOp1 = gtCloneExpr(tree->gtOp.gtOp1, addFlags, -1, 0, deepVarNum, deepVarVal);
7282 copy->gtOp.gtOp1 = gtCloneExpr(tree->gtOp.gtOp1, addFlags, deepVarNum, deepVarVal);
7286 if (tree->gtGetOp2IfPresent())
7288 copy->gtOp.gtOp2 = gtCloneExpr(tree->gtOp.gtOp2, addFlags, deepVarNum, deepVarVal);
7292 addFlags |= tree->gtFlags;
7294 // Copy any node annotations, if necessary.
7295 switch (tree->gtOper)
7303 if (!tree->AsIndir()->gtOp1->OperIs(GT_INDEX_ADDR) && TryGetArrayInfo(tree->AsIndir(), &arrInfo))
7305 GetArrayInfoMap()->Set(copy, arrInfo);
7315 /* GTF_NODE_MASK should not be propagated from 'tree' to 'copy' */
7316 addFlags &= ~GTF_NODE_MASK;
7319 // Effects flags propagate upwards.
7320 if (copy->gtOp.gtOp1 != nullptr)
7322 copy->gtFlags |= (copy->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
7324 if (copy->gtGetOp2IfPresent() != nullptr)
7326 copy->gtFlags |= (copy->gtGetOp2()->gtFlags & GTF_ALL_EFFECT);
7332 /* See what kind of a special operator we have here */
7337 copy = gtCloneExpr(tree->gtStmt.gtStmtExpr, addFlags, deepVarNum, deepVarVal);
7338 copy = gtNewStmt(copy, tree->gtStmt.gtStmtILoffsx);
7343 // We can't safely clone calls that have GT_RET_EXPRs via gtCloneExpr.
7344 // You must use gtCloneCandidateCall for these calls (and then do appropriate other fixup)
7345 if (tree->gtCall.IsInlineCandidate() || tree->gtCall.IsGuardedDevirtualizationCandidate())
7347 NO_WAY("Cloning of calls with associated GT_RET_EXPR nodes is not supported");
7350 copy = gtCloneExprCallHelper(tree->AsCall(), addFlags, deepVarNum, deepVarVal);
7355 copy = gtNewFieldRef(tree->TypeGet(), tree->gtField.gtFldHnd, nullptr, tree->gtField.gtFldOffset);
7357 copy->gtField.gtFldObj = tree->gtField.gtFldObj
7358 ? gtCloneExpr(tree->gtField.gtFldObj, addFlags, deepVarNum, deepVarVal)
7360 copy->gtField.gtFldMayOverlap = tree->gtField.gtFldMayOverlap;
7361 #ifdef FEATURE_READYTORUN_COMPILER
7362 copy->gtField.gtFieldLookup = tree->gtField.gtFieldLookup;
7369 GenTree* inds[GT_ARR_MAX_RANK];
7370 for (unsigned dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
7372 inds[dim] = gtCloneExpr(tree->gtArrElem.gtArrInds[dim], addFlags, deepVarNum, deepVarVal);
7374 copy = new (this, GT_ARR_ELEM)
7375 GenTreeArrElem(tree->TypeGet(), gtCloneExpr(tree->gtArrElem.gtArrObj, addFlags, deepVarNum, deepVarVal),
7376 tree->gtArrElem.gtArrRank, tree->gtArrElem.gtArrElemSize, tree->gtArrElem.gtArrElemType,
7383 copy = new (this, GT_ARR_OFFSET)
7384 GenTreeArrOffs(tree->TypeGet(), gtCloneExpr(tree->gtArrOffs.gtOffset, addFlags, deepVarNum, deepVarVal),
7385 gtCloneExpr(tree->gtArrOffs.gtIndex, addFlags, deepVarNum, deepVarVal),
7386 gtCloneExpr(tree->gtArrOffs.gtArrObj, addFlags, deepVarNum, deepVarVal),
7387 tree->gtArrOffs.gtCurrDim, tree->gtArrOffs.gtArrRank, tree->gtArrOffs.gtArrElemType);
7392 copy = new (this, GT_CMPXCHG)
7393 GenTreeCmpXchg(tree->TypeGet(),
7394 gtCloneExpr(tree->gtCmpXchg.gtOpLocation, addFlags, deepVarNum, deepVarVal),
7395 gtCloneExpr(tree->gtCmpXchg.gtOpValue, addFlags, deepVarNum, deepVarVal),
7396 gtCloneExpr(tree->gtCmpXchg.gtOpComparand, addFlags, deepVarNum, deepVarVal));
7399 case GT_ARR_BOUNDS_CHECK:
7402 #endif // FEATURE_SIMD
7403 #ifdef FEATURE_HW_INTRINSICS
7404 case GT_HW_INTRINSIC_CHK:
7405 #endif // FEATURE_HW_INTRINSICS
7406 copy = new (this, oper)
7407 GenTreeBoundsChk(oper, tree->TypeGet(),
7408 gtCloneExpr(tree->gtBoundsChk.gtIndex, addFlags, deepVarNum, deepVarVal),
7409 gtCloneExpr(tree->gtBoundsChk.gtArrLen, addFlags, deepVarNum, deepVarVal),
7410 tree->gtBoundsChk.gtThrowKind);
7411 copy->gtBoundsChk.gtIndRngFailBB = tree->gtBoundsChk.gtIndRngFailBB;
7414 case GT_STORE_DYN_BLK:
7416 copy = new (this, oper)
7417 GenTreeDynBlk(gtCloneExpr(tree->gtDynBlk.Addr(), addFlags, deepVarNum, deepVarVal),
7418 gtCloneExpr(tree->gtDynBlk.gtDynamicSize, addFlags, deepVarNum, deepVarVal));
7425 NO_WAY("unexpected operator");
7430 // If it has a zero-offset field seq, copy annotation.
7431 if (tree->TypeGet() == TYP_BYREF)
7433 FieldSeqNode* fldSeq = nullptr;
7434 if (GetZeroOffsetFieldMap()->Lookup(tree, &fldSeq))
7436 GetZeroOffsetFieldMap()->Set(copy, fldSeq);
7440 copy->gtVNPair = tree->gtVNPair; // A cloned tree gets the orginal's Value number pair
7442 /* Compute the flags for the copied node. Note that we can do this only
7443 if we didnt gtFoldExpr(copy) */
7445 if (copy->gtOper == oper)
7447 addFlags |= tree->gtFlags;
7450 /* GTF_NODE_MASK should not be propagated from 'tree' to 'copy' */
7451 addFlags &= ~GTF_NODE_MASK;
7453 // Some other flags depend on the context of the expression, and should not be preserved.
7454 // For example, GTF_RELOP_QMARK:
7455 if (copy->OperKind() & GTK_RELOP)
7457 addFlags &= ~GTF_RELOP_QMARK;
7459 // On the other hand, if we're creating such a context, restore this flag.
7460 if (copy->OperGet() == GT_QMARK)
7462 copy->gtOp.gtOp1->gtFlags |= GTF_RELOP_QMARK;
7465 copy->gtFlags |= addFlags;
7467 // Update side effect flags since they may be different from the source side effect flags.
7468 // For example, we may have replaced some locals with constants and made indirections non-throwing.
7469 gtUpdateNodeSideEffects(copy);
7472 /* GTF_COLON_COND should be propagated from 'tree' to 'copy' */
7473 copy->gtFlags |= (tree->gtFlags & GTF_COLON_COND);
7476 // Non-node debug flags should be propagated from 'tree' to 'copy'
7477 copy->gtDebugFlags |= (tree->gtDebugFlags & ~GTF_DEBUG_NODE_MASK);
7480 /* Make sure to copy back fields that may have been initialized */
7482 copy->CopyRawCosts(tree);
7483 copy->gtRsvdRegs = tree->gtRsvdRegs;
7484 copy->CopyReg(tree);
7488 //------------------------------------------------------------------------
7489 // gtCloneExprCallHelper: clone a call tree
7492 // Do not invoke this method directly, instead call either gtCloneExpr
7493 // or gtCloneCandidateCall, as appropriate.
7496 // tree - the call to clone
7497 // addFlags - GTF_* flags to add to the copied tree nodes
7498 // deepVarNum - lclNum to replace uses of beyond the root, or BAD_VAR_NUM for no replacement
7499 // deepVarVal - If replacing beyond root, replace `deepVarNum` with IntCns `deepVarVal`
7502 // Cloned copy of call and all subtrees.
7504 GenTreeCall* Compiler::gtCloneExprCallHelper(GenTreeCall* tree, unsigned addFlags, unsigned deepVarNum, int deepVarVal)
7506 GenTreeCall* copy = new (this, GT_CALL) GenTreeCall(tree->TypeGet());
7508 copy->gtCallObjp = tree->gtCallObjp ? gtCloneExpr(tree->gtCallObjp, addFlags, deepVarNum, deepVarVal) : nullptr;
7510 tree->gtCallArgs ? gtCloneExpr(tree->gtCallArgs, addFlags, deepVarNum, deepVarVal)->AsArgList() : nullptr;
7511 copy->gtCallMoreFlags = tree->gtCallMoreFlags;
7512 copy->gtCallLateArgs = tree->gtCallLateArgs
7513 ? gtCloneExpr(tree->gtCallLateArgs, addFlags, deepVarNum, deepVarVal)->AsArgList()
7516 #if !FEATURE_FIXED_OUT_ARGS
7517 copy->regArgList = tree->regArgList;
7518 copy->regArgListCount = tree->regArgListCount;
7521 // The call sig comes from the EE and doesn't change throughout the compilation process, meaning
7522 // we only really need one physical copy of it. Therefore a shallow pointer copy will suffice.
7523 // (Note that this still holds even if the tree we are cloning was created by an inlinee compiler,
7524 // because the inlinee still uses the inliner's memory allocator anyway.)
7525 copy->callSig = tree->callSig;
7527 copy->gtCallType = tree->gtCallType;
7528 copy->gtReturnType = tree->gtReturnType;
7529 copy->gtControlExpr = tree->gtControlExpr;
7531 /* Copy the union */
7532 if (tree->gtCallType == CT_INDIRECT)
7534 copy->gtCallCookie =
7535 tree->gtCallCookie ? gtCloneExpr(tree->gtCallCookie, addFlags, deepVarNum, deepVarVal) : nullptr;
7536 copy->gtCallAddr = tree->gtCallAddr ? gtCloneExpr(tree->gtCallAddr, addFlags, deepVarNum, deepVarVal) : nullptr;
7538 else if (tree->IsVirtualStub())
7540 copy->gtCallMethHnd = tree->gtCallMethHnd;
7541 copy->gtStubCallStubAddr = tree->gtStubCallStubAddr;
7545 copy->gtCallMethHnd = tree->gtCallMethHnd;
7546 copy->gtInlineCandidateInfo = nullptr;
7549 if (tree->fgArgInfo)
7551 // Create and initialize the fgArgInfo for our copy of the call tree
7552 copy->fgArgInfo = new (this, CMK_Unknown) fgArgInfo(copy, tree);
7556 copy->fgArgInfo = nullptr;
7559 copy->gtRetClsHnd = tree->gtRetClsHnd;
7561 #if FEATURE_MULTIREG_RET
7562 copy->gtReturnTypeDesc = tree->gtReturnTypeDesc;
7565 #ifdef FEATURE_READYTORUN_COMPILER
7566 copy->setEntryPoint(tree->gtEntryPoint);
7569 #if defined(DEBUG) || defined(INLINE_DATA)
7570 copy->gtInlineObservation = tree->gtInlineObservation;
7571 copy->gtRawILOffset = tree->gtCall.gtRawILOffset;
7574 copy->CopyOtherRegFlags(tree);
7579 //------------------------------------------------------------------------
7580 // gtCloneCandidateCall: clone a call that is an inline or guarded
7581 // devirtualization candidate (~ any call that can have a GT_RET_EXPR)
7584 // If the call really is a candidate, the caller must take additional steps
7585 // after cloning to re-establish candidate info and the relationship between
7586 // the candidate and any associated GT_RET_EXPR.
7589 // call - the call to clone
7592 // Cloned copy of call and all subtrees.
7594 GenTreeCall* Compiler::gtCloneCandidateCall(GenTreeCall* call)
7596 assert(call->IsInlineCandidate() || call->IsGuardedDevirtualizationCandidate());
7598 GenTreeCall* result = gtCloneExprCallHelper(call);
7600 // There is some common post-processing in gtCloneExpr that we reproduce
7601 // here, for the fields that make sense for candidate calls.
7602 result->gtFlags |= call->gtFlags;
7605 result->gtDebugFlags |= (call->gtDebugFlags & ~GTF_DEBUG_NODE_MASK);
7608 result->CopyReg(call);
7613 //------------------------------------------------------------------------
7614 // gtReplaceTree: Replace a tree with a new tree.
7617 // stmt - The top-level root stmt of the tree being replaced.
7618 // Must not be null.
7619 // tree - The tree being replaced. Must not be null.
7620 // replacementTree - The replacement tree. Must not be null.
7623 // The tree node that replaces the old tree.
7626 // The sequencing of the stmt has been done.
7629 // The caller must ensure that the original statement has been sequenced,
7630 // and the side effect flags are updated on the statement nodes,
7631 // but this method will sequence 'replacementTree', and insert it into the
7632 // proper place in the statement sequence.
7634 GenTree* Compiler::gtReplaceTree(GenTree* stmt, GenTree* tree, GenTree* replacementTree)
7636 assert(fgStmtListThreaded);
7637 assert(tree != nullptr);
7638 assert(stmt != nullptr);
7639 assert(replacementTree != nullptr);
7641 GenTree** treePtr = nullptr;
7642 GenTree* treeParent = tree->gtGetParent(&treePtr);
7644 assert(treeParent != nullptr || tree == stmt->gtStmt.gtStmtExpr);
7646 if (treePtr == nullptr)
7648 // Replace the stmt expr and rebuild the linear order for "stmt".
7649 assert(treeParent == nullptr);
7650 assert(fgOrder != FGOrderLinear);
7651 stmt->gtStmt.gtStmtExpr = tree;
7656 assert(treeParent != nullptr);
7658 // Check to see if the node to be replaced is a call argument and if so,
7659 // set `treeParent` to the call node.
7660 GenTree* cursor = treeParent;
7661 while ((cursor != nullptr) && (cursor->OperGet() == GT_LIST))
7663 cursor = cursor->gtNext;
7666 if ((cursor != nullptr) && (cursor->OperGet() == GT_CALL))
7668 treeParent = cursor;
7673 assert(treeParent->TryGetUse(tree, &useEdge));
7674 assert(useEdge == treePtr);
7677 GenTree* treeFirstNode = fgGetFirstNode(tree);
7678 GenTree* treeLastNode = tree;
7679 GenTree* treePrevNode = treeFirstNode->gtPrev;
7680 GenTree* treeNextNode = treeLastNode->gtNext;
7682 treeParent->ReplaceOperand(treePtr, replacementTree);
7684 // Build the linear order for "replacementTree".
7685 fgSetTreeSeq(replacementTree, treePrevNode);
7687 // Restore linear-order Prev and Next for "replacementTree".
7688 if (treePrevNode != nullptr)
7690 treeFirstNode = fgGetFirstNode(replacementTree);
7691 treeFirstNode->gtPrev = treePrevNode;
7692 treePrevNode->gtNext = treeFirstNode;
7696 // Update the linear oder start of "stmt" if treeFirstNode
7697 // appears to have replaced the original first node.
7698 assert(treeFirstNode == stmt->gtStmt.gtStmtList);
7699 stmt->gtStmt.gtStmtList = fgGetFirstNode(replacementTree);
7702 if (treeNextNode != nullptr)
7704 treeLastNode = replacementTree;
7705 treeLastNode->gtNext = treeNextNode;
7706 treeNextNode->gtPrev = treeLastNode;
7710 return replacementTree;
7713 //------------------------------------------------------------------------
7714 // gtUpdateSideEffects: Update the side effects of a tree and its ancestors
7717 // stmt - The tree's statement
7718 // tree - Tree to update the side effects for
7720 // Note: If tree's order hasn't been established, the method updates side effect
7721 // flags on all statement's nodes.
7723 void Compiler::gtUpdateSideEffects(GenTree* stmt, GenTree* tree)
7725 if (fgStmtListThreaded)
7727 gtUpdateTreeAncestorsSideEffects(tree);
7731 gtUpdateStmtSideEffects(stmt);
7735 //------------------------------------------------------------------------
7736 // gtUpdateTreeAncestorsSideEffects: Update the side effects of a tree and its ancestors
7737 // when statement order has been established.
7740 // tree - Tree to update the side effects for
7742 void Compiler::gtUpdateTreeAncestorsSideEffects(GenTree* tree)
7744 assert(fgStmtListThreaded);
7745 while (tree != nullptr)
7747 gtUpdateNodeSideEffects(tree);
7748 tree = tree->gtGetParent(nullptr);
7752 //------------------------------------------------------------------------
7753 // gtUpdateStmtSideEffects: Update the side effects for statement tree nodes.
7756 // stmt - The statement to update side effects on
7758 void Compiler::gtUpdateStmtSideEffects(GenTree* stmt)
7760 fgWalkTree(&stmt->gtStmt.gtStmtExpr, fgUpdateSideEffectsPre, fgUpdateSideEffectsPost);
7763 //------------------------------------------------------------------------
7764 // gtUpdateNodeOperSideEffects: Update the side effects based on the node operation.
7767 // tree - Tree to update the side effects on
7770 // This method currently only updates GTF_EXCEPT, GTF_ASG, and GTF_CALL flags.
7771 // The other side effect flags may remain unnecessarily (conservatively) set.
7772 // The caller of this method is expected to update the flags based on the children's flags.
7774 void Compiler::gtUpdateNodeOperSideEffects(GenTree* tree)
7776 if (tree->OperMayThrow(this))
7778 tree->gtFlags |= GTF_EXCEPT;
7782 tree->gtFlags &= ~GTF_EXCEPT;
7783 if (tree->OperIsIndirOrArrLength())
7785 tree->gtFlags |= GTF_IND_NONFAULTING;
7789 if (tree->OperRequiresAsgFlag())
7791 tree->gtFlags |= GTF_ASG;
7795 tree->gtFlags &= ~GTF_ASG;
7798 if (tree->OperRequiresCallFlag(this))
7800 tree->gtFlags |= GTF_CALL;
7804 tree->gtFlags &= ~GTF_CALL;
7808 //------------------------------------------------------------------------
7809 // gtUpdateNodeSideEffects: Update the side effects based on the node operation and
7810 // children's side efects.
7813 // tree - Tree to update the side effects on
7816 // This method currently only updates GTF_EXCEPT and GTF_ASG flags. The other side effect
7817 // flags may remain unnecessarily (conservatively) set.
7819 void Compiler::gtUpdateNodeSideEffects(GenTree* tree)
7821 gtUpdateNodeOperSideEffects(tree);
7822 unsigned nChildren = tree->NumChildren();
7823 for (unsigned childNum = 0; childNum < nChildren; childNum++)
7825 GenTree* child = tree->GetChild(childNum);
7826 if (child != nullptr)
7828 tree->gtFlags |= (child->gtFlags & GTF_ALL_EFFECT);
7833 //------------------------------------------------------------------------
7834 // fgUpdateSideEffectsPre: Update the side effects based on the tree operation.
7837 // pTree - Pointer to the tree to update the side effects
7838 // fgWalkPre - Walk data
7841 // This method currently only updates GTF_EXCEPT and GTF_ASG flags. The other side effect
7842 // flags may remain unnecessarily (conservatively) set.
7844 Compiler::fgWalkResult Compiler::fgUpdateSideEffectsPre(GenTree** pTree, fgWalkData* fgWalkPre)
7846 fgWalkPre->compiler->gtUpdateNodeOperSideEffects(*pTree);
7848 return WALK_CONTINUE;
7851 //------------------------------------------------------------------------
7852 // fgUpdateSideEffectsPost: Update the side effects of the parent based on the tree's flags.
7855 // pTree - Pointer to the tree
7856 // fgWalkPost - Walk data
7859 // The routine is used for updating the stale side effect flags for ancestor
7860 // nodes starting from treeParent up to the top-level stmt expr.
7862 Compiler::fgWalkResult Compiler::fgUpdateSideEffectsPost(GenTree** pTree, fgWalkData* fgWalkPost)
7864 GenTree* tree = *pTree;
7865 GenTree* parent = fgWalkPost->parent;
7866 if (parent != nullptr)
7868 parent->gtFlags |= (tree->gtFlags & GTF_ALL_EFFECT);
7870 return WALK_CONTINUE;
7873 /*****************************************************************************
7875 * Compares two trees and returns true when both trees are the same.
7876 * Instead of fully comparing the two trees this method can just return false.
7877 * Thus callers should not assume that the trees are different when false is returned.
7878 * Only when true is returned can the caller perform code optimizations.
7879 * The current implementation only compares a limited set of LEAF/CONST node
7880 * and returns false for all othere trees.
7882 bool Compiler::gtCompareTree(GenTree* op1, GenTree* op2)
7884 /* Make sure that both trees are of the same GT node kind */
7885 if (op1->OperGet() != op2->OperGet())
7890 /* Make sure that both trees are returning the same type */
7891 if (op1->gtType != op2->gtType)
7896 /* Figure out what kind of a node we have */
7898 genTreeOps oper = op1->OperGet();
7899 unsigned kind = op1->OperKind();
7901 /* Is this a constant or leaf node? */
7903 if (kind & (GTK_CONST | GTK_LEAF))
7908 if ((op1->gtIntCon.gtIconVal == op2->gtIntCon.gtIconVal) && GenTree::SameIconHandleFlag(op1, op2))
7915 if (op1->gtLngCon.gtLconVal == op2->gtLngCon.gtLconVal)
7922 if (op1->gtStrCon.gtSconCPX == op2->gtStrCon.gtSconCPX)
7929 if (op1->gtLclVarCommon.gtLclNum == op2->gtLclVarCommon.gtLclNum)
7936 if (op1->gtClsVar.gtClsVarHnd == op2->gtClsVar.gtClsVarHnd)
7943 // we return false for these unhandled 'oper' kinds
7950 GenTree* Compiler::gtGetThisArg(GenTreeCall* call)
7952 if (call->gtCallObjp != nullptr)
7954 if (call->gtCallObjp->gtOper != GT_NOP && call->gtCallObjp->gtOper != GT_ASG)
7956 if (!(call->gtCallObjp->gtFlags & GTF_LATE_ARG))
7958 return call->gtCallObjp;
7962 if (call->gtCallLateArgs)
7964 regNumber thisReg = REG_ARG_0;
7965 unsigned argNum = 0;
7966 fgArgTabEntry* thisArgTabEntry = gtArgEntryByArgNum(call, argNum);
7967 GenTree* result = thisArgTabEntry->node;
7969 #if !FEATURE_FIXED_OUT_ARGS
7970 GenTree* lateArgs = call->gtCallLateArgs;
7971 regList list = call->regArgList;
7973 while (lateArgs != NULL)
7975 assert(lateArgs->gtOper == GT_LIST);
7976 assert(index < call->regArgListCount);
7977 regNumber curArgReg = list[index];
7978 if (curArgReg == thisReg)
7980 if (optAssertionPropagatedCurrentStmt)
7981 result = lateArgs->gtOp.gtOp1;
7983 assert(result == lateArgs->gtOp.gtOp1);
7986 lateArgs = lateArgs->gtOp.gtOp2;
7996 bool GenTree::gtSetFlags() const
7999 // When FEATURE_SET_FLAGS (_TARGET_ARM_) is active the method returns true
8000 // when the gtFlags has the flag GTF_SET_FLAGS set
8001 // otherwise the architecture will be have instructions that typically set
8002 // the flags and this method will return true.
8004 // Exceptions: GT_IND (load/store) is not allowed to set the flags
8005 // and on XARCH the GT_MUL/GT_DIV and all overflow instructions
8006 // do not set the condition flags
8008 // Precondition we have a GTK_SMPOP
8010 if (!varTypeIsIntegralOrI(TypeGet()) && (TypeGet() != TYP_VOID))
8015 if (((gtFlags & GTF_SET_FLAGS) != 0) && (gtOper != GT_IND))
8017 // GTF_SET_FLAGS is not valid on GT_IND and is overlaid with GTF_NONFAULTING_IND
8026 bool GenTree::gtRequestSetFlags()
8028 bool result = false;
8030 #if FEATURE_SET_FLAGS
8031 // This method is a Nop unless FEATURE_SET_FLAGS is defined
8033 // In order to set GTF_SET_FLAGS
8034 // we must have a GTK_SMPOP
8035 // and we have a integer or machine size type (not floating point or TYP_LONG on 32-bit)
8037 if (!OperIsSimple())
8040 if (!varTypeIsIntegralOrI(TypeGet()))
8047 // These will turn into simple load from memory instructions
8048 // and we can't force the setting of the flags on load from memory
8053 // These instructions don't set the flags (on x86/x64)
8058 // Otherwise we can set the flags for this gtOper
8059 // and codegen must set the condition flags.
8061 gtFlags |= GTF_SET_FLAGS;
8065 #endif // FEATURE_SET_FLAGS
8067 // Codegen for this tree must set the condition flags if
8068 // this method returns true.
8073 unsigned GenTree::NumChildren()
8075 if (OperIsConst() || OperIsLeaf())
8079 else if (OperIsUnary())
8081 if (OperGet() == GT_NOP || OperGet() == GT_RETURN || OperGet() == GT_RETFILT)
8083 if (gtOp.gtOp1 == nullptr)
8097 else if (OperIsBinary())
8099 // All binary operators except LEA have at least one arg; the second arg may sometimes be null, however.
8100 if (OperGet() == GT_LEA)
8102 unsigned childCount = 0;
8103 if (gtOp.gtOp1 != nullptr)
8107 if (gtOp.gtOp2 != nullptr)
8113 #ifdef FEATURE_HW_INTRINSICS
8114 // GT_HWIntrinsic require special handling
8115 if (OperGet() == GT_HWIntrinsic)
8117 if (gtOp.gtOp1 == nullptr)
8123 assert(gtOp.gtOp1 != nullptr);
8124 if (gtOp.gtOp2 == nullptr)
8141 case GT_ARR_BOUNDS_CHECK:
8144 #endif // FEATURE_SIMD
8145 #ifdef FEATURE_HW_INTRINSICS
8146 case GT_HW_INTRINSIC_CHK:
8147 #endif // FEATURE_HW_INTRINSICS
8155 return 1 + AsArrElem()->gtArrRank;
8161 case GT_STORE_DYN_BLK:
8166 GenTreeCall* call = AsCall();
8167 unsigned res = 0; // arg list(s) (including late args).
8168 if (call->gtCallObjp != nullptr)
8172 if (call->gtCallArgs != nullptr)
8176 if (call->gtCallLateArgs != nullptr)
8178 res++; // Add late args?
8180 if (call->gtControlExpr != nullptr)
8185 if (call->gtCallType == CT_INDIRECT)
8187 if (call->gtCallCookie != nullptr)
8191 if (call->gtCallAddr != nullptr)
8206 GenTree* GenTree::GetChild(unsigned childNum)
8208 assert(childNum < NumChildren()); // Precondition.
8209 assert(NumChildren() <= MAX_CHILDREN);
8210 assert(!(OperIsConst() || OperIsLeaf()));
8213 return AsUnOp()->gtOp1;
8215 // Special case for assignment of dynamic block.
8216 // This code is here to duplicate the former case where the size may be evaluated prior to the
8217 // source and destination addresses. In order to do this, we treat the size as a child of the
8219 // TODO-1stClassStructs: Revisit the need to duplicate former behavior, so that we can remove
8220 // these special cases.
8221 if ((OperGet() == GT_ASG) && (gtOp.gtOp1->OperGet() == GT_DYN_BLK) && (childNum == 2))
8223 return gtOp.gtOp1->AsDynBlk()->gtDynamicSize;
8225 else if (OperIsBinary())
8227 if (OperIsAddrMode())
8229 // If this is the first (0th) child, only return op1 if it is non-null
8230 // Otherwise, we return gtOp2.
8231 if (childNum == 0 && AsOp()->gtOp1 != nullptr)
8233 return AsOp()->gtOp1;
8235 return AsOp()->gtOp2;
8237 // TODO-Cleanup: Consider handling ReverseOps here, and then we wouldn't have to handle it in
8238 // fgGetFirstNode(). However, it seems that it causes loop hoisting behavior to change.
8241 return AsOp()->gtOp1;
8245 return AsOp()->gtOp2;
8257 return AsCmpXchg()->gtOpLocation;
8259 return AsCmpXchg()->gtOpValue;
8261 return AsCmpXchg()->gtOpComparand;
8265 case GT_ARR_BOUNDS_CHECK:
8268 #endif // FEATURE_SIMD
8269 #ifdef FEATURE_HW_INTRINSICS
8270 case GT_HW_INTRINSIC_CHK:
8271 #endif // FEATURE_HW_INTRINSICS
8275 return AsBoundsChk()->gtIndex;
8277 return AsBoundsChk()->gtArrLen;
8282 case GT_STORE_DYN_BLK:
8286 return AsDynBlk()->Addr();
8288 return AsDynBlk()->Data();
8290 return AsDynBlk()->gtDynamicSize;
8298 return AsDynBlk()->gtEvalSizeFirst ? AsDynBlk()->gtDynamicSize : AsDynBlk()->Addr();
8300 return AsDynBlk()->gtEvalSizeFirst ? AsDynBlk()->Addr() : AsDynBlk()->gtDynamicSize;
8306 return AsField()->gtFldObj;
8309 return AsStmt()->gtStmtExpr;
8314 return AsArrElem()->gtArrObj;
8318 return AsArrElem()->gtArrInds[childNum - 1];
8325 return AsArrOffs()->gtOffset;
8327 return AsArrOffs()->gtIndex;
8329 return AsArrOffs()->gtArrObj;
8336 // The if chain below assumes that all possible children are non-null.
8337 // If some are null, "virtually skip them."
8338 // If there isn't "virtually skip it."
8339 GenTreeCall* call = AsCall();
8341 if (call->gtCallObjp == nullptr)
8345 if (childNum >= 1 && call->gtCallArgs == nullptr)
8349 if (childNum >= 2 && call->gtCallLateArgs == nullptr)
8353 if (childNum >= 3 && call->gtControlExpr == nullptr)
8357 if (call->gtCallType == CT_INDIRECT)
8359 if (childNum >= 4 && call->gtCallCookie == nullptr)
8367 return call->gtCallObjp;
8369 else if (childNum == 1)
8371 return call->gtCallArgs;
8373 else if (childNum == 2)
8375 return call->gtCallLateArgs;
8377 else if (childNum == 3)
8379 return call->gtControlExpr;
8383 assert(call->gtCallType == CT_INDIRECT);
8386 return call->gtCallCookie;
8390 assert(childNum == 5);
8391 return call->gtCallAddr;
8403 GenTreeUseEdgeIterator::GenTreeUseEdgeIterator()
8404 : m_advance(nullptr), m_node(nullptr), m_edge(nullptr), m_argList(nullptr), m_state(-1)
8408 GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node)
8409 : m_advance(nullptr), m_node(node), m_edge(nullptr), m_argList(nullptr), m_state(0)
8411 assert(m_node != nullptr);
8413 // NOTE: the switch statement below must be updated when introducing new nodes.
8415 switch (m_node->OperGet())
8420 case GT_LCL_VAR_ADDR:
8421 case GT_LCL_FLD_ADDR:
8430 case GT_MEMORYBARRIER:
8435 case GT_START_NONGC:
8437 #if !FEATURE_EH_FUNCLETS
8439 #endif // !FEATURE_EH_FUNCLETS
8443 case GT_CLS_VAR_ADDR:
8447 case GT_PINVOKE_PROLOG:
8448 case GT_PINVOKE_EPILOG:
8453 // Standard unary operators
8454 case GT_STORE_LCL_VAR:
8455 case GT_STORE_LCL_FLD:
8471 case GT_RUNTIMELOOKUP:
8480 #if FEATURE_ARG_SPLIT
8481 case GT_PUTARG_SPLIT:
8482 #endif // FEATURE_ARG_SPLIT
8484 m_edge = &m_node->AsUnOp()->gtOp1;
8485 assert(*m_edge != nullptr);
8486 m_advance = &GenTreeUseEdgeIterator::Terminate;
8489 // Unary operators with an optional operand
8493 if (m_node->AsUnOp()->gtOp1 == nullptr)
8495 assert(m_node->NullOp1Legal());
8500 m_edge = &m_node->AsUnOp()->gtOp1;
8501 m_advance = &GenTreeUseEdgeIterator::Terminate;
8507 SetEntryStateForList(m_node->AsUnOp()->gtOp1);
8511 SetEntryStateForList(m_node);
8516 if (m_node->AsSIMD()->gtSIMDIntrinsicID == SIMDIntrinsicInitN)
8518 SetEntryStateForList(m_node->AsSIMD()->gtOp1);
8522 SetEntryStateForBinOp();
8525 #endif // FEATURE_SIMD
8527 #ifdef FEATURE_HW_INTRINSICS
8528 case GT_HWIntrinsic:
8529 if (m_node->AsHWIntrinsic()->gtOp1 == nullptr)
8531 assert(m_node->NullOp1Legal());
8534 else if (m_node->AsHWIntrinsic()->gtOp1->OperIsList())
8536 SetEntryStateForList(m_node->AsHWIntrinsic()->gtOp1);
8540 SetEntryStateForBinOp();
8543 #endif // FEATURE_HW_INTRINSICS
8545 // LEA, which may have no first operand
8547 if (m_node->AsAddrMode()->gtOp1 == nullptr)
8549 m_edge = &m_node->AsAddrMode()->gtOp2;
8550 m_advance = &GenTreeUseEdgeIterator::Terminate;
8554 SetEntryStateForBinOp();
8560 m_edge = &m_node->AsCmpXchg()->gtOpLocation;
8561 assert(*m_edge != nullptr);
8562 m_advance = &GenTreeUseEdgeIterator::AdvanceCmpXchg;
8565 case GT_ARR_BOUNDS_CHECK:
8568 #endif // FEATURE_SIMD
8569 #ifdef FEATURE_HW_INTRINSICS
8570 case GT_HW_INTRINSIC_CHK:
8571 #endif // FEATURE_HW_INTRINSICS
8572 m_edge = &m_node->AsBoundsChk()->gtIndex;
8573 assert(*m_edge != nullptr);
8574 m_advance = &GenTreeUseEdgeIterator::AdvanceBoundsChk;
8578 if (m_node->AsField()->gtFldObj == nullptr)
8584 m_edge = &m_node->AsField()->gtFldObj;
8585 m_advance = &GenTreeUseEdgeIterator::Terminate;
8590 if (m_node->AsStmt()->gtStmtExpr == nullptr)
8596 m_edge = &m_node->AsStmt()->gtStmtExpr;
8597 m_advance = &GenTreeUseEdgeIterator::Terminate;
8602 m_edge = &m_node->AsArrElem()->gtArrObj;
8603 assert(*m_edge != nullptr);
8604 m_advance = &GenTreeUseEdgeIterator::AdvanceArrElem;
8608 m_edge = &m_node->AsArrOffs()->gtOffset;
8609 assert(*m_edge != nullptr);
8610 m_advance = &GenTreeUseEdgeIterator::AdvanceArrOffset;
8615 GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
8616 m_edge = dynBlock->gtEvalSizeFirst ? &dynBlock->gtDynamicSize : &dynBlock->gtOp1;
8617 assert(*m_edge != nullptr);
8618 m_advance = &GenTreeUseEdgeIterator::AdvanceDynBlk;
8622 case GT_STORE_DYN_BLK:
8624 GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
8625 if (dynBlock->gtEvalSizeFirst)
8627 m_edge = &dynBlock->gtDynamicSize;
8631 m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp2 : &dynBlock->gtOp1;
8633 assert(*m_edge != nullptr);
8635 m_advance = &GenTreeUseEdgeIterator::AdvanceStoreDynBlk;
8640 AdvanceCall<CALL_INSTANCE>();
8645 assert(m_node->OperIsBinary());
8646 SetEntryStateForBinOp();
8651 //------------------------------------------------------------------------
8652 // GenTreeUseEdgeIterator::AdvanceCmpXchg: produces the next operand of a CmpXchg node and advances the state.
8654 void GenTreeUseEdgeIterator::AdvanceCmpXchg()
8659 m_edge = &m_node->AsCmpXchg()->gtOpValue;
8663 m_edge = &m_node->AsCmpXchg()->gtOpComparand;
8664 m_advance = &GenTreeUseEdgeIterator::Terminate;
8670 assert(*m_edge != nullptr);
8673 //------------------------------------------------------------------------
8674 // GenTreeUseEdgeIterator::AdvanceBoundsChk: produces the next operand of a BoundsChk node and advances the state.
8676 void GenTreeUseEdgeIterator::AdvanceBoundsChk()
8678 m_edge = &m_node->AsBoundsChk()->gtArrLen;
8679 assert(*m_edge != nullptr);
8680 m_advance = &GenTreeUseEdgeIterator::Terminate;
8683 //------------------------------------------------------------------------
8684 // GenTreeUseEdgeIterator::AdvanceArrElem: produces the next operand of a ArrElem node and advances the state.
8686 // Because these nodes are variadic, this function uses `m_state` to index into the list of array indices.
8688 void GenTreeUseEdgeIterator::AdvanceArrElem()
8690 if (m_state < m_node->AsArrElem()->gtArrRank)
8692 m_edge = &m_node->AsArrElem()->gtArrInds[m_state];
8693 assert(*m_edge != nullptr);
8702 //------------------------------------------------------------------------
8703 // GenTreeUseEdgeIterator::AdvanceArrOffset: produces the next operand of a ArrOffset node and advances the state.
8705 void GenTreeUseEdgeIterator::AdvanceArrOffset()
8710 m_edge = &m_node->AsArrOffs()->gtIndex;
8714 m_edge = &m_node->AsArrOffs()->gtArrObj;
8715 m_advance = &GenTreeUseEdgeIterator::Terminate;
8721 assert(*m_edge != nullptr);
8724 //------------------------------------------------------------------------
8725 // GenTreeUseEdgeIterator::AdvanceDynBlk: produces the next operand of a DynBlk node and advances the state.
8727 void GenTreeUseEdgeIterator::AdvanceDynBlk()
8729 GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
8731 m_edge = dynBlock->gtEvalSizeFirst ? &dynBlock->gtOp1 : &dynBlock->gtDynamicSize;
8732 assert(*m_edge != nullptr);
8733 m_advance = &GenTreeUseEdgeIterator::Terminate;
8736 //------------------------------------------------------------------------
8737 // GenTreeUseEdgeIterator::AdvanceStoreDynBlk: produces the next operand of a StoreDynBlk node and advances the state.
8739 // These nodes are moderately complicated but rare enough that templating this function is probably not
8740 // worth the extra complexity.
8742 void GenTreeUseEdgeIterator::AdvanceStoreDynBlk()
8744 GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
8745 if (dynBlock->gtEvalSizeFirst)
8750 m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp2 : &dynBlock->gtOp1;
8754 m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp1 : &dynBlock->gtOp2;
8755 m_advance = &GenTreeUseEdgeIterator::Terminate;
8766 m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp1 : &dynBlock->gtOp2;
8770 m_edge = &dynBlock->gtDynamicSize;
8771 m_advance = &GenTreeUseEdgeIterator::Terminate;
8778 assert(*m_edge != nullptr);
8781 //------------------------------------------------------------------------
8782 // GenTreeUseEdgeIterator::AdvanceBinOp: produces the next operand of a binary node and advances the state.
8784 // This function must be instantiated s.t. `ReverseOperands` is `true` iff the node is marked with the
8785 // `GTF_REVERSE_OPS` flag.
8787 template <bool ReverseOperands>
8788 void GenTreeUseEdgeIterator::AdvanceBinOp()
8790 assert(ReverseOperands == ((m_node->gtFlags & GTF_REVERSE_OPS) != 0));
8792 m_edge = !ReverseOperands ? &m_node->AsOp()->gtOp2 : &m_node->AsOp()->gtOp1;
8793 assert(*m_edge != nullptr);
8794 m_advance = &GenTreeUseEdgeIterator::Terminate;
8797 //------------------------------------------------------------------------
8798 // GenTreeUseEdgeIterator::SetEntryStateForBinOp: produces the first operand of a binary node and chooses
8799 // the appropriate advance function.
8801 void GenTreeUseEdgeIterator::SetEntryStateForBinOp()
8803 assert(m_node != nullptr);
8804 assert(m_node->OperIsBinary());
8806 GenTreeOp* const node = m_node->AsOp();
8808 if (node->gtOp2 == nullptr)
8810 assert(node->gtOp1 != nullptr);
8811 assert(node->NullOp2Legal());
8812 m_edge = &node->gtOp1;
8813 m_advance = &GenTreeUseEdgeIterator::Terminate;
8815 else if ((node->gtFlags & GTF_REVERSE_OPS) != 0)
8817 m_edge = &m_node->AsOp()->gtOp2;
8818 m_advance = &GenTreeUseEdgeIterator::AdvanceBinOp<true>;
8822 m_edge = &m_node->AsOp()->gtOp1;
8823 m_advance = &GenTreeUseEdgeIterator::AdvanceBinOp<false>;
8827 //------------------------------------------------------------------------
8828 // GenTreeUseEdgeIterator::AdvanceList: produces the next operand of a variadic node and advances the state.
8830 // This function does not use `m_state` for anything meaningful; it simply walks the `m_argList` until
8831 // there are no further entries.
8833 void GenTreeUseEdgeIterator::AdvanceList()
8835 assert(m_state == 0);
8837 if (m_argList == nullptr)
8843 GenTreeArgList* listNode = m_argList->AsArgList();
8844 m_edge = &listNode->gtOp1;
8845 m_argList = listNode->Rest();
8849 //------------------------------------------------------------------------
8850 // GenTreeUseEdgeIterator::SetEntryStateForList: produces the first operand of a list node.
8852 void GenTreeUseEdgeIterator::SetEntryStateForList(GenTree* list)
8855 m_advance = &GenTreeUseEdgeIterator::AdvanceList;
8859 //------------------------------------------------------------------------
8860 // GenTreeUseEdgeIterator::AdvanceCall: produces the next operand of a call node and advances the state.
8862 // This function is a bit tricky: in order to avoid doing unnecessary work, it is instantiated with the
8863 // state number the iterator will be in when it is called. For example, `AdvanceCall<CALL_INSTANCE>`
8864 // is the instantiation used when the iterator is at the `CALL_INSTANCE` state (i.e. the entry state).
8865 // This sort of templating allows each state to avoid processing earlier states without unnecessary
8866 // duplication of code.
8868 // Note that this method expands the argument lists (`gtCallArgs` and `gtCallLateArgs`) into their
8869 // component operands.
8871 template <int state>
8872 void GenTreeUseEdgeIterator::AdvanceCall()
8874 GenTreeCall* const call = m_node->AsCall();
8879 m_argList = call->gtCallArgs;
8880 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_ARGS>;
8881 if (call->gtCallObjp != nullptr)
8883 m_edge = &call->gtCallObjp;
8889 if (m_argList != nullptr)
8891 GenTreeArgList* argNode = m_argList->AsArgList();
8892 m_edge = &argNode->gtOp1;
8893 m_argList = argNode->Rest();
8896 m_argList = call->gtCallLateArgs;
8897 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_LATE_ARGS>;
8900 case CALL_LATE_ARGS:
8901 if (m_argList != nullptr)
8903 GenTreeArgList* argNode = m_argList->AsArgList();
8904 m_edge = &argNode->gtOp1;
8905 m_argList = argNode->Rest();
8908 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_CONTROL_EXPR>;
8911 case CALL_CONTROL_EXPR:
8912 if (call->gtControlExpr != nullptr)
8914 if (call->gtCallType == CT_INDIRECT)
8916 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_COOKIE>;
8920 m_advance = &GenTreeUseEdgeIterator::Terminate;
8922 m_edge = &call->gtControlExpr;
8925 else if (call->gtCallType != CT_INDIRECT)
8933 assert(call->gtCallType == CT_INDIRECT);
8935 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_ADDRESS>;
8936 if (call->gtCallCookie != nullptr)
8938 m_edge = &call->gtCallCookie;
8944 assert(call->gtCallType == CT_INDIRECT);
8946 m_advance = &GenTreeUseEdgeIterator::Terminate;
8947 if (call->gtCallAddr != nullptr)
8949 m_edge = &call->gtCallAddr;
8958 //------------------------------------------------------------------------
8959 // GenTreeUseEdgeIterator::Terminate: advances the iterator to the terminal state.
8961 void GenTreeUseEdgeIterator::Terminate()
8966 //------------------------------------------------------------------------
8967 // GenTreeUseEdgeIterator::operator++: advances the iterator to the next operand.
8969 GenTreeUseEdgeIterator& GenTreeUseEdgeIterator::operator++()
8971 // If we've reached the terminal state, do nothing.
8974 (this->*m_advance)();
8980 GenTreeUseEdgeIterator GenTree::UseEdgesBegin()
8982 return GenTreeUseEdgeIterator(this);
8985 GenTreeUseEdgeIterator GenTree::UseEdgesEnd()
8987 return GenTreeUseEdgeIterator();
8990 IteratorPair<GenTreeUseEdgeIterator> GenTree::UseEdges()
8992 return MakeIteratorPair(UseEdgesBegin(), UseEdgesEnd());
8995 GenTreeOperandIterator GenTree::OperandsBegin()
8997 return GenTreeOperandIterator(this);
9000 GenTreeOperandIterator GenTree::OperandsEnd()
9002 return GenTreeOperandIterator();
9005 IteratorPair<GenTreeOperandIterator> GenTree::Operands()
9007 return MakeIteratorPair(OperandsBegin(), OperandsEnd());
9010 bool GenTree::Precedes(GenTree* other)
9012 assert(other != nullptr);
9014 for (GenTree* node = gtNext; node != nullptr; node = node->gtNext)
9027 /* static */ int GenTree::gtDispFlags(unsigned flags, unsigned debugFlags)
9029 int charsDisplayed = 11; // 11 is the "baseline" number of flag characters displayed
9031 printf("%c", (flags & GTF_ASG) ? 'A' : (IsContained(flags) ? 'c' : '-'));
9032 printf("%c", (flags & GTF_CALL) ? 'C' : '-');
9033 printf("%c", (flags & GTF_EXCEPT) ? 'X' : '-');
9034 printf("%c", (flags & GTF_GLOB_REF) ? 'G' : '-');
9035 printf("%c", (debugFlags & GTF_DEBUG_NODE_MORPHED) ? '+' : // First print '+' if GTF_DEBUG_NODE_MORPHED is set
9036 (flags & GTF_ORDER_SIDEEFF) ? 'O' : '-'); // otherwise print 'O' or '-'
9037 printf("%c", (flags & GTF_COLON_COND) ? '?' : '-');
9038 printf("%c", (flags & GTF_DONT_CSE) ? 'N' : // N is for No cse
9039 (flags & GTF_MAKE_CSE) ? 'H' : '-'); // H is for Hoist this expr
9040 printf("%c", (flags & GTF_REVERSE_OPS) ? 'R' : '-');
9041 printf("%c", (flags & GTF_UNSIGNED) ? 'U' : (flags & GTF_BOOLEAN) ? 'B' : '-');
9042 #if FEATURE_SET_FLAGS
9043 printf("%c", (flags & GTF_SET_FLAGS) ? 'S' : '-');
9046 printf("%c", (flags & GTF_LATE_ARG) ? 'L' : '-');
9047 printf("%c", (flags & GTF_SPILLED) ? 'z' : (flags & GTF_SPILL) ? 'Z' : '-');
9049 return charsDisplayed;
9052 /*****************************************************************************/
9054 void Compiler::gtDispNodeName(GenTree* tree)
9056 /* print the node name */
9061 if (tree->gtOper < GT_COUNT)
9063 name = GenTree::OpName(tree->OperGet());
9070 char* bufp = &buf[0];
9072 if ((tree->gtOper == GT_CNS_INT) && tree->IsIconHandle())
9074 sprintf_s(bufp, sizeof(buf), " %s(h)%c", name, 0);
9076 else if (tree->gtOper == GT_PUTARG_STK)
9078 sprintf_s(bufp, sizeof(buf), " %s [+0x%02x]%c", name, tree->AsPutArgStk()->getArgOffset(), 0);
9080 else if (tree->gtOper == GT_CALL)
9082 const char* callType = "CALL";
9083 const char* gtfType = "";
9084 const char* ctType = "";
9085 char gtfTypeBuf[100];
9087 if (tree->gtCall.gtCallType == CT_USER_FUNC)
9089 if (tree->gtCall.IsVirtual())
9094 else if (tree->gtCall.gtCallType == CT_HELPER)
9098 else if (tree->gtCall.gtCallType == CT_INDIRECT)
9104 assert(!"Unknown gtCallType");
9107 if (tree->gtFlags & GTF_CALL_NULLCHECK)
9109 gtfType = " nullcheck";
9111 if (tree->gtCall.IsVirtualVtable())
9115 else if (tree->gtCall.IsVirtualStub())
9119 #ifdef FEATURE_READYTORUN_COMPILER
9120 else if (tree->gtCall.IsR2RRelativeIndir())
9122 gtfType = " r2r_ind";
9124 #endif // FEATURE_READYTORUN_COMPILER
9125 else if (tree->gtFlags & GTF_CALL_UNMANAGED)
9127 char* gtfTypeBufWalk = gtfTypeBuf;
9128 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " unman");
9129 if (tree->gtFlags & GTF_CALL_POP_ARGS)
9131 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " popargs");
9133 if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
9135 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " thiscall");
9137 gtfType = gtfTypeBuf;
9140 sprintf_s(bufp, sizeof(buf), " %s%s%s%c", callType, ctType, gtfType, 0);
9142 else if (tree->gtOper == GT_ARR_ELEM)
9144 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s[", name);
9145 for (unsigned rank = tree->gtArrElem.gtArrRank - 1; rank; rank--)
9147 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), ",");
9149 SimpleSprintf_s(bufp, buf, sizeof(buf), "]");
9151 else if (tree->gtOper == GT_ARR_OFFSET || tree->gtOper == GT_ARR_INDEX)
9153 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s[", name);
9154 unsigned char currDim;
9156 if (tree->gtOper == GT_ARR_OFFSET)
9158 currDim = tree->gtArrOffs.gtCurrDim;
9159 rank = tree->gtArrOffs.gtArrRank;
9163 currDim = tree->gtArrIndex.gtCurrDim;
9164 rank = tree->gtArrIndex.gtArrRank;
9167 for (unsigned char dim = 0; dim < rank; dim++)
9169 // Use a defacto standard i,j,k for the dimensions.
9170 // Note that we only support up to rank 3 arrays with these nodes, so we won't run out of characters.
9174 dimChar = 'i' + dim;
9176 else if (dim > currDim)
9181 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "%c", dimChar);
9182 if (dim != rank - 1)
9184 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), ",");
9187 SimpleSprintf_s(bufp, buf, sizeof(buf), "]");
9189 else if (tree->gtOper == GT_LEA)
9191 GenTreeAddrMode* lea = tree->AsAddrMode();
9192 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s(", name);
9193 if (lea->Base() != nullptr)
9195 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "b+");
9197 if (lea->Index() != nullptr)
9199 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "(i*%d)+", lea->gtScale);
9201 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "%d)", lea->Offset());
9203 else if (tree->gtOper == GT_ARR_BOUNDS_CHECK)
9205 switch (tree->gtBoundsChk.gtThrowKind)
9207 case SCK_RNGCHK_FAIL:
9208 sprintf_s(bufp, sizeof(buf), " %s_Rng", name);
9211 sprintf_s(bufp, sizeof(buf), " %s_Arg", name);
9213 case SCK_ARG_RNG_EXCPN:
9214 sprintf_s(bufp, sizeof(buf), " %s_ArgRng", name);
9220 else if (tree->gtOverflowEx())
9222 sprintf_s(bufp, sizeof(buf), " %s_ovfl%c", name, 0);
9224 else if (tree->OperIsBlk() && !tree->OperIsDynBlk())
9226 sprintf_s(bufp, sizeof(buf), " %s(%d)", name, tree->AsBlk()->gtBlkSize);
9230 sprintf_s(bufp, sizeof(buf), " %s%c", name, 0);
9233 if (strlen(buf) < 10)
9235 printf(" %-10s", buf);
9243 void Compiler::gtDispVN(GenTree* tree)
9245 if (tree->gtVNPair.GetLiberal() != ValueNumStore::NoVN)
9247 assert(tree->gtVNPair.GetConservative() != ValueNumStore::NoVN);
9249 vnpPrint(tree->gtVNPair, 0);
9253 //------------------------------------------------------------------------
9254 // gtDispNode: Print a tree to jitstdout.
9257 // tree - the tree to be printed
9258 // indentStack - the specification for the current level of indentation & arcs
9259 // msg - a contextual method (i.e. from the parent) to print
9265 // 'indentStack' may be null, in which case no indentation or arcs are printed
9266 // 'msg' may be null
9268 void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, __in __in_z __in_opt const char* msg, bool isLIR)
9270 bool printPointer = true; // always true..
9271 bool printFlags = true; // always true..
9272 bool printCost = true; // always true..
9280 printf("N%03u ", tree->gtSeqNum);
9281 if (tree->gtCostsInitialized)
9283 printf("(%3u,%3u) ", tree->gtCostEx, tree->gtCostSz);
9289 ") "); // This probably indicates a bug: the node has a sequence number, but not costs.
9294 if (tree->gtOper == GT_STMT)
9296 prev = tree->gtStmt.gtStmtExpr;
9303 bool hasSeqNum = true;
9304 unsigned dotNum = 0;
9308 prev = prev->gtPrev;
9310 if ((prev == nullptr) || (prev == tree))
9317 } while (prev->gtSeqNum == 0);
9319 // If we have an indent stack, don't add additional characters,
9320 // as it will mess up the alignment.
9321 bool displayDotNum = tree->gtOper != GT_STMT && hasSeqNum && (indentStack == nullptr);
9324 printf("N%03u.%02u ", prev->gtSeqNum, dotNum);
9331 if (tree->gtCostsInitialized)
9333 printf("(%3u,%3u) ", tree->gtCostEx, tree->gtCostSz);
9339 // Do better alignment in this case
9349 if (optValnumCSE_phase)
9351 if (IS_CSE_INDEX(tree->gtCSEnum))
9353 printf("CSE #%02d (%s)", GET_CSE_INDEX(tree->gtCSEnum), (IS_CSE_USE(tree->gtCSEnum) ? "use" : "def"));
9361 /* Print the node ID */
9365 if (tree->gtOper >= GT_COUNT)
9367 printf(" **** ILLEGAL NODE ****");
9373 /* First print the flags associated with the node */
9374 switch (tree->gtOper)
9382 case GT_STORE_DYN_BLK:
9385 // We prefer printing V or U
9386 if ((tree->gtFlags & (GTF_IND_VOLATILE | GTF_IND_UNALIGNED)) == 0)
9388 if (tree->gtFlags & GTF_IND_TGTANYWHERE)
9394 if (tree->gtFlags & GTF_IND_INVARIANT)
9400 if (tree->gtFlags & GTF_IND_ARR_INDEX)
9406 if (tree->gtFlags & GTF_IND_NONFAULTING)
9408 printf("n"); // print a n for non-faulting
9412 if (tree->gtFlags & GTF_IND_ASG_LHS)
9414 printf("D"); // print a D for definition
9424 if ((tree->gtFlags & (GTF_IND_VOLATILE | GTF_IND_UNALIGNED)) == 0) // We prefer printing V or U over R
9426 if (tree->gtFlags & GTF_INX_REFARR_LAYOUT)
9431 } // R means RefArray
9437 if (tree->gtFlags & GTF_IND_VOLATILE)
9443 if (tree->gtFlags & GTF_IND_UNALIGNED)
9452 if (tree->OperIsInitBlkOp())
9461 if (tree->gtCall.IsInlineCandidate())
9463 if (tree->gtCall.IsGuardedDevirtualizationCandidate())
9474 else if (tree->gtCall.IsGuardedDevirtualizationCandidate())
9480 if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_RETBUFFARG)
9486 if (tree->gtFlags & GTF_CALL_HOISTABLE)
9496 #if !defined(_TARGET_64BIT_)
9499 if (tree->gtFlags & GTF_MUL_64RSLT)
9508 if (tree->gtFlags & GTF_ADDR_ONSTACK)
9518 case GT_LCL_VAR_ADDR:
9519 case GT_LCL_FLD_ADDR:
9520 case GT_STORE_LCL_FLD:
9521 case GT_STORE_LCL_VAR:
9522 if (tree->gtFlags & GTF_VAR_USEASG)
9528 if (tree->gtFlags & GTF_VAR_DEF)
9534 if (tree->gtFlags & GTF_VAR_CAST)
9540 if (tree->gtFlags & GTF_VAR_ARR_INDEX)
9556 if (tree->gtFlags & GTF_RELOP_NAN_UN)
9562 if (tree->gtFlags & GTF_RELOP_JMP_USED)
9568 if (tree->gtFlags & GTF_RELOP_QMARK)
9577 printf((tree->gtFlags & GTF_JCMP_TST) ? "T" : "C");
9578 printf((tree->gtFlags & GTF_JCMP_EQ) ? "EQ" : "NE");
9582 if (tree->gtFlags & GTF_FIELD_LIST_HEAD)
9597 /* Then print the general purpose flags */
9598 unsigned flags = tree->gtFlags;
9600 if (tree->OperIsBinary())
9602 genTreeOps oper = tree->OperGet();
9604 // Check for GTF_ADDRMODE_NO_CSE flag on add/mul/shl Binary Operators
9605 if ((oper == GT_ADD) || (oper == GT_MUL) || (oper == GT_LSH))
9607 if ((tree->gtFlags & GTF_ADDRMODE_NO_CSE) != 0)
9609 flags |= GTF_DONT_CSE; // Force the GTF_ADDRMODE_NO_CSE flag to print out like GTF_DONT_CSE
9613 else // !tree->OperIsBinary()
9615 // the GTF_REVERSE flag only applies to binary operations
9616 flags &= ~GTF_REVERSE_OPS; // we use this value for GTF_VAR_ARR_INDEX above
9619 msgLength -= GenTree::gtDispFlags(flags, tree->gtDebugFlags);
9621 printf("%c", (flags & GTF_ASG ) ? 'A' : '-');
9622 printf("%c", (flags & GTF_CALL ) ? 'C' : '-');
9623 printf("%c", (flags & GTF_EXCEPT ) ? 'X' : '-');
9624 printf("%c", (flags & GTF_GLOB_REF ) ? 'G' : '-');
9625 printf("%c", (flags & GTF_ORDER_SIDEEFF ) ? 'O' : '-');
9626 printf("%c", (flags & GTF_COLON_COND ) ? '?' : '-');
9627 printf("%c", (flags & GTF_DONT_CSE ) ? 'N' : // N is for No cse
9628 (flags & GTF_MAKE_CSE ) ? 'H' : '-'); // H is for Hoist this expr
9629 printf("%c", (flags & GTF_REVERSE_OPS ) ? 'R' : '-');
9630 printf("%c", (flags & GTF_UNSIGNED ) ? 'U' :
9631 (flags & GTF_BOOLEAN ) ? 'B' : '-');
9632 printf("%c", (flags & GTF_SET_FLAGS ) ? 'S' : '-');
9633 printf("%c", (flags & GTF_SPILLED ) ? 'z' : '-');
9634 printf("%c", (flags & GTF_SPILL ) ? 'Z' : '-');
9638 // If we're printing a node for LIR, we use the space normally associated with the message
9639 // to display the node's temp name (if any)
9640 const bool hasOperands = tree->OperandsBegin() != tree->OperandsEnd();
9643 assert(msg == nullptr);
9645 // If the tree does not have any operands, we do not display the indent stack. This gives us
9646 // two additional characters for alignment.
9652 if (tree->IsValue())
9654 const size_t bufLength = msgLength - 1;
9655 msg = reinterpret_cast<char*>(alloca(bufLength * sizeof(char)));
9656 sprintf_s(const_cast<char*>(msg), bufLength, "t%d = %s", tree->gtTreeID, hasOperands ? "" : " ");
9660 /* print the msg associated with the node */
9671 printf(isLIR ? " %+*s" : " %-*s", msgLength, msg);
9673 /* Indent the node accordingly */
9674 if (!isLIR || hasOperands)
9676 printIndent(indentStack);
9679 gtDispNodeName(tree);
9681 assert(tree == nullptr || tree->gtOper < GT_COUNT);
9685 /* print the type of the node */
9686 if (tree->gtOper != GT_CAST)
9688 printf(" %-6s", varTypeName(tree->TypeGet()));
9689 if (tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_STORE_LCL_VAR)
9691 LclVarDsc* varDsc = &lvaTable[tree->gtLclVarCommon.gtLclNum];
9692 if (varDsc->lvAddrExposed)
9694 printf("(AX)"); // Variable has address exposed.
9697 if (varDsc->lvUnusedStruct)
9699 assert(varDsc->lvPromoted);
9700 printf("(U)"); // Unused struct
9702 else if (varDsc->lvPromoted)
9704 if (varTypeIsPromotable(varDsc))
9706 printf("(P)"); // Promoted struct
9710 // Promoted implicit by-refs can have this state during
9711 // global morph while they are being rewritten
9712 assert(fgGlobalMorph);
9713 printf("(P?!)"); // Promoted struct
9718 if (tree->gtOper == GT_STMT)
9720 if (opts.compDbgInfo)
9722 IL_OFFSET endIL = tree->gtStmt.gtStmtLastILoffs;
9725 if (tree->gtStmt.gtStmtILoffsx == BAD_IL_OFFSET)
9731 printf("0x%03X", jitGetILoffs(tree->gtStmt.gtStmtILoffsx));
9734 if (endIL == BAD_IL_OFFSET)
9740 printf("0x%03X", endIL);
9746 if (tree->IsArgPlaceHolderNode() && (tree->gtArgPlace.gtArgPlaceClsHnd != nullptr))
9748 printf(" => [clsHnd=%08X]", dspPtr(tree->gtArgPlace.gtArgPlaceClsHnd));
9751 if (tree->gtOper == GT_RUNTIMELOOKUP)
9753 #ifdef _TARGET_64BIT_
9754 printf(" 0x%llx", dspPtr(tree->gtRuntimeLookup.gtHnd));
9756 printf(" 0x%x", dspPtr(tree->gtRuntimeLookup.gtHnd));
9759 switch (tree->gtRuntimeLookup.gtHndType)
9761 case CORINFO_HANDLETYPE_CLASS:
9764 case CORINFO_HANDLETYPE_METHOD:
9767 case CORINFO_HANDLETYPE_FIELD:
9777 // for tracking down problems in reguse prediction or liveness tracking
9782 dspRegMask(tree->gtRsvdRegs);
9788 void Compiler::gtDispRegVal(GenTree* tree)
9790 switch (tree->GetRegTag())
9792 // Don't display NOREG; the absence of this tag will imply this state
9793 // case GenTree::GT_REGTAG_NONE: printf(" NOREG"); break;
9795 case GenTree::GT_REGTAG_REG:
9796 printf(" REG %s", compRegVarName(tree->gtRegNum));
9803 if (tree->IsMultiRegCall())
9805 // 0th reg is gtRegNum, which is already printed above.
9806 // Print the remaining regs of a multi-reg call node.
9807 GenTreeCall* call = tree->AsCall();
9808 unsigned regCount = call->GetReturnTypeDesc()->TryGetReturnRegCount();
9809 for (unsigned i = 1; i < regCount; ++i)
9811 printf(",%s", compRegVarName(call->GetRegNumByIdx(i)));
9814 else if (tree->IsCopyOrReloadOfMultiRegCall())
9816 GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
9817 GenTreeCall* call = tree->gtGetOp1()->AsCall();
9818 unsigned regCount = call->GetReturnTypeDesc()->TryGetReturnRegCount();
9819 for (unsigned i = 1; i < regCount; ++i)
9821 printf(",%s", compRegVarName(copyOrReload->GetRegNumByIdx(i)));
9825 #if FEATURE_MULTIREG_RET
9826 if (tree->IsCopyOrReload())
9828 for (int i = 1; i < MAX_RET_REG_COUNT; i++)
9830 regNumber reg = (regNumber)tree->AsCopyOrReload()->GetRegNumByIdx(i);
9835 printf(",%s", compRegVarName(reg));
9840 #if defined(_TARGET_ARM_)
9841 if (tree->OperIsMultiRegOp() && (tree->AsMultiRegOp()->gtOtherReg != REG_NA))
9843 printf(",%s", compRegVarName(tree->AsMultiRegOp()->gtOtherReg));
9848 // We usually/commonly don't expect to print anything longer than this string,
9849 #define LONGEST_COMMON_LCL_VAR_DISPLAY "V99 PInvokeFrame"
9850 #define LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH (sizeof(LONGEST_COMMON_LCL_VAR_DISPLAY))
9851 #define BUF_SIZE (LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH * 2)
9853 void Compiler::gtGetLclVarNameInfo(unsigned lclNum, const char** ilKindOut, const char** ilNameOut, unsigned* ilNumOut)
9855 const char* ilKind = nullptr;
9856 const char* ilName = nullptr;
9858 unsigned ilNum = compMap2ILvarNum(lclNum);
9860 if (ilNum == (unsigned)ICorDebugInfo::RETBUF_ILNUM)
9864 else if (ilNum == (unsigned)ICorDebugInfo::VARARGS_HND_ILNUM)
9866 ilName = "VarArgHandle";
9868 else if (ilNum == (unsigned)ICorDebugInfo::TYPECTXT_ILNUM)
9872 else if (ilNum == (unsigned)ICorDebugInfo::UNKNOWN_ILNUM)
9875 if (lclNumIsTrueCSE(lclNum))
9878 ilNum = lclNum - optCSEstart;
9880 else if (lclNum >= optCSEstart)
9882 // Currently any new LclVar's introduced after the CSE phase
9883 // are believed to be created by the "rationalizer" that is what is meant by the "rat" prefix.
9885 ilNum = lclNum - (optCSEstart + optCSEcount);
9888 #endif // FEATURE_ANYCSE
9890 if (lclNum == info.compLvFrameListRoot)
9892 ilName = "FramesRoot";
9894 else if (lclNum == lvaInlinedPInvokeFrameVar)
9896 ilName = "PInvokeFrame";
9898 else if (lclNum == lvaGSSecurityCookie)
9900 ilName = "GsCookie";
9902 #if FEATURE_FIXED_OUT_ARGS
9903 else if (lclNum == lvaPInvokeFrameRegSaveVar)
9905 ilName = "PInvokeFrameRegSave";
9907 else if (lclNum == lvaOutgoingArgSpaceVar)
9911 #endif // FEATURE_FIXED_OUT_ARGS
9913 else if (lclNum == lvaPromotedStructAssemblyScratchVar)
9915 ilName = "PromotedStructScratch";
9917 #endif // _TARGET_ARM_
9918 #if !FEATURE_EH_FUNCLETS
9919 else if (lclNum == lvaShadowSPslotsVar)
9923 #endif // !FEATURE_EH_FUNCLETS
9924 #ifdef JIT32_GCENCODER
9925 else if (lclNum == lvaLocAllocSPvar)
9927 ilName = "LocAllocSP";
9929 #endif // JIT32_GCENCODER
9930 #if FEATURE_EH_FUNCLETS
9931 else if (lclNum == lvaPSPSym)
9935 #endif // FEATURE_EH_FUNCLETS
9939 if (compIsForInlining())
9941 ilNum = lclNum - impInlineInfo->InlinerCompiler->info.compLocalsCount;
9945 ilNum = lclNum - info.compLocalsCount;
9950 else if (lclNum < (compIsForInlining() ? impInlineInfo->InlinerCompiler->info.compArgsCount : info.compArgsCount))
9952 if (ilNum == 0 && !info.compIsStatic)
9963 if (!lvaTable[lclNum].lvIsStructField)
9967 if (compIsForInlining())
9969 ilNum -= impInlineInfo->InlinerCompiler->info.compILargsCount;
9973 ilNum -= info.compILargsCount;
9977 *ilKindOut = ilKind;
9978 *ilNameOut = ilName;
9982 /*****************************************************************************/
9983 int Compiler::gtGetLclVarName(unsigned lclNum, char* buf, unsigned buf_remaining)
9985 char* bufp_next = buf;
9986 unsigned charsPrinted = 0;
9989 sprintf_result = sprintf_s(bufp_next, buf_remaining, "V%02u", lclNum);
9991 if (sprintf_result < 0)
9993 return sprintf_result;
9996 charsPrinted += sprintf_result;
9997 bufp_next += sprintf_result;
9998 buf_remaining -= sprintf_result;
10000 const char* ilKind = nullptr;
10001 const char* ilName = nullptr;
10002 unsigned ilNum = 0;
10004 gtGetLclVarNameInfo(lclNum, &ilKind, &ilName, &ilNum);
10006 if (ilName != nullptr)
10008 sprintf_result = sprintf_s(bufp_next, buf_remaining, " %s", ilName);
10009 if (sprintf_result < 0)
10011 return sprintf_result;
10013 charsPrinted += sprintf_result;
10014 bufp_next += sprintf_result;
10015 buf_remaining -= sprintf_result;
10017 else if (ilKind != nullptr)
10019 sprintf_result = sprintf_s(bufp_next, buf_remaining, " %s%d", ilKind, ilNum);
10020 if (sprintf_result < 0)
10022 return sprintf_result;
10024 charsPrinted += sprintf_result;
10025 bufp_next += sprintf_result;
10026 buf_remaining -= sprintf_result;
10029 assert(charsPrinted > 0);
10030 assert(buf_remaining > 0);
10032 return (int)charsPrinted;
10035 /*****************************************************************************
10036 * Get the local var name, and create a copy of the string that can be used in debug output.
10038 char* Compiler::gtGetLclVarName(unsigned lclNum)
10040 char buf[BUF_SIZE];
10041 int charsPrinted = gtGetLclVarName(lclNum, buf, _countof(buf));
10042 if (charsPrinted < 0)
10047 char* retBuf = new (this, CMK_DebugOnly) char[charsPrinted + 1];
10048 strcpy_s(retBuf, charsPrinted + 1, buf);
10052 /*****************************************************************************/
10053 void Compiler::gtDispLclVar(unsigned lclNum, bool padForBiggestDisp)
10055 char buf[BUF_SIZE];
10056 int charsPrinted = gtGetLclVarName(lclNum, buf, _countof(buf));
10058 if (charsPrinted < 0)
10065 if (padForBiggestDisp && (charsPrinted < LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH))
10067 printf("%*c", LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH - charsPrinted, ' ');
10071 /*****************************************************************************/
10072 void Compiler::gtDispConst(GenTree* tree)
10074 assert(tree->OperKind() & GTK_CONST);
10076 switch (tree->gtOper)
10079 if (tree->IsIconHandle(GTF_ICON_STR_HDL))
10081 const wchar_t* str = eeGetCPString(tree->gtIntCon.gtIconVal);
10082 if (str != nullptr)
10084 printf(" 0x%X \"%S\"", dspPtr(tree->gtIntCon.gtIconVal), str);
10088 // Note that eGetCPString isn't currently implemented on Linux/ARM
10089 // and instead always returns nullptr
10090 printf(" 0x%X [ICON_STR_HDL]", dspPtr(tree->gtIntCon.gtIconVal));
10095 ssize_t dspIconVal = tree->IsIconHandle() ? dspPtr(tree->gtIntCon.gtIconVal) : tree->gtIntCon.gtIconVal;
10097 if (tree->TypeGet() == TYP_REF)
10099 assert(tree->gtIntCon.gtIconVal == 0);
10102 else if ((tree->gtIntCon.gtIconVal > -1000) && (tree->gtIntCon.gtIconVal < 1000))
10104 printf(" %ld", dspIconVal);
10105 #ifdef _TARGET_64BIT_
10107 else if ((tree->gtIntCon.gtIconVal & 0xFFFFFFFF00000000LL) != 0)
10109 printf(" 0x%llx", dspIconVal);
10114 printf(" 0x%X", dspIconVal);
10117 if (tree->IsIconHandle())
10119 switch (tree->GetIconHandleFlag())
10121 case GTF_ICON_SCOPE_HDL:
10124 case GTF_ICON_CLASS_HDL:
10127 case GTF_ICON_METHOD_HDL:
10130 case GTF_ICON_FIELD_HDL:
10133 case GTF_ICON_STATIC_HDL:
10136 case GTF_ICON_STR_HDL:
10137 unreached(); // This case is handled above
10139 case GTF_ICON_PSTR_HDL:
10142 case GTF_ICON_PTR_HDL:
10145 case GTF_ICON_VARG_HDL:
10148 case GTF_ICON_PINVKI_HDL:
10149 printf(" pinvoke");
10151 case GTF_ICON_TOKEN_HDL:
10154 case GTF_ICON_TLS_HDL:
10157 case GTF_ICON_FTN_ADDR:
10160 case GTF_ICON_CIDMID_HDL:
10161 printf(" cid/mid");
10163 case GTF_ICON_BBC_PTR:
10167 printf(" UNKNOWN");
10172 if ((tree->gtFlags & GTF_ICON_FIELD_OFF) != 0)
10174 printf(" field offset");
10177 #ifdef FEATURE_SIMD
10178 if ((tree->gtFlags & GTF_ICON_SIMD_COUNT) != 0)
10180 printf(" Vector<T>.Count");
10184 if ((tree->IsReuseRegVal()) != 0)
10186 printf(" reuse reg val");
10190 gtDispFieldSeq(tree->gtIntCon.gtFieldSeq);
10195 printf(" 0x%016I64x", tree->gtLngCon.gtLconVal);
10199 if (*((__int64*)&tree->gtDblCon.gtDconVal) == (__int64)I64(0x8000000000000000))
10201 printf(" -0.00000");
10205 printf(" %#.17g", tree->gtDblCon.gtDconVal);
10209 printf("<string constant>");
10212 assert(!"unexpected constant node");
10215 gtDispRegVal(tree);
10218 void Compiler::gtDispFieldSeq(FieldSeqNode* pfsn)
10220 if (pfsn == FieldSeqStore::NotAField() || (pfsn == nullptr))
10227 while (pfsn != nullptr)
10229 assert(pfsn != FieldSeqStore::NotAField()); // Can't exist in a field sequence list except alone
10230 CORINFO_FIELD_HANDLE fldHnd = pfsn->m_fieldHnd;
10231 // First check the "pseudo" field handles...
10232 if (fldHnd == FieldSeqStore::FirstElemPseudoField)
10234 printf("#FirstElem");
10236 else if (fldHnd == FieldSeqStore::ConstantIndexPseudoField)
10238 printf("#ConstantIndex");
10242 printf("%s", eeGetFieldName(fldHnd));
10244 pfsn = pfsn->m_next;
10245 if (pfsn != nullptr)
10253 //------------------------------------------------------------------------
10254 // gtDispLeaf: Print a single leaf node to jitstdout.
10257 // tree - the tree to be printed
10258 // indentStack - the specification for the current level of indentation & arcs
10264 // 'indentStack' may be null, in which case no indentation or arcs are printed
10266 void Compiler::gtDispLeaf(GenTree* tree, IndentStack* indentStack)
10268 if (tree->OperKind() & GTK_CONST)
10274 bool isLclFld = false;
10276 switch (tree->gtOper)
10282 case GT_LCL_FLD_ADDR:
10283 case GT_STORE_LCL_FLD:
10289 case GT_LCL_VAR_ADDR:
10290 case GT_STORE_LCL_VAR:
10292 varNum = tree->gtLclVarCommon.gtLclNum;
10293 varDsc = &lvaTable[varNum];
10294 gtDispLclVar(varNum);
10295 if (tree->gtLclVarCommon.HasSsaName())
10297 if (tree->gtFlags & GTF_VAR_USEASG)
10299 assert(tree->gtFlags & GTF_VAR_DEF);
10300 printf("ud:%d->%d", tree->gtLclVarCommon.gtSsaNum, GetSsaNumForLocalVarDef(tree));
10304 printf("%s:%d", (tree->gtFlags & GTF_VAR_DEF) ? "d" : "u", tree->gtLclVarCommon.gtSsaNum);
10310 printf("[+%u]", tree->gtLclFld.gtLclOffs);
10311 gtDispFieldSeq(tree->gtLclFld.gtFieldSeq);
10314 if (varDsc->lvRegister)
10317 varDsc->PrintVarReg();
10319 else if (tree->InReg())
10321 printf(" %s", compRegVarName(tree->gtRegNum));
10324 if (varDsc->lvPromoted)
10326 if (!varTypeIsPromotable(varDsc) && !varDsc->lvUnusedStruct)
10328 // Promoted implicit byrefs can get in this state while they are being rewritten
10329 // in global morph.
10330 assert(fgGlobalMorph);
10334 CORINFO_CLASS_HANDLE typeHnd = varDsc->lvVerTypeInfo.GetClassHandle();
10335 CORINFO_FIELD_HANDLE fldHnd;
10337 for (unsigned i = varDsc->lvFieldLclStart; i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++i)
10339 LclVarDsc* fieldVarDsc = &lvaTable[i];
10340 const char* fieldName;
10341 #if !defined(_TARGET_64BIT_)
10342 if (varTypeIsLong(varDsc))
10344 fieldName = (i == 0) ? "lo" : "hi";
10347 #endif // !defined(_TARGET_64BIT_)
10349 fldHnd = info.compCompHnd->getFieldInClass(typeHnd, fieldVarDsc->lvFldOrdinal);
10350 fieldName = eeGetFieldName(fldHnd);
10355 printIndent(indentStack);
10356 printf(" %-6s V%02u.%s (offs=0x%02x) -> ", varTypeName(fieldVarDsc->TypeGet()),
10357 tree->gtLclVarCommon.gtLclNum, fieldName, fieldVarDsc->lvFldOffset);
10360 if (fieldVarDsc->lvRegister)
10363 fieldVarDsc->PrintVarReg();
10366 if (fieldVarDsc->lvTracked && fgLocalVarLivenessDone && // Includes local variable liveness
10367 ((tree->gtFlags & GTF_VAR_DEATH) != 0))
10369 printf(" (last use)");
10374 else // a normal not-promoted lclvar
10376 if (varDsc->lvTracked && fgLocalVarLivenessDone && ((tree->gtFlags & GTF_VAR_DEATH) != 0))
10378 printf(" (last use)");
10385 const char* methodName;
10386 const char* className;
10388 methodName = eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtVal.gtVal1, &className);
10389 printf(" %s.%s\n", className, methodName);
10394 printf(" Hnd=%#x", dspPtr(tree->gtClsVar.gtClsVarHnd));
10395 gtDispFieldSeq(tree->gtClsVar.gtFieldSeq);
10398 case GT_CLS_VAR_ADDR:
10399 printf(" Hnd=%#x", dspPtr(tree->gtClsVar.gtClsVarHnd));
10403 if (tree->gtLabel.gtLabBB)
10405 printf(" dst=" FMT_BB, tree->gtLabel.gtLabBB->bbNum);
10409 printf(" dst=<null>");
10416 const char* methodName;
10417 const char* className;
10419 methodName = eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtFptrVal.gtFptrMethod, &className);
10420 printf(" %s.%s\n", className, methodName);
10424 #if !FEATURE_EH_FUNCLETS
10426 printf(" endNstLvl=%d", tree->gtVal.gtVal1);
10428 #endif // !FEATURE_EH_FUNCLETS
10430 // Vanilla leaves. No qualifying information available. So do nothing
10433 case GT_START_NONGC:
10436 case GT_MEMORYBARRIER:
10438 case GT_PINVOKE_PROLOG:
10443 printf("(inl return from call ");
10444 printTreeID(tree->gtRetExpr.gtInlineCandidate);
10449 printf(" %s", getRegName(tree->gtPhysReg.gtSrcReg, varTypeIsFloating(tree)));
10453 printf(" IL offset: ");
10454 if (tree->gtStmt.gtStmtILoffsx == BAD_IL_OFFSET)
10460 printf("0x%x", jitGetILoffs(tree->gtStmt.gtStmtILoffsx));
10466 printf(" cond=%s", GenTree::OpName(tree->AsCC()->gtCondition));
10469 printf(" cond=%s%s", (tree->gtFlags & GTF_JCMP_TST) ? "TEST_" : "",
10470 (tree->gtFlags & GTF_JCMP_EQ) ? "EQ" : "NE");
10473 assert(!"don't know how to display tree leaf node");
10476 gtDispRegVal(tree);
10479 //------------------------------------------------------------------------
10480 // gtDispLeaf: Print a child node to jitstdout.
10483 // tree - the tree to be printed
10484 // indentStack - the specification for the current level of indentation & arcs
10485 // arcType - the type of arc to use for this child
10486 // msg - a contextual method (i.e. from the parent) to print
10487 // topOnly - a boolean indicating whether to print the children, or just the top node
10493 // 'indentStack' may be null, in which case no indentation or arcs are printed
10494 // 'msg' has a default value of null
10495 // 'topOnly' is an optional argument that defaults to false
10497 void Compiler::gtDispChild(GenTree* child,
10498 IndentStack* indentStack,
10499 IndentInfo arcType,
10500 __in_opt const char* msg, /* = nullptr */
10501 bool topOnly) /* = false */
10503 indentStack->Push(arcType);
10504 gtDispTree(child, indentStack, msg, topOnly);
10505 indentStack->Pop();
10508 #ifdef FEATURE_SIMD
10509 // Intrinsic Id to name map
10510 extern const char* const simdIntrinsicNames[] = {
10511 #define SIMD_INTRINSIC(mname, inst, id, name, r, ac, arg1, arg2, arg3, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) name,
10512 #include "simdintrinsiclist.h"
10514 #endif // FEATURE_SIMD
10516 /*****************************************************************************/
10518 void Compiler::gtDispTree(GenTree* tree,
10519 IndentStack* indentStack, /* = nullptr */
10520 __in __in_z __in_opt const char* msg, /* = nullptr */
10521 bool topOnly, /* = false */
10522 bool isLIR) /* = false */
10524 if (tree == nullptr)
10526 printf(" [%08X] <NULL>\n", tree);
10527 printf(""); // null string means flush
10531 if (indentStack == nullptr)
10533 indentStack = new (this, CMK_DebugOnly) IndentStack(this);
10536 if (IsUninitialized(tree))
10538 /* Value used to initalize nodes */
10539 printf("Uninitialized tree node!");
10543 if (tree->gtOper >= GT_COUNT)
10545 gtDispNode(tree, indentStack, msg, isLIR);
10546 printf("Bogus operator!");
10550 /* Is tree a leaf node? */
10552 if (tree->OperIsLeaf() || tree->OperIsLocalStore()) // local stores used to be leaves
10554 gtDispNode(tree, indentStack, msg, isLIR);
10555 gtDispLeaf(tree, indentStack);
10558 if (tree->OperIsLocalStore() && !topOnly)
10560 gtDispChild(tree->gtOp.gtOp1, indentStack, IINone);
10565 // Determine what kind of arc to propagate.
10566 IndentInfo myArc = IINone;
10567 IndentInfo lowerArc = IINone;
10568 if (indentStack->Depth() > 0)
10570 myArc = indentStack->Pop();
10574 indentStack->Push(IIArc);
10578 indentStack->Push(IIArc);
10582 indentStack->Push(IINone);
10586 indentStack->Push(IIEmbedded);
10587 lowerArc = IIEmbedded;
10590 indentStack->Push(IINone);
10599 // Special case formatting for PHI nodes -- arg lists like calls.
10601 if (tree->OperGet() == GT_PHI)
10603 gtDispNode(tree, indentStack, msg, isLIR);
10609 if (tree->gtOp.gtOp1 != nullptr)
10611 IndentInfo arcType = IIArcTop;
10612 for (GenTreeArgList* args = tree->gtOp.gtOp1->AsArgList(); args != nullptr; args = args->Rest())
10614 if (args->Rest() == nullptr)
10616 arcType = IIArcBottom;
10618 gtDispChild(args->Current(), indentStack, arcType);
10626 /* Is it a 'simple' unary/binary operator? */
10628 const char* childMsg = nullptr;
10630 if (tree->OperIsSimple())
10634 if (tree->gtGetOp2IfPresent())
10636 // Label the childMsgs of the GT_COLON operator
10637 // op2 is the then part
10639 if (tree->gtOper == GT_COLON)
10643 gtDispChild(tree->gtOp.gtOp2, indentStack, IIArcTop, childMsg, topOnly);
10647 // Now, get the right type of arc for this node
10648 if (myArc != IINone)
10650 indentStack->Pop();
10651 indentStack->Push(myArc);
10654 gtDispNode(tree, indentStack, msg, isLIR);
10656 // Propagate lowerArc to the lower children.
10657 if (indentStack->Depth() > 0)
10659 (void)indentStack->Pop();
10660 indentStack->Push(lowerArc);
10663 if (tree->gtOper == GT_CAST)
10665 /* Format a message that explains the effect of this GT_CAST */
10667 var_types fromType = genActualType(tree->gtCast.CastOp()->TypeGet());
10668 var_types toType = tree->CastToType();
10669 var_types finalType = tree->TypeGet();
10671 /* if GTF_UNSIGNED is set then force fromType to an unsigned type */
10672 if (tree->gtFlags & GTF_UNSIGNED)
10674 fromType = genUnsignedType(fromType);
10677 if (finalType != toType)
10679 printf(" %s <-", varTypeName(finalType));
10682 printf(" %s <- %s", varTypeName(toType), varTypeName(fromType));
10685 if (tree->gtOper == GT_OBJ && (tree->gtFlags & GTF_VAR_DEATH))
10687 printf(" (last use)");
10689 if (tree->OperIsBlkOp())
10691 if (tree->OperIsCopyBlkOp())
10695 else if (tree->OperIsInitBlkOp())
10699 if (tree->OperIsStoreBlk() && (tree->AsBlk()->gtBlkOpKind != GenTreeBlk::BlkOpKindInvalid))
10701 switch (tree->AsBlk()->gtBlkOpKind)
10703 case GenTreeBlk::BlkOpKindRepInstr:
10704 printf(" (RepInstr)");
10706 case GenTreeBlk::BlkOpKindUnroll:
10707 printf(" (Unroll)");
10709 case GenTreeBlk::BlkOpKindHelper:
10710 printf(" (Helper)");
10717 else if (tree->OperIsFieldList())
10719 printf(" %s at offset %d", varTypeName(tree->AsFieldList()->gtFieldType),
10720 tree->AsFieldList()->gtFieldOffset);
10722 #if FEATURE_PUT_STRUCT_ARG_STK
10723 else if (tree->OperGet() == GT_PUTARG_STK)
10725 printf(" (%d slots)", tree->AsPutArgStk()->gtNumSlots);
10726 if (tree->AsPutArgStk()->gtPutArgStkKind != GenTreePutArgStk::Kind::Invalid)
10728 switch (tree->AsPutArgStk()->gtPutArgStkKind)
10730 case GenTreePutArgStk::Kind::RepInstr:
10731 printf(" (RepInstr)");
10733 case GenTreePutArgStk::Kind::Unroll:
10734 printf(" (Unroll)");
10736 case GenTreePutArgStk::Kind::Push:
10739 case GenTreePutArgStk::Kind::PushAllSlots:
10740 printf(" (PushAllSlots)");
10747 #endif // FEATURE_PUT_STRUCT_ARG_STK
10749 if (tree->gtOper == GT_INTRINSIC)
10751 switch (tree->gtIntrinsic.gtIntrinsicId)
10753 case CORINFO_INTRINSIC_Sin:
10756 case CORINFO_INTRINSIC_Cos:
10759 case CORINFO_INTRINSIC_Cbrt:
10762 case CORINFO_INTRINSIC_Sqrt:
10765 case CORINFO_INTRINSIC_Abs:
10768 case CORINFO_INTRINSIC_Round:
10771 case CORINFO_INTRINSIC_Cosh:
10774 case CORINFO_INTRINSIC_Sinh:
10777 case CORINFO_INTRINSIC_Tan:
10780 case CORINFO_INTRINSIC_Tanh:
10783 case CORINFO_INTRINSIC_Asin:
10786 case CORINFO_INTRINSIC_Asinh:
10789 case CORINFO_INTRINSIC_Acos:
10792 case CORINFO_INTRINSIC_Acosh:
10795 case CORINFO_INTRINSIC_Atan:
10798 case CORINFO_INTRINSIC_Atan2:
10801 case CORINFO_INTRINSIC_Atanh:
10804 case CORINFO_INTRINSIC_Log10:
10807 case CORINFO_INTRINSIC_Pow:
10810 case CORINFO_INTRINSIC_Exp:
10813 case CORINFO_INTRINSIC_Ceiling:
10814 printf(" ceiling");
10816 case CORINFO_INTRINSIC_Floor:
10819 case CORINFO_INTRINSIC_Object_GetType:
10820 printf(" objGetType");
10828 #ifdef FEATURE_SIMD
10829 if (tree->gtOper == GT_SIMD)
10831 printf(" %s %s", varTypeName(tree->gtSIMD.gtSIMDBaseType),
10832 simdIntrinsicNames[tree->gtSIMD.gtSIMDIntrinsicID]);
10834 #endif // FEATURE_SIMD
10836 #ifdef FEATURE_HW_INTRINSICS
10837 if (tree->gtOper == GT_HWIntrinsic)
10840 tree->gtHWIntrinsic.gtSIMDBaseType == TYP_UNKNOWN ? ""
10841 : varTypeName(tree->gtHWIntrinsic.gtSIMDBaseType),
10842 HWIntrinsicInfo::lookupName(tree->gtHWIntrinsic.gtHWIntrinsicId));
10844 #endif // FEATURE_HW_INTRINSICS
10846 gtDispRegVal(tree);
10850 if (!topOnly && tree->gtOp.gtOp1)
10853 // Label the child of the GT_COLON operator
10854 // op1 is the else part
10856 if (tree->gtOper == GT_COLON)
10860 else if (tree->gtOper == GT_QMARK)
10864 gtDispChild(tree->gtOp.gtOp1, indentStack, IIArcBottom, childMsg, topOnly);
10870 // Now, get the right type of arc for this node
10871 if (myArc != IINone)
10873 indentStack->Pop();
10874 indentStack->Push(myArc);
10876 gtDispNode(tree, indentStack, msg, isLIR);
10878 // Propagate lowerArc to the lower children.
10879 if (indentStack->Depth() > 0)
10881 (void)indentStack->Pop();
10882 indentStack->Push(lowerArc);
10885 // See what kind of a special operator we have here, and handle its special children.
10887 switch (tree->gtOper)
10890 if (FieldSeqStore::IsPseudoField(tree->gtField.gtFldHnd))
10892 printf(" #PseudoField:0x%x", tree->gtField.gtFldOffset);
10896 printf(" %s", eeGetFieldName(tree->gtField.gtFldHnd), 0);
10899 if (tree->gtField.gtFldObj && !topOnly)
10903 gtDispChild(tree->gtField.gtFldObj, indentStack, IIArcBottom);
10907 gtDispRegVal(tree);
10915 GenTreeCall* call = tree->AsCall();
10916 assert(call->gtFlags & GTF_CALL);
10917 unsigned numChildren = call->NumChildren();
10918 GenTree* lastChild = nullptr;
10919 if (numChildren != 0)
10921 lastChild = call->GetChild(numChildren - 1);
10924 if (call->gtCallType != CT_INDIRECT)
10926 const char* methodName;
10927 const char* className;
10929 methodName = eeGetMethodName(call->gtCallMethHnd, &className);
10931 printf(" %s.%s", className, methodName);
10934 if ((call->gtFlags & GTF_CALL_UNMANAGED) && (call->gtCallMoreFlags & GTF_CALL_M_FRAME_VAR_DEATH))
10936 printf(" (FramesRoot last use)");
10939 if (((call->gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0) && (call->gtInlineCandidateInfo != nullptr) &&
10940 (call->gtInlineCandidateInfo->exactContextHnd != nullptr))
10942 printf(" (exactContextHnd=0x%p)", dspPtr(call->gtInlineCandidateInfo->exactContextHnd));
10946 if (call->IsMultiRegCall())
10948 gtDispRegVal(call);
10959 if ((call->gtCallObjp != nullptr) && (call->gtCallObjp->gtOper != GT_NOP) &&
10960 (!call->gtCallObjp->IsArgPlaceHolderNode()))
10962 if (call->gtCallObjp->gtOper == GT_ASG)
10964 sprintf_s(bufp, sizeof(buf), "this SETUP%c", 0);
10968 sprintf_s(bufp, sizeof(buf), "this in %s%c", compRegVarName(REG_ARG_0), 0);
10970 gtDispChild(call->gtCallObjp, indentStack, (call->gtCallObjp == lastChild) ? IIArcBottom : IIArc,
10974 if (call->gtCallArgs)
10976 gtDispArgList(call, indentStack);
10979 if (call->gtCallType == CT_INDIRECT)
10981 gtDispChild(call->gtCallAddr, indentStack, (call->gtCallAddr == lastChild) ? IIArcBottom : IIArc,
10982 "calli tgt", topOnly);
10985 if (call->gtControlExpr != nullptr)
10987 gtDispChild(call->gtControlExpr, indentStack,
10988 (call->gtControlExpr == lastChild) ? IIArcBottom : IIArc, "control expr", topOnly);
10991 #if !FEATURE_FIXED_OUT_ARGS
10992 regList list = call->regArgList;
10994 /* process the late argument list */
10995 int lateArgIndex = 0;
10996 for (GenTreeArgList* lateArgs = call->gtCallLateArgs; lateArgs;
10997 (lateArgIndex++, lateArgs = lateArgs->Rest()))
11001 argx = lateArgs->Current();
11003 IndentInfo arcType = (lateArgs->Rest() == nullptr) ? IIArcBottom : IIArc;
11004 gtGetLateArgMsg(call, argx, lateArgIndex, -1, bufp, sizeof(buf));
11005 gtDispChild(argx, indentStack, arcType, bufp, topOnly);
11016 gtDispChild(tree->gtStmt.gtStmtExpr, indentStack, IIArcBottom);
11026 gtDispChild(tree->gtArrElem.gtArrObj, indentStack, IIArc, nullptr, topOnly);
11029 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
11031 IndentInfo arcType = ((dim + 1) == tree->gtArrElem.gtArrRank) ? IIArcBottom : IIArc;
11032 gtDispChild(tree->gtArrElem.gtArrInds[dim], indentStack, arcType, nullptr, topOnly);
11037 case GT_ARR_OFFSET:
11042 gtDispChild(tree->gtArrOffs.gtOffset, indentStack, IIArc, nullptr, topOnly);
11043 gtDispChild(tree->gtArrOffs.gtIndex, indentStack, IIArc, nullptr, topOnly);
11044 gtDispChild(tree->gtArrOffs.gtArrObj, indentStack, IIArcBottom, nullptr, topOnly);
11053 gtDispChild(tree->gtCmpXchg.gtOpLocation, indentStack, IIArc, nullptr, topOnly);
11054 gtDispChild(tree->gtCmpXchg.gtOpValue, indentStack, IIArc, nullptr, topOnly);
11055 gtDispChild(tree->gtCmpXchg.gtOpComparand, indentStack, IIArcBottom, nullptr, topOnly);
11059 case GT_ARR_BOUNDS_CHECK:
11060 #ifdef FEATURE_SIMD
11062 #endif // FEATURE_SIMD
11063 #ifdef FEATURE_HW_INTRINSICS
11064 case GT_HW_INTRINSIC_CHK:
11065 #endif // FEATURE_HW_INTRINSICS
11070 gtDispChild(tree->gtBoundsChk.gtIndex, indentStack, IIArc, nullptr, topOnly);
11071 gtDispChild(tree->gtBoundsChk.gtArrLen, indentStack, IIArcBottom, nullptr, topOnly);
11075 case GT_STORE_DYN_BLK:
11077 if (tree->OperIsCopyBlkOp())
11081 else if (tree->OperIsInitBlkOp())
11089 if (tree->gtDynBlk.Data() != nullptr)
11091 gtDispChild(tree->gtDynBlk.Data(), indentStack, IIArc, nullptr, topOnly);
11093 gtDispChild(tree->gtDynBlk.Addr(), indentStack, IIArc, nullptr, topOnly);
11094 gtDispChild(tree->gtDynBlk.gtDynamicSize, indentStack, IIArcBottom, nullptr, topOnly);
11099 printf("<DON'T KNOW HOW TO DISPLAY THIS NODE> :");
11100 printf(""); // null string means flush
11105 //------------------------------------------------------------------------
11106 // gtGetArgMsg: Construct a message about the given argument
11109 // call - The call for which 'arg' is an argument
11110 // arg - The argument for which a message should be constructed
11111 // argNum - The ordinal number of the arg in the argument list
11112 // listCount - When printing in LIR form this is the count for a GT_FIELD_LIST
11113 // or -1 if we are not printing in LIR form
11114 // bufp - A pointer to the buffer into which the message is written
11115 // bufLength - The length of the buffer pointed to by bufp
11118 // No return value, but bufp is written.
11121 // 'call' must be a call node
11122 // 'arg' must be an argument to 'call' (else gtArgEntryByNode will assert)
11124 void Compiler::gtGetArgMsg(
11125 GenTreeCall* call, GenTree* arg, unsigned argNum, int listCount, char* bufp, unsigned bufLength)
11127 if (call->gtCallLateArgs != nullptr)
11129 fgArgTabEntry* curArgTabEntry = gtArgEntryByArgNum(call, argNum);
11130 assert(curArgTabEntry);
11132 if (arg->gtFlags & GTF_LATE_ARG)
11134 sprintf_s(bufp, bufLength, "arg%d SETUP%c", argNum, 0);
11138 #ifdef _TARGET_ARM_
11139 if (curArgTabEntry->isSplit)
11141 regNumber firstReg = curArgTabEntry->regNum;
11142 if (listCount == -1)
11144 if (curArgTabEntry->numRegs == 1)
11146 sprintf_s(bufp, bufLength, "arg%d %s out+%02x%c", argNum, compRegVarName(firstReg),
11147 (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE, 0);
11151 regNumber lastReg = REG_STK;
11152 char separator = (curArgTabEntry->numRegs == 2) ? ',' : '-';
11153 if (curArgTabEntry->isHfaRegArg)
11155 unsigned lastRegNum = genMapFloatRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
11156 lastReg = genMapFloatRegArgNumToRegNum(lastRegNum);
11160 unsigned lastRegNum = genMapIntRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
11161 lastReg = genMapIntRegArgNumToRegNum(lastRegNum);
11163 sprintf_s(bufp, bufLength, "arg%d %s%c%s out+%02x%c", argNum, compRegVarName(firstReg),
11164 separator, compRegVarName(lastReg), (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE,
11170 unsigned curArgNum = BAD_VAR_NUM;
11171 bool isFloat = curArgTabEntry->isHfaRegArg;
11174 curArgNum = genMapFloatRegNumToRegArgNum(firstReg) + listCount;
11178 curArgNum = genMapIntRegNumToRegArgNum(firstReg) + listCount;
11181 if (!isFloat && curArgNum < MAX_REG_ARG)
11183 regNumber curReg = genMapIntRegArgNumToRegNum(curArgNum);
11184 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
11186 else if (isFloat && curArgNum < MAX_FLOAT_REG_ARG)
11188 regNumber curReg = genMapFloatRegArgNumToRegNum(curArgNum);
11189 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
11193 unsigned stackSlot = listCount - curArgTabEntry->numRegs;
11194 sprintf_s(bufp, bufLength, "arg%d m%d out+%02x%c", argNum, listCount,
11195 stackSlot * TARGET_POINTER_SIZE, 0);
11200 #endif // _TARGET_ARM_
11201 #if FEATURE_FIXED_OUT_ARGS
11202 if (listCount == -1)
11204 sprintf_s(bufp, bufLength, "arg%d out+%02x%c", argNum, curArgTabEntry->slotNum * TARGET_POINTER_SIZE,
11207 else // listCount is 0,1,2 or 3
11209 assert(listCount <= MAX_ARG_REG_COUNT);
11210 sprintf_s(bufp, bufLength, "arg%d out+%02x%c", argNum,
11211 (curArgTabEntry->slotNum + listCount) * TARGET_POINTER_SIZE, 0);
11214 sprintf_s(bufp, bufLength, "arg%d on STK%c", argNum, 0);
11220 sprintf_s(bufp, bufLength, "arg%d%c", argNum, 0);
11224 //------------------------------------------------------------------------
11225 // gtGetLateArgMsg: Construct a message about the given argument
11228 // call - The call for which 'arg' is an argument
11229 // argx - The argument for which a message should be constructed
11230 // lateArgIndex - The ordinal number of the arg in the lastArg list
11231 // listCount - When printing in LIR form this is the count for a multireg GT_FIELD_LIST
11232 // or -1 if we are not printing in LIR form
11233 // bufp - A pointer to the buffer into which the message is written
11234 // bufLength - The length of the buffer pointed to by bufp
11237 // No return value, but bufp is written.
11240 // 'call' must be a call node
11241 // 'arg' must be an argument to 'call' (else gtArgEntryByNode will assert)
11243 void Compiler::gtGetLateArgMsg(
11244 GenTreeCall* call, GenTree* argx, int lateArgIndex, int listCount, char* bufp, unsigned bufLength)
11246 assert(!argx->IsArgPlaceHolderNode()); // No place holders nodes are in gtCallLateArgs;
11248 fgArgTabEntry* curArgTabEntry = gtArgEntryByLateArgIndex(call, lateArgIndex);
11249 assert(curArgTabEntry);
11250 regNumber argReg = curArgTabEntry->regNum;
11252 #if !FEATURE_FIXED_OUT_ARGS
11253 assert(lateArgIndex < call->regArgListCount);
11254 assert(argReg == call->regArgList[lateArgIndex]);
11256 if (argReg == REG_STK)
11258 sprintf_s(bufp, bufLength, "arg%d in out+%02x%c", curArgTabEntry->argNum,
11259 curArgTabEntry->slotNum * TARGET_POINTER_SIZE, 0);
11264 if (gtArgIsThisPtr(curArgTabEntry))
11266 sprintf_s(bufp, bufLength, "this in %s%c", compRegVarName(argReg), 0);
11268 #ifdef _TARGET_ARM_
11269 else if (curArgTabEntry->isSplit)
11271 regNumber firstReg = curArgTabEntry->regNum;
11272 unsigned argNum = curArgTabEntry->argNum;
11273 if (listCount == -1)
11275 if (curArgTabEntry->numRegs == 1)
11277 sprintf_s(bufp, bufLength, "arg%d %s out+%02x%c", argNum, compRegVarName(firstReg),
11278 (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE, 0);
11282 regNumber lastReg = REG_STK;
11283 char separator = (curArgTabEntry->numRegs == 2) ? ',' : '-';
11284 if (curArgTabEntry->isHfaRegArg)
11286 unsigned lastRegNum = genMapFloatRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
11287 lastReg = genMapFloatRegArgNumToRegNum(lastRegNum);
11291 unsigned lastRegNum = genMapIntRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
11292 lastReg = genMapIntRegArgNumToRegNum(lastRegNum);
11294 sprintf_s(bufp, bufLength, "arg%d %s%c%s out+%02x%c", argNum, compRegVarName(firstReg), separator,
11295 compRegVarName(lastReg), (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE, 0);
11300 unsigned curArgNum = BAD_VAR_NUM;
11301 bool isFloat = curArgTabEntry->isHfaRegArg;
11304 curArgNum = genMapFloatRegNumToRegArgNum(firstReg) + listCount;
11308 curArgNum = genMapIntRegNumToRegArgNum(firstReg) + listCount;
11311 if (!isFloat && curArgNum < MAX_REG_ARG)
11313 regNumber curReg = genMapIntRegArgNumToRegNum(curArgNum);
11314 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
11316 else if (isFloat && curArgNum < MAX_FLOAT_REG_ARG)
11318 regNumber curReg = genMapFloatRegArgNumToRegNum(curArgNum);
11319 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
11323 unsigned stackSlot = listCount - curArgTabEntry->numRegs;
11324 sprintf_s(bufp, bufLength, "arg%d m%d out+%02x%c", argNum, listCount,
11325 stackSlot * TARGET_POINTER_SIZE, 0);
11330 #endif // _TARGET_ARM_
11333 #if FEATURE_MULTIREG_ARGS
11334 if (curArgTabEntry->numRegs >= 2)
11336 // listCount could be -1 but it is signed, so this comparison is OK.
11337 assert(listCount <= MAX_ARG_REG_COUNT);
11338 char separator = (curArgTabEntry->numRegs == 2) ? ',' : '-';
11339 sprintf_s(bufp, bufLength, "arg%d %s%c%s%c", curArgTabEntry->argNum, compRegVarName(argReg), separator,
11340 compRegVarName(curArgTabEntry->getRegNum(curArgTabEntry->numRegs - 1)), 0);
11345 sprintf_s(bufp, bufLength, "arg%d in %s%c", curArgTabEntry->argNum, compRegVarName(argReg), 0);
11351 //------------------------------------------------------------------------
11352 // gtDispArgList: Dump the tree for a call arg list
11355 // call - The call to dump arguments for
11356 // indentStack - the specification for the current level of indentation & arcs
11361 void Compiler::gtDispArgList(GenTreeCall* call, IndentStack* indentStack)
11363 GenTree* args = call->gtCallArgs;
11364 unsigned argnum = 0;
11365 const int BufLength = 256;
11366 char buf[BufLength];
11367 char* bufp = &buf[0];
11368 unsigned numChildren = call->NumChildren();
11369 assert(numChildren != 0);
11370 bool argListIsLastChild = (args == call->GetChild(numChildren - 1));
11372 IndentInfo arcType = IIArc;
11373 if (call->gtCallObjp != nullptr)
11378 while (args != nullptr)
11380 assert(args->gtOper == GT_LIST);
11381 GenTree* arg = args->gtOp.gtOp1;
11382 if (!arg->IsNothingNode() && !arg->IsArgPlaceHolderNode())
11384 gtGetArgMsg(call, arg, argnum, -1, bufp, BufLength);
11385 if (argListIsLastChild && (args->gtOp.gtOp2 == nullptr))
11387 arcType = IIArcBottom;
11389 gtDispChild(arg, indentStack, arcType, bufp, false);
11391 args = args->gtOp.gtOp2;
11396 //------------------------------------------------------------------------
11397 // gtDispArgList: Dump the tree for a call arg list
11400 // tree - The call for which 'arg' is an argument
11401 // indentStack - the specification for the current level of indentation & arcs
11407 // 'tree' must be a GT_LIST node
11409 void Compiler::gtDispTreeList(GenTree* tree, IndentStack* indentStack /* = nullptr */)
11411 for (/*--*/; tree != nullptr; tree = tree->gtNext)
11413 gtDispTree(tree, indentStack);
11418 //------------------------------------------------------------------------
11419 // Compiler::gtDispRange: dumps a range of LIR.
11422 // range - the range of LIR to display.
11424 void Compiler::gtDispRange(LIR::ReadOnlyRange const& range)
11426 for (GenTree* node : range)
11428 gtDispLIRNode(node);
11432 //------------------------------------------------------------------------
11433 // Compiler::gtDispTreeRange: dumps the LIR range that contains all of the
11434 // nodes in the dataflow tree rooted at a given
11438 // containingRange - the LIR range that contains the root node.
11439 // tree - the root of the dataflow tree.
11441 void Compiler::gtDispTreeRange(LIR::Range& containingRange, GenTree* tree)
11444 gtDispRange(containingRange.GetTreeRange(tree, &unused));
11447 //------------------------------------------------------------------------
11448 // Compiler::gtDispLIRNode: dumps a single LIR node.
11451 // node - the LIR node to dump.
11452 // prefixMsg - an optional prefix for each line of output.
11454 void Compiler::gtDispLIRNode(GenTree* node, const char* prefixMsg /* = nullptr */)
11456 auto displayOperand = [](GenTree* operand, const char* message, IndentInfo operandArc, IndentStack& indentStack,
11457 size_t prefixIndent) {
11458 assert(operand != nullptr);
11459 assert(message != nullptr);
11461 if (prefixIndent != 0)
11463 printf("%*s", (int)prefixIndent, "");
11466 // 49 spaces for alignment
11467 printf("%-49s", "");
11468 #if FEATURE_SET_FLAGS
11469 // additional flag enlarges the flag field by one character
11473 indentStack.Push(operandArc);
11474 indentStack.print();
11476 operandArc = IIArc;
11478 printf(" t%-5d %-6s %s\n", operand->gtTreeID, varTypeName(operand->TypeGet()), message);
11481 IndentStack indentStack(this);
11483 size_t prefixIndent = 0;
11484 if (prefixMsg != nullptr)
11486 prefixIndent = strlen(prefixMsg);
11489 const int bufLength = 256;
11490 char buf[bufLength];
11492 const bool nodeIsCall = node->IsCall();
11495 IndentInfo operandArc = IIArcTop;
11496 for (GenTree* operand : node->Operands())
11498 if (operand->IsArgPlaceHolderNode() || !operand->IsValue())
11500 // Either of these situations may happen with calls.
11506 GenTreeCall* call = node->AsCall();
11507 if (operand == call->gtCallObjp)
11509 sprintf_s(buf, sizeof(buf), "this in %s", compRegVarName(REG_ARG_0));
11510 displayOperand(operand, buf, operandArc, indentStack, prefixIndent);
11512 else if (operand == call->gtCallAddr)
11514 displayOperand(operand, "calli tgt", operandArc, indentStack, prefixIndent);
11516 else if (operand == call->gtControlExpr)
11518 displayOperand(operand, "control expr", operandArc, indentStack, prefixIndent);
11520 else if (operand == call->gtCallCookie)
11522 displayOperand(operand, "cookie", operandArc, indentStack, prefixIndent);
11526 fgArgTabEntry* curArgTabEntry = gtArgEntryByNode(call, operand);
11527 assert(curArgTabEntry);
11529 if (operand->OperGet() == GT_LIST)
11532 for (GenTreeArgList* element = operand->AsArgList(); element != nullptr; element = element->Rest())
11534 operand = element->Current();
11535 if (curArgTabEntry->lateArgInx == (unsigned)-1)
11537 gtGetArgMsg(call, operand, curArgTabEntry->argNum, listIndex, buf, sizeof(buf));
11541 gtGetLateArgMsg(call, operand, curArgTabEntry->lateArgInx, listIndex, buf, sizeof(buf));
11544 displayOperand(operand, buf, operandArc, indentStack, prefixIndent);
11545 operandArc = IIArc;
11550 if (!curArgTabEntry->isLateArg())
11552 gtGetArgMsg(call, operand, curArgTabEntry->argNum, -1, buf, sizeof(buf));
11556 gtGetLateArgMsg(call, operand, curArgTabEntry->lateArgInx, -1, buf, sizeof(buf));
11559 displayOperand(operand, buf, operandArc, indentStack, prefixIndent);
11563 else if (node->OperIsDynBlkOp())
11565 if (operand == node->AsBlk()->Addr())
11567 displayOperand(operand, "lhs", operandArc, indentStack, prefixIndent);
11569 else if (operand == node->AsBlk()->Data())
11571 displayOperand(operand, "rhs", operandArc, indentStack, prefixIndent);
11575 assert(operand == node->AsDynBlk()->gtDynamicSize);
11576 displayOperand(operand, "size", operandArc, indentStack, prefixIndent);
11579 else if (node->OperGet() == GT_DYN_BLK)
11581 if (operand == node->AsBlk()->Addr())
11583 displayOperand(operand, "lhs", operandArc, indentStack, prefixIndent);
11587 assert(operand == node->AsDynBlk()->gtDynamicSize);
11588 displayOperand(operand, "size", operandArc, indentStack, prefixIndent);
11591 else if (node->OperIs(GT_ASG))
11593 if (operand == node->gtGetOp1())
11595 displayOperand(operand, "lhs", operandArc, indentStack, prefixIndent);
11599 displayOperand(operand, "rhs", operandArc, indentStack, prefixIndent);
11604 displayOperand(operand, "", operandArc, indentStack, prefixIndent);
11607 operandArc = IIArc;
11610 // Visit the operator
11612 if (prefixMsg != nullptr)
11614 printf("%s", prefixMsg);
11617 const bool topOnly = true;
11618 const bool isLIR = true;
11619 gtDispTree(node, &indentStack, nullptr, topOnly, isLIR);
11622 /*****************************************************************************/
11625 /*****************************************************************************
11627 * Check if the given node can be folded,
11628 * and call the methods to perform the folding
11631 GenTree* Compiler::gtFoldExpr(GenTree* tree)
11633 unsigned kind = tree->OperKind();
11635 /* We must have a simple operation to fold */
11637 // If we're in CSE, it's not safe to perform tree
11638 // folding given that it can will potentially
11639 // change considered CSE candidates.
11640 if (optValnumCSE_phase)
11645 if (!(kind & GTK_SMPOP))
11650 GenTree* op1 = tree->gtOp.gtOp1;
11652 /* Filter out non-foldable trees that can have constant children */
11654 assert(kind & (GTK_UNOP | GTK_BINOP));
11655 switch (tree->gtOper)
11665 /* try to fold the current node */
11667 if ((kind & GTK_UNOP) && op1)
11669 if (op1->OperKind() & GTK_CONST)
11671 return gtFoldExprConst(tree);
11674 else if ((kind & GTK_BINOP) && op1 && tree->gtOp.gtOp2 &&
11675 // Don't take out conditionals for debugging
11676 !((opts.compDbgCode || opts.MinOpts()) && tree->OperIsCompare()))
11678 GenTree* op2 = tree->gtOp.gtOp2;
11680 // The atomic operations are exempted here because they are never computable statically;
11681 // one of their arguments is an address.
11682 if (((op1->OperKind() & op2->OperKind()) & GTK_CONST) && !tree->OperIsAtomicOp())
11684 /* both nodes are constants - fold the expression */
11685 return gtFoldExprConst(tree);
11687 else if ((op1->OperKind() | op2->OperKind()) & GTK_CONST)
11689 /* at least one is a constant - see if we have a
11690 * special operator that can use only one constant
11691 * to fold - e.g. booleans */
11693 return gtFoldExprSpecial(tree);
11695 else if (tree->OperIsCompare())
11697 /* comparisons of two local variables can sometimes be folded */
11699 return gtFoldExprCompare(tree);
11701 else if (op2->OperGet() == GT_COLON)
11703 assert(tree->OperGet() == GT_QMARK);
11705 GenTree* colon_op1 = op2->gtOp.gtOp1;
11706 GenTree* colon_op2 = op2->gtOp.gtOp2;
11708 if (gtCompareTree(colon_op1, colon_op2))
11710 // Both sides of the GT_COLON are the same tree
11712 GenTree* sideEffList = nullptr;
11713 gtExtractSideEffList(op1, &sideEffList);
11715 // Clear colon flags only if the qmark itself is not conditionaly executed
11716 if ((tree->gtFlags & GTF_COLON_COND) == 0)
11718 fgWalkTreePre(&colon_op2, gtClearColonCond);
11721 if (sideEffList == nullptr)
11723 // No side-effects, just return colon_op2
11731 printf("\nIdentical GT_COLON trees with side effects! Extracting side effects...\n");
11732 gtDispTree(sideEffList);
11736 // Change the GT_COLON into a GT_COMMA node with the side-effects
11737 op2->ChangeOper(GT_COMMA);
11738 op2->gtFlags |= (sideEffList->gtFlags & GTF_ALL_EFFECT);
11739 op2->gtOp.gtOp1 = sideEffList;
11746 /* Return the original node (folded/bashed or not) */
11751 //------------------------------------------------------------------------
11752 // gtFoldExprCall: see if a call is foldable
11755 // call - call to examine
11758 // The original call if no folding happened.
11759 // An alternative tree if folding happens.
11762 // Checks for calls to Type.op_Equality, Type.op_Inequality, and
11763 // Enum.HasFlag, and if the call is to one of these,
11764 // attempts to optimize.
11766 GenTree* Compiler::gtFoldExprCall(GenTreeCall* call)
11768 // Can only fold calls to special intrinsics.
11769 if ((call->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) == 0)
11774 // Defer folding if not optimizing.
11775 if (opts.compDbgCode || opts.MinOpts())
11780 // Fetch id of the intrinsic.
11781 const CorInfoIntrinsics methodID = info.compCompHnd->getIntrinsicID(call->gtCallMethHnd);
11785 case CORINFO_INTRINSIC_TypeEQ:
11786 case CORINFO_INTRINSIC_TypeNEQ:
11788 noway_assert(call->TypeGet() == TYP_INT);
11789 GenTree* op1 = call->gtCallArgs->gtOp.gtOp1;
11790 GenTree* op2 = call->gtCallArgs->gtOp.gtOp2->gtOp.gtOp1;
11792 // If either operand is known to be a RuntimeType, this can be folded
11793 GenTree* result = gtFoldTypeEqualityCall(methodID, op1, op2);
11794 if (result != nullptr)
11805 // Check for a new-style jit intrinsic.
11806 const NamedIntrinsic ni = lookupNamedIntrinsic(call->gtCallMethHnd);
11808 if (ni == NI_System_Enum_HasFlag)
11810 GenTree* thisOp = call->gtCallObjp;
11811 GenTree* flagOp = call->gtCallArgs->gtOp.gtOp1;
11812 GenTree* result = gtOptimizeEnumHasFlag(thisOp, flagOp);
11814 if (result != nullptr)
11823 //------------------------------------------------------------------------
11824 // gtFoldTypeEqualityCall: see if a (potential) type equality call is foldable
11827 // methodID -- type equality intrinsic ID
11828 // op1 -- first argument to call
11829 // op2 -- second argument to call
11832 // nulltpr if no folding happened.
11833 // An alternative tree if folding happens.
11836 // If either operand is known to be a a RuntimeType, then the type
11837 // equality methods will simply check object identity and so we can
11838 // fold the call into a simple compare of the call's operands.
11840 GenTree* Compiler::gtFoldTypeEqualityCall(CorInfoIntrinsics methodID, GenTree* op1, GenTree* op2)
11842 // The method must be be a type equality intrinsic
11843 assert(methodID == CORINFO_INTRINSIC_TypeEQ || methodID == CORINFO_INTRINSIC_TypeNEQ);
11845 if ((gtGetTypeProducerKind(op1) == TPK_Unknown) && (gtGetTypeProducerKind(op2) == TPK_Unknown))
11850 const genTreeOps simpleOp = (methodID == CORINFO_INTRINSIC_TypeEQ) ? GT_EQ : GT_NE;
11852 JITDUMP("\nFolding call to Type:op_%s to a simple compare via %s\n",
11853 methodID == CORINFO_INTRINSIC_TypeEQ ? "Equality" : "Inequality", GenTree::OpName(simpleOp));
11855 GenTree* compare = gtNewOperNode(simpleOp, TYP_INT, op1, op2);
11860 /*****************************************************************************
11862 * Some comparisons can be folded:
11865 * classVarA == classVarA
11866 * locA + locB == locB + locA
11870 GenTree* Compiler::gtFoldExprCompare(GenTree* tree)
11872 GenTree* op1 = tree->gtOp.gtOp1;
11873 GenTree* op2 = tree->gtOp.gtOp2;
11875 assert(tree->OperIsCompare());
11877 /* Filter out cases that cannot be folded here */
11879 /* Do not fold floats or doubles (e.g. NaN != Nan) */
11881 if (varTypeIsFloating(op1->TypeGet()))
11886 /* Currently we can only fold when the two subtrees exactly match */
11888 if ((tree->gtFlags & GTF_SIDE_EFFECT) || GenTree::Compare(op1, op2, true) == false)
11890 return tree; /* return unfolded tree */
11895 switch (tree->gtOper)
11900 cons = gtNewIconNode(true); /* Folds to GT_CNS_INT(true) */
11906 cons = gtNewIconNode(false); /* Folds to GT_CNS_INT(false) */
11910 assert(!"Unexpected relOp");
11914 /* The node has beeen folded into 'cons' */
11918 fgMorphTreeDone(cons);
11922 cons->gtNext = tree->gtNext;
11923 cons->gtPrev = tree->gtPrev;
11929 //------------------------------------------------------------------------
11930 // gtCreateHandleCompare: generate a type handle comparison
11933 // oper -- comparison operation (equal/not equal)
11934 // op1 -- first operand
11935 // op2 -- second operand
11936 // typeCheckInliningResult -- indicates how the comparison should happen
11939 // Type comparison tree
11942 GenTree* Compiler::gtCreateHandleCompare(genTreeOps oper,
11945 CorInfoInlineTypeCheck typeCheckInliningResult)
11947 // If we can compare pointers directly, just emit the binary operation
11948 if (typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_PASS)
11950 return gtNewOperNode(oper, TYP_INT, op1, op2);
11953 assert(typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_USE_HELPER);
11955 // Emit a call to a runtime helper
11956 GenTreeArgList* helperArgs = gtNewArgList(op1, op2);
11957 GenTree* ret = gtNewHelperCallNode(CORINFO_HELP_ARE_TYPES_EQUIVALENT, TYP_INT, helperArgs);
11960 ret = gtNewOperNode(GT_NE, TYP_INT, ret, gtNewIconNode(0, TYP_INT));
11964 assert(oper == GT_NE);
11965 ret = gtNewOperNode(GT_EQ, TYP_INT, ret, gtNewIconNode(0, TYP_INT));
11971 //------------------------------------------------------------------------
11972 // gtFoldTypeCompare: see if a type comparison can be further simplified
11975 // tree -- tree possibly comparing types
11978 // An alternative tree if folding happens.
11979 // Original tree otherwise.
11983 // typeof(...) == obj.GetType()
11984 // typeof(...) == typeof(...)
11986 // And potentially optimizes away the need to obtain actual
11987 // RuntimeType objects to do the comparison.
11989 GenTree* Compiler::gtFoldTypeCompare(GenTree* tree)
11991 // Only handle EQ and NE
11992 // (maybe relop vs null someday)
11993 const genTreeOps oper = tree->OperGet();
11994 if ((oper != GT_EQ) && (oper != GT_NE))
11999 // Screen for the right kinds of operands
12000 GenTree* const op1 = tree->gtOp.gtOp1;
12001 const TypeProducerKind op1Kind = gtGetTypeProducerKind(op1);
12002 if (op1Kind == TPK_Unknown)
12007 GenTree* const op2 = tree->gtOp.gtOp2;
12008 const TypeProducerKind op2Kind = gtGetTypeProducerKind(op2);
12009 if (op2Kind == TPK_Unknown)
12014 // We must have a handle on one side or the other here to optimize,
12015 // otherwise we can't be sure that optimizing is sound.
12016 const bool op1IsFromHandle = (op1Kind == TPK_Handle);
12017 const bool op2IsFromHandle = (op2Kind == TPK_Handle);
12019 if (!(op1IsFromHandle || op2IsFromHandle))
12024 // If both types are created via handles, we can simply compare
12025 // handles (or the indirection cells for handles) instead of the
12026 // types that they'd create.
12027 if (op1IsFromHandle && op2IsFromHandle)
12029 JITDUMP("Optimizing compare of types-from-handles to instead compare handles\n");
12030 GenTree* op1ClassFromHandle = tree->gtOp.gtOp1->gtCall.gtCallArgs->gtOp.gtOp1;
12031 GenTree* op2ClassFromHandle = tree->gtOp.gtOp2->gtCall.gtCallArgs->gtOp.gtOp1;
12032 GenTree* op1TunneledHandle = nullptr;
12033 GenTree* op2TunneledHandle = nullptr;
12034 CORINFO_CLASS_HANDLE cls1Hnd = NO_CLASS_HANDLE;
12035 CORINFO_CLASS_HANDLE cls2Hnd = NO_CLASS_HANDLE;
12036 unsigned runtimeLookupCount = 0;
12038 // Try and find class handles from op1 and op2
12039 cls1Hnd = gtGetHelperArgClassHandle(op1ClassFromHandle, &runtimeLookupCount, &op1TunneledHandle);
12040 cls2Hnd = gtGetHelperArgClassHandle(op2ClassFromHandle, &runtimeLookupCount, &op2TunneledHandle);
12042 // If we have both class handles, try and resolve the type equality test completely.
12043 bool resolveFailed = false;
12045 if ((cls1Hnd != NO_CLASS_HANDLE) && (cls2Hnd != NO_CLASS_HANDLE))
12047 JITDUMP("Asking runtime to compare %p (%s) and %p (%s) for equality\n", dspPtr(cls1Hnd),
12048 info.compCompHnd->getClassName(cls1Hnd), dspPtr(cls2Hnd), info.compCompHnd->getClassName(cls2Hnd));
12049 TypeCompareState s = info.compCompHnd->compareTypesForEquality(cls1Hnd, cls2Hnd);
12051 if (s != TypeCompareState::May)
12053 // Type comparison result is known.
12054 const bool typesAreEqual = (s == TypeCompareState::Must);
12055 const bool operatorIsEQ = (oper == GT_EQ);
12056 const int compareResult = operatorIsEQ ^ typesAreEqual ? 0 : 1;
12057 JITDUMP("Runtime reports comparison is known at jit time: %u\n", compareResult);
12058 GenTree* result = gtNewIconNode(compareResult);
12060 // Any runtime lookups that fed into this compare are
12061 // now dead code, so they no longer require the runtime context.
12062 assert(lvaGenericsContextUseCount >= runtimeLookupCount);
12063 lvaGenericsContextUseCount -= runtimeLookupCount;
12068 resolveFailed = true;
12074 JITDUMP("Runtime reports comparison is NOT known at jit time\n");
12078 JITDUMP("Could not find handle for %s%s\n", (cls1Hnd == NO_CLASS_HANDLE) ? " cls1" : "",
12079 (cls2Hnd == NO_CLASS_HANDLE) ? " cls2" : "");
12082 // We can't answer the equality comparison definitively at jit
12083 // time, but can still simplfy the comparison.
12085 // Find out how we can compare the two handles.
12086 // NOTE: We're potentially passing NO_CLASS_HANDLE, but the runtime knows what to do with it here.
12087 CorInfoInlineTypeCheck inliningKind =
12088 info.compCompHnd->canInlineTypeCheck(cls1Hnd, CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN);
12090 // If the first type needs helper, check the other type: it might be okay with a simple compare.
12091 if (inliningKind == CORINFO_INLINE_TYPECHECK_USE_HELPER)
12093 inliningKind = info.compCompHnd->canInlineTypeCheck(cls2Hnd, CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN);
12096 assert(inliningKind == CORINFO_INLINE_TYPECHECK_PASS || inliningKind == CORINFO_INLINE_TYPECHECK_USE_HELPER);
12098 // If we successfully tunneled through both operands, compare
12099 // the tunneled values, otherwise compare the original values.
12101 if ((op1TunneledHandle != nullptr) && (op2TunneledHandle != nullptr))
12103 compare = gtCreateHandleCompare(oper, op1TunneledHandle, op2TunneledHandle, inliningKind);
12107 compare = gtCreateHandleCompare(oper, op1ClassFromHandle, op2ClassFromHandle, inliningKind);
12110 // Drop any now-irrelvant flags
12111 compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
12116 // Just one operand creates a type from a handle.
12118 // If the other operand is fetching the type from an object,
12119 // we can sometimes optimize the type compare into a simpler
12120 // method table comparison.
12122 // TODO: if other operand is null...
12123 if ((op1Kind != TPK_GetType) && (op2Kind != TPK_GetType))
12128 GenTree* const opHandle = op1IsFromHandle ? op1 : op2;
12129 GenTree* const opOther = op1IsFromHandle ? op2 : op1;
12131 // Tunnel through the handle operand to get at the class handle involved.
12132 GenTree* const opHandleArgument = opHandle->gtCall.gtCallArgs->gtOp.gtOp1;
12133 CORINFO_CLASS_HANDLE clsHnd = gtGetHelperArgClassHandle(opHandleArgument);
12135 // If we couldn't find the class handle, give up.
12136 if (clsHnd == NO_CLASS_HANDLE)
12141 // Ask the VM if this type can be equality tested by a simple method
12142 // table comparison.
12143 CorInfoInlineTypeCheck typeCheckInliningResult =
12144 info.compCompHnd->canInlineTypeCheck(clsHnd, CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE);
12145 if (typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_NONE)
12150 // We're good to go.
12151 JITDUMP("Optimizing compare of obj.GetType()"
12152 " and type-from-handle to compare method table pointer\n");
12154 // opHandleArgument is the method table we're looking for.
12155 GenTree* const knownMT = opHandleArgument;
12157 // Fetch object method table from the object itself.
12158 GenTree* objOp = nullptr;
12160 // Note we may see intrinsified or regular calls to GetType
12161 if (opOther->OperGet() == GT_INTRINSIC)
12163 objOp = opOther->gtUnOp.gtOp1;
12167 assert(opOther->OperGet() == GT_CALL);
12168 objOp = opOther->gtCall.gtCallObjp;
12171 GenTree* const objMT = gtNewOperNode(GT_IND, TYP_I_IMPL, objOp);
12173 // Update various flags
12174 objMT->gtFlags |= GTF_EXCEPT;
12175 compCurBB->bbFlags |= BBF_HAS_VTABREF;
12176 optMethodFlags |= OMF_HAS_VTABLEREF;
12178 // Compare the two method tables
12179 GenTree* const compare = gtCreateHandleCompare(oper, objMT, knownMT, typeCheckInliningResult);
12181 // Drop any now irrelevant flags
12182 compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
12188 //------------------------------------------------------------------------
12189 // gtGetHelperArgClassHandle: find the compile time class handle from
12190 // a helper call argument tree
12193 // tree - tree that passes the handle to the helper
12194 // runtimeLookupCount [optional, in/out] - incremented if tree was a runtime lookup
12195 // handleTree [optional, out] - set to the literal operand tree for indirect handles
12198 // The compile time class handle if known.
12200 CORINFO_CLASS_HANDLE Compiler::gtGetHelperArgClassHandle(GenTree* tree,
12201 unsigned* runtimeLookupCount,
12202 GenTree** handleTree)
12204 CORINFO_CLASS_HANDLE result = NO_CLASS_HANDLE;
12206 // Walk through any wrapping nop.
12207 if ((tree->gtOper == GT_NOP) && (tree->gtType == TYP_I_IMPL))
12209 tree = tree->gtOp.gtOp1;
12212 // The handle could be a literal constant
12213 if ((tree->OperGet() == GT_CNS_INT) && (tree->TypeGet() == TYP_I_IMPL))
12215 assert(tree->IsIconHandle(GTF_ICON_CLASS_HDL));
12216 result = (CORINFO_CLASS_HANDLE)tree->gtIntCon.gtCompileTimeHandle;
12218 // Or the result of a runtime lookup
12219 else if (tree->OperGet() == GT_RUNTIMELOOKUP)
12221 result = tree->AsRuntimeLookup()->GetClassHandle();
12223 if (runtimeLookupCount != nullptr)
12225 *runtimeLookupCount = *runtimeLookupCount + 1;
12228 // Or something reached indirectly
12229 else if (tree->gtOper == GT_IND)
12231 // The handle indirs we are looking for will be marked as non-faulting.
12232 // Certain others (eg from refanytype) may not be.
12233 if (tree->gtFlags & GTF_IND_NONFAULTING)
12235 GenTree* handleTreeInternal = tree->gtOp.gtOp1;
12237 if ((handleTreeInternal->OperGet() == GT_CNS_INT) && (handleTreeInternal->TypeGet() == TYP_I_IMPL))
12239 // These handle constants should be class handles.
12240 assert(handleTreeInternal->IsIconHandle(GTF_ICON_CLASS_HDL));
12241 result = (CORINFO_CLASS_HANDLE)handleTreeInternal->gtIntCon.gtCompileTimeHandle;
12243 if (handleTree != nullptr)
12245 *handleTree = handleTreeInternal;
12254 /*****************************************************************************
12256 * Some binary operators can be folded even if they have only one
12257 * operand constant - e.g. boolean operators, add with 0
12258 * multiply with 1, etc
12261 GenTree* Compiler::gtFoldExprSpecial(GenTree* tree)
12263 GenTree* op1 = tree->gtOp.gtOp1;
12264 GenTree* op2 = tree->gtOp.gtOp2;
12265 genTreeOps oper = tree->OperGet();
12271 assert(tree->OperKind() & GTK_BINOP);
12273 /* Filter out operators that cannot be folded here */
12274 if (oper == GT_CAST)
12279 /* We only consider TYP_INT for folding
12280 * Do not fold pointer arithmetic (e.g. addressing modes!) */
12282 if (oper != GT_QMARK && !varTypeIsIntOrI(tree->gtType))
12287 /* Find out which is the constant node */
12289 if (op1->IsCnsIntOrI())
12294 else if (op2->IsCnsIntOrI())
12304 /* Get the constant value */
12306 val = cons->gtIntConCommon.IconValue();
12308 /* Here op is the non-constant operand, val is the constant,
12309 first is true if the constant is op1 */
12317 // Optimize boxed value classes; these are always false. This IL is
12318 // generated when a generic value is tested against null:
12319 // <T> ... foo(T x) { ... if ((object)x == null) ...
12320 if (val == 0 && op->IsBoxedValue())
12322 JITDUMP("\nAttempting to optimize BOX(valueType) %s null [%06u]\n", GenTree::OpName(oper),
12325 // We don't expect GT_GT with signed compares, and we
12326 // can't predict the result if we do see it, since the
12327 // boxed object addr could have its high bit set.
12328 if ((oper == GT_GT) && !tree->IsUnsigned())
12330 JITDUMP(" bailing; unexpected signed compare via GT_GT\n");
12334 // The tree under the box must be side effect free
12335 // since we will drop it if we optimize.
12336 assert(!gtTreeHasSideEffects(op->gtBox.gtOp.gtOp1, GTF_SIDE_EFFECT));
12338 // See if we can optimize away the box and related statements.
12339 GenTree* boxSourceTree = gtTryRemoveBoxUpstreamEffects(op);
12340 bool didOptimize = (boxSourceTree != nullptr);
12342 // If optimization succeeded, remove the box.
12345 // Set up the result of the compare.
12346 int compareResult = 0;
12349 // GT_GT(null, box) == false
12350 // GT_GT(box, null) == true
12351 compareResult = (op1 == op);
12353 else if (oper == GT_EQ)
12355 // GT_EQ(box, null) == false
12356 // GT_EQ(null, box) == false
12361 assert(oper == GT_NE);
12362 // GT_NE(box, null) == true
12363 // GT_NE(null, box) == true
12367 JITDUMP("\nSuccess: replacing BOX(valueType) %s null with %d\n", GenTree::OpName(oper),
12370 op = gtNewIconNode(compareResult);
12374 fgMorphTreeDone(op);
12378 op->gtNext = tree->gtNext;
12379 op->gtPrev = tree->gtPrev;
12403 /* Multiply by zero - return the 'zero' node, but not if side effects */
12404 if (!(op->gtFlags & GTF_SIDE_EFFECT))
12414 if ((op2 == cons) && (val == 1) && !(op1->OperKind() & GTK_CONST))
12421 if ((op2 == cons) && (val == 0) && !(op1->OperKind() & GTK_CONST))
12430 /* AND with zero - return the 'zero' node, but not if side effects */
12432 if (!(op->gtFlags & GTF_SIDE_EFFECT))
12440 /* The GTF_BOOLEAN flag is set for nodes that are part
12441 * of a boolean expression, thus all their children
12442 * are known to evaluate to only 0 or 1 */
12444 if (tree->gtFlags & GTF_BOOLEAN)
12447 /* The constant value must be 1
12448 * AND with 1 stays the same */
12460 else if (tree->gtFlags & GTF_BOOLEAN)
12462 /* The constant value must be 1 - OR with 1 is 1 */
12466 /* OR with one - return the 'one' node, but not if side effects */
12468 if (!(op->gtFlags & GTF_SIDE_EFFECT))
12487 else if (!(op->gtFlags & GTF_SIDE_EFFECT))
12497 assert(op1 == cons && op2 == op && op2->gtOper == GT_COLON);
12498 assert(op2->gtOp.gtOp1 && op2->gtOp.gtOp2);
12500 assert(val == 0 || val == 1);
12502 GenTree* opToDelete;
12505 op = op2->AsColon()->ThenNode();
12506 opToDelete = op2->AsColon()->ElseNode();
12510 op = op2->AsColon()->ElseNode();
12511 opToDelete = op2->AsColon()->ThenNode();
12514 // Clear colon flags only if the qmark itself is not conditionaly executed
12515 if ((tree->gtFlags & GTF_COLON_COND) == 0)
12517 fgWalkTreePre(&op, gtClearColonCond);
12527 /* The node is not foldable */
12533 /* The node has beeen folded into 'op' */
12535 // If there was an assigment update, we just morphed it into
12536 // a use, update the flags appropriately
12537 if (op->gtOper == GT_LCL_VAR)
12539 assert(tree->OperIs(GT_ASG) || (op->gtFlags & (GTF_VAR_USEASG | GTF_VAR_DEF)) == 0);
12541 op->gtFlags &= ~(GTF_VAR_USEASG | GTF_VAR_DEF);
12544 op->gtNext = tree->gtNext;
12545 op->gtPrev = tree->gtPrev;
12550 //------------------------------------------------------------------------
12551 // gtTryRemoveBoxUpstreamEffects: given an unused value type box,
12552 // try and remove the upstream allocation and unnecessary parts of
12556 // op - the box node to optimize
12557 // options - controls whether and how trees are modified
12561 // A tree representing the original value to box, if removal
12562 // is successful/possible (but see note). nullptr if removal fails.
12565 // Value typed box gets special treatment because it has associated
12566 // side effects that can be removed if the box result is not used.
12568 // By default (options == BR_REMOVE_AND_NARROW) this method will
12569 // try and remove unnecessary trees and will try and reduce remaning
12570 // operations to the minimal set, possibly narrowing the width of
12571 // loads from the box source if it is a struct.
12573 // To perform a trial removal, pass BR_DONT_REMOVE. This can be
12574 // useful to determine if this optimization should only be
12575 // performed if some other conditions hold true.
12577 // To remove but not alter the access to the box source, pass
12578 // BR_REMOVE_BUT_NOT_NARROW.
12580 // To remove and return the tree for the type handle used for
12581 // the boxed newobj, pass BR_REMOVE_BUT_NOT_NARROW_WANT_TYPE_HANDLE.
12582 // This can be useful when the only part of the box that is "live"
12585 // If removal fails, is is possible that a subsequent pass may be
12586 // able to optimize. Blocking side effects may now be minimized
12587 // (null or bounds checks might have been removed) or might be
12588 // better known (inline return placeholder updated with the actual
12589 // return expression). So the box is perhaps best left as is to
12590 // help trigger this re-examination.
12592 GenTree* Compiler::gtTryRemoveBoxUpstreamEffects(GenTree* op, BoxRemovalOptions options)
12594 assert(op->IsBoxedValue());
12596 // grab related parts for the optimization
12597 GenTreeBox* box = op->AsBox();
12598 GenTree* asgStmt = box->gtAsgStmtWhenInlinedBoxValue;
12599 GenTree* copyStmt = box->gtCopyStmtWhenInlinedBoxValue;
12601 assert(asgStmt->gtOper == GT_STMT);
12602 assert(copyStmt->gtOper == GT_STMT);
12604 JITDUMP("gtTryRemoveBoxUpstreamEffects: %s to %s of BOX (valuetype)"
12605 " [%06u] (assign/newobj [%06u] copy [%06u])\n",
12606 (options == BR_DONT_REMOVE) ? "checking if it is possible" : "attempting",
12607 (options == BR_MAKE_LOCAL_COPY) ? "make local unboxed version" : "remove side effects", dspTreeID(op),
12608 dspTreeID(asgStmt), dspTreeID(copyStmt));
12610 // If we don't recognize the form of the assign, bail.
12611 GenTree* asg = asgStmt->gtStmt.gtStmtExpr;
12612 if (asg->gtOper != GT_ASG)
12614 JITDUMP(" bailing; unexpected assignment op %s\n", GenTree::OpName(asg->gtOper));
12618 // If we're eventually going to return the type handle, remember it now.
12619 GenTree* boxTypeHandle = nullptr;
12620 if ((options == BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE) || (options == BR_DONT_REMOVE_WANT_TYPE_HANDLE))
12622 GenTree* asgSrc = asg->gtOp.gtOp2;
12623 genTreeOps asgSrcOper = asgSrc->OperGet();
12625 // Allocation may be via AllocObj or via helper call, depending
12626 // on when this is invoked and whether the jit is using AllocObj
12627 // for R2R allocations.
12628 if (asgSrcOper == GT_ALLOCOBJ)
12630 GenTreeAllocObj* allocObj = asgSrc->AsAllocObj();
12631 boxTypeHandle = allocObj->gtOp.gtOp1;
12633 else if (asgSrcOper == GT_CALL)
12635 GenTreeCall* newobjCall = asgSrc->AsCall();
12636 GenTree* newobjArgs = newobjCall->gtCallArgs;
12638 // In R2R expansions the handle may not be an explicit operand to the helper,
12639 // so we can't remove the box.
12640 if (newobjArgs == nullptr)
12642 assert(newobjCall->IsHelperCall(this, CORINFO_HELP_READYTORUN_NEW));
12643 JITDUMP(" bailing; newobj via R2R helper\n");
12647 boxTypeHandle = newobjArgs->AsArgList()->Current();
12654 assert(boxTypeHandle != nullptr);
12657 // If we don't recognize the form of the copy, bail.
12658 GenTree* copy = copyStmt->gtStmt.gtStmtExpr;
12659 if (copy->gtOper != GT_ASG)
12661 // GT_RET_EXPR is a tolerable temporary failure.
12662 // The jit will revisit this optimization after
12663 // inlining is done.
12664 if (copy->gtOper == GT_RET_EXPR)
12666 JITDUMP(" bailing; must wait for replacement of copy %s\n", GenTree::OpName(copy->gtOper));
12670 // Anything else is a missed case we should
12671 // figure out how to handle. One known case
12672 // is GT_COMMAs enclosing the GT_ASG we are
12674 JITDUMP(" bailing; unexpected copy op %s\n", GenTree::OpName(copy->gtOper));
12679 // Handle case where we are optimizing the box into a local copy
12680 if (options == BR_MAKE_LOCAL_COPY)
12682 // Drill into the box to get at the box temp local and the box type
12683 GenTree* boxTemp = box->BoxOp();
12684 assert(boxTemp->IsLocal());
12685 const unsigned boxTempLcl = boxTemp->AsLclVar()->GetLclNum();
12686 assert(lvaTable[boxTempLcl].lvType == TYP_REF);
12687 CORINFO_CLASS_HANDLE boxClass = lvaTable[boxTempLcl].lvClassHnd;
12688 assert(boxClass != nullptr);
12690 // Verify that the copyDst has the expected shape
12691 // (blk|obj|ind (add (boxTempLcl, ptr-size)))
12693 // The shape here is constrained to the patterns we produce
12694 // over in impImportAndPushBox for the inlined box case.
12695 GenTree* copyDst = copy->gtOp.gtOp1;
12697 if (!copyDst->OperIs(GT_BLK, GT_IND, GT_OBJ))
12699 JITDUMP("Unexpected copy dest operator %s\n", GenTree::OpName(copyDst->gtOper));
12703 GenTree* copyDstAddr = copyDst->gtOp.gtOp1;
12704 if (copyDstAddr->OperGet() != GT_ADD)
12706 JITDUMP("Unexpected copy dest address tree\n");
12710 GenTree* copyDstAddrOp1 = copyDstAddr->gtOp.gtOp1;
12711 if ((copyDstAddrOp1->OperGet() != GT_LCL_VAR) || (copyDstAddrOp1->gtLclVarCommon.gtLclNum != boxTempLcl))
12713 JITDUMP("Unexpected copy dest address 1st addend\n");
12717 GenTree* copyDstAddrOp2 = copyDstAddr->gtOp.gtOp2;
12718 if (!copyDstAddrOp2->IsIntegralConst(TARGET_POINTER_SIZE))
12720 JITDUMP("Unexpected copy dest address 2nd addend\n");
12724 // Screening checks have all passed. Do the transformation.
12726 // Retype the box temp to be a struct
12727 JITDUMP("Retyping box temp V%02u to struct %s\n", boxTempLcl, eeGetClassName(boxClass));
12728 lvaTable[boxTempLcl].lvType = TYP_UNDEF;
12729 const bool isUnsafeValueClass = false;
12730 lvaSetStruct(boxTempLcl, boxClass, isUnsafeValueClass);
12731 var_types boxTempType = lvaTable[boxTempLcl].lvType;
12733 // Remove the newobj and assigment to box temp
12734 JITDUMP("Bashing NEWOBJ [%06u] to NOP\n", dspTreeID(asg));
12735 asg->gtBashToNOP();
12737 // Update the copy from the value to be boxed to the box temp
12738 GenTree* newDst = gtNewOperNode(GT_ADDR, TYP_BYREF, gtNewLclvNode(boxTempLcl, boxTempType));
12739 copyDst->gtOp.gtOp1 = newDst;
12741 // Return the address of the now-struct typed box temp
12742 GenTree* retValue = gtNewOperNode(GT_ADDR, TYP_BYREF, gtNewLclvNode(boxTempLcl, boxTempType));
12747 // If the copy is a struct copy, make sure we know how to isolate
12748 // any source side effects.
12749 GenTree* copySrc = copy->gtOp.gtOp2;
12751 // If the copy source is from a pending inline, wait for it to resolve.
12752 if (copySrc->gtOper == GT_RET_EXPR)
12754 JITDUMP(" bailing; must wait for replacement of copy source %s\n", GenTree::OpName(copySrc->gtOper));
12758 bool hasSrcSideEffect = false;
12759 bool isStructCopy = false;
12761 if (gtTreeHasSideEffects(copySrc, GTF_SIDE_EFFECT))
12763 hasSrcSideEffect = true;
12765 if (varTypeIsStruct(copySrc->gtType))
12767 isStructCopy = true;
12769 if ((copySrc->gtOper != GT_OBJ) && (copySrc->gtOper != GT_IND) && (copySrc->gtOper != GT_FIELD))
12771 // We don't know how to handle other cases, yet.
12772 JITDUMP(" bailing; unexpected copy source struct op with side effect %s\n",
12773 GenTree::OpName(copySrc->gtOper));
12779 // If this was a trial removal, we're done.
12780 if (options == BR_DONT_REMOVE)
12785 if (options == BR_DONT_REMOVE_WANT_TYPE_HANDLE)
12787 return boxTypeHandle;
12790 // Otherwise, proceed with the optimization.
12792 // Change the assignment expression to a NOP.
12793 JITDUMP("\nBashing NEWOBJ [%06u] to NOP\n", dspTreeID(asg));
12794 asg->gtBashToNOP();
12796 // Change the copy expression so it preserves key
12797 // source side effects.
12798 JITDUMP("\nBashing COPY [%06u]", dspTreeID(copy));
12800 if (!hasSrcSideEffect)
12802 // If there were no copy source side effects just bash
12803 // the copy to a NOP.
12804 copy->gtBashToNOP();
12805 JITDUMP(" to NOP; no source side effects.\n");
12807 else if (!isStructCopy)
12809 // For scalar types, go ahead and produce the
12810 // value as the copy is fairly cheap and likely
12811 // the optimizer can trim things down to just the
12812 // minimal side effect parts.
12813 copyStmt->gtStmt.gtStmtExpr = copySrc;
12814 JITDUMP(" to scalar read via [%06u]\n", dspTreeID(copySrc));
12818 // For struct types read the first byte of the
12819 // source struct; there's no need to read the
12820 // entire thing, and no place to put it.
12821 assert(copySrc->gtOper == GT_OBJ || copySrc->gtOper == GT_IND || copySrc->gtOper == GT_FIELD);
12822 copyStmt->gtStmt.gtStmtExpr = copySrc;
12824 if (options == BR_REMOVE_AND_NARROW || options == BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE)
12826 JITDUMP(" to read first byte of struct via modified [%06u]\n", dspTreeID(copySrc));
12827 copySrc->ChangeOper(GT_IND);
12828 copySrc->gtType = TYP_BYTE;
12832 JITDUMP(" to read entire struct via modified [%06u]\n", dspTreeID(copySrc));
12836 if (fgStmtListThreaded)
12838 fgSetStmtSeq(asgStmt);
12839 fgSetStmtSeq(copyStmt);
12842 // Box effects were successfully optimized.
12844 if (options == BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE)
12846 return boxTypeHandle;
12854 //------------------------------------------------------------------------
12855 // gtOptimizeEnumHasFlag: given the operands for a call to Enum.HasFlag,
12856 // try and optimize the call to a simple and/compare tree.
12859 // thisOp - first argument to the call
12860 // flagOp - second argument to the call
12863 // A new cmp/amd tree if successful. nullptr on failure.
12866 // If successful, may allocate new temps and modify connected
12869 GenTree* Compiler::gtOptimizeEnumHasFlag(GenTree* thisOp, GenTree* flagOp)
12871 JITDUMP("Considering optimizing call to Enum.HasFlag....\n");
12873 // Operands must be boxes
12874 if (!thisOp->IsBoxedValue() || !flagOp->IsBoxedValue())
12876 JITDUMP("bailing, need both inputs to be BOXes\n");
12880 // Operands must have same type
12881 bool isExactThis = false;
12882 bool isNonNullThis = false;
12883 CORINFO_CLASS_HANDLE thisHnd = gtGetClassHandle(thisOp, &isExactThis, &isNonNullThis);
12885 if (thisHnd == nullptr)
12887 JITDUMP("bailing, can't find type for 'this' operand\n");
12891 // A boxed thisOp should have exact type and non-null instance
12892 assert(isExactThis);
12893 assert(isNonNullThis);
12895 bool isExactFlag = false;
12896 bool isNonNullFlag = false;
12897 CORINFO_CLASS_HANDLE flagHnd = gtGetClassHandle(flagOp, &isExactFlag, &isNonNullFlag);
12899 if (flagHnd == nullptr)
12901 JITDUMP("bailing, can't find type for 'flag' operand\n");
12905 // A boxed flagOp should have exact type and non-null instance
12906 assert(isExactFlag);
12907 assert(isNonNullFlag);
12909 if (flagHnd != thisHnd)
12911 JITDUMP("bailing, operand types differ\n");
12915 // If we have a shared type instance we can't safely check type
12916 // equality, so bail.
12917 DWORD classAttribs = info.compCompHnd->getClassAttribs(thisHnd);
12918 if (classAttribs & CORINFO_FLG_SHAREDINST)
12920 JITDUMP("bailing, have shared instance type\n");
12924 // Simulate removing the box for thisOP. We need to know that it can
12925 // be safely removed before we can optimize.
12926 GenTree* thisVal = gtTryRemoveBoxUpstreamEffects(thisOp, BR_DONT_REMOVE);
12927 if (thisVal == nullptr)
12929 // Note we may fail here if the this operand comes from
12930 // a call. We should be able to retry this post-inlining.
12931 JITDUMP("bailing, can't undo box of 'this' operand\n");
12935 GenTree* flagVal = gtTryRemoveBoxUpstreamEffects(flagOp, BR_REMOVE_BUT_NOT_NARROW);
12936 if (flagVal == nullptr)
12938 // Note we may fail here if the flag operand comes from
12939 // a call. We should be able to retry this post-inlining.
12940 JITDUMP("bailing, can't undo box of 'flag' operand\n");
12944 // Yes, both boxes can be cleaned up. Optimize.
12945 JITDUMP("Optimizing call to Enum.HasFlag\n");
12947 // Undo the boxing of thisOp and prepare to operate directly
12948 // on the original enum values.
12949 thisVal = gtTryRemoveBoxUpstreamEffects(thisOp, BR_REMOVE_BUT_NOT_NARROW);
12951 // Our trial removal above should guarantee successful removal here.
12952 assert(thisVal != nullptr);
12954 // We should have a consistent view of the type
12955 var_types type = thisVal->TypeGet();
12956 assert(type == flagVal->TypeGet());
12958 // The thisVal and flagVal trees come from earlier statements.
12960 // Unless they are invariant values, we need to evaluate them both
12961 // to temps at those points to safely transmit the values here.
12963 // Also we need to use the flag twice, so we need two trees for it.
12964 GenTree* thisValOpt = nullptr;
12965 GenTree* flagValOpt = nullptr;
12966 GenTree* flagValOptCopy = nullptr;
12968 if (thisVal->IsIntegralConst())
12970 thisValOpt = gtClone(thisVal);
12971 assert(thisValOpt != nullptr);
12975 const unsigned thisTmp = lvaGrabTemp(true DEBUGARG("Enum:HasFlag this temp"));
12976 GenTree* thisAsg = gtNewTempAssign(thisTmp, thisVal);
12977 GenTree* thisAsgStmt = thisOp->AsBox()->gtCopyStmtWhenInlinedBoxValue;
12978 thisAsgStmt->gtStmt.gtStmtExpr = thisAsg;
12979 thisValOpt = gtNewLclvNode(thisTmp, type);
12982 if (flagVal->IsIntegralConst())
12984 flagValOpt = gtClone(flagVal);
12985 assert(flagValOpt != nullptr);
12986 flagValOptCopy = gtClone(flagVal);
12987 assert(flagValOptCopy != nullptr);
12991 const unsigned flagTmp = lvaGrabTemp(true DEBUGARG("Enum:HasFlag flag temp"));
12992 GenTree* flagAsg = gtNewTempAssign(flagTmp, flagVal);
12993 GenTree* flagAsgStmt = flagOp->AsBox()->gtCopyStmtWhenInlinedBoxValue;
12994 flagAsgStmt->gtStmt.gtStmtExpr = flagAsg;
12995 flagValOpt = gtNewLclvNode(flagTmp, type);
12996 flagValOptCopy = gtNewLclvNode(flagTmp, type);
12999 // Turn the call into (thisValTmp & flagTmp) == flagTmp.
13000 GenTree* andTree = gtNewOperNode(GT_AND, type, thisValOpt, flagValOpt);
13001 GenTree* cmpTree = gtNewOperNode(GT_EQ, TYP_INT, andTree, flagValOptCopy);
13003 JITDUMP("Optimized call to Enum.HasFlag\n");
13008 /*****************************************************************************
13010 * Fold the given constant tree.
13014 #pragma warning(push)
13015 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
13017 GenTree* Compiler::gtFoldExprConst(GenTree* tree)
13019 unsigned kind = tree->OperKind();
13021 SSIZE_T i1, i2, itemp;
13022 INT64 lval1, lval2, ltemp;
13025 var_types switchType;
13026 FieldSeqNode* fieldSeq = FieldSeqStore::NotAField(); // default unless we override it when folding
13028 assert(kind & (GTK_UNOP | GTK_BINOP));
13030 GenTree* op1 = tree->gtOp.gtOp1;
13031 GenTree* op2 = tree->gtGetOp2IfPresent();
13033 if (!opts.OptEnabled(CLFLG_CONSTANTFOLD))
13038 if (tree->OperGet() == GT_NOP)
13043 #ifdef FEATURE_SIMD
13044 if (tree->OperGet() == GT_SIMD)
13048 #endif // FEATURE_SIMD
13050 if (tree->gtOper == GT_ALLOCOBJ)
13055 if (tree->gtOper == GT_RUNTIMELOOKUP)
13060 if (kind & GTK_UNOP)
13062 assert(op1->OperKind() & GTK_CONST);
13064 switch (op1->gtType)
13068 /* Fold constant INT unary operator */
13070 if (!op1->gtIntCon.ImmedValCanBeFolded(this, tree->OperGet()))
13075 i1 = (int)op1->gtIntCon.gtIconVal;
13077 // If we fold a unary oper, then the folded constant
13078 // is considered a ConstantIndexField if op1 was one
13081 if ((op1->gtIntCon.gtFieldSeq != nullptr) && op1->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
13083 fieldSeq = op1->gtIntCon.gtFieldSeq;
13086 switch (tree->gtOper)
13097 i1 = ((i1 >> 24) & 0xFF) | ((i1 >> 8) & 0xFF00) | ((i1 << 8) & 0xFF0000) |
13098 ((i1 << 24) & 0xFF000000);
13102 i1 = ((i1 >> 8) & 0xFF) | ((i1 << 8) & 0xFF00);
13106 // assert (genActualType(tree->CastToType()) == tree->gtType);
13107 switch (tree->CastToType())
13110 itemp = INT32(INT8(i1));
13114 itemp = INT32(INT16(i1));
13116 if (tree->gtOverflow() && ((itemp != i1) || ((tree->gtFlags & GTF_UNSIGNED) && i1 < 0)))
13124 itemp = INT32(UINT16(i1));
13125 if (tree->gtOverflow())
13137 itemp = INT32(UINT8(i1));
13138 if (tree->gtOverflow())
13149 if (!(tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && i1 < 0)
13156 if ((tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && i1 < 0)
13163 if (tree->IsUnsigned())
13165 lval1 = UINT64(UINT32(i1));
13169 if (tree->gtOverflow() && (i1 < 0))
13173 lval1 = UINT64(INT32(i1));
13178 if (tree->IsUnsigned())
13180 lval1 = INT64(UINT32(i1));
13184 lval1 = INT64(INT32(i1));
13189 if (tree->gtFlags & GTF_UNSIGNED)
13191 f1 = forceCastToFloat(UINT32(i1));
13195 f1 = forceCastToFloat(INT32(i1));
13201 if (tree->gtFlags & GTF_UNSIGNED)
13203 d1 = (double)UINT32(i1);
13207 d1 = (double)INT32(i1);
13212 assert(!"BAD_TYP");
13225 /* Fold constant LONG unary operator */
13227 if (!op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13232 lval1 = op1->gtIntConCommon.LngValue();
13234 switch (tree->gtOper)
13245 lval1 = ((lval1 >> 56) & 0xFF) | ((lval1 >> 40) & 0xFF00) | ((lval1 >> 24) & 0xFF0000) |
13246 ((lval1 >> 8) & 0xFF000000) | ((lval1 << 8) & 0xFF00000000) |
13247 ((lval1 << 24) & 0xFF0000000000) | ((lval1 << 40) & 0xFF000000000000) |
13248 ((lval1 << 56) & 0xFF00000000000000);
13252 assert(genActualType(tree->CastToType()) == tree->gtType);
13253 switch (tree->CastToType())
13256 i1 = INT32(INT8(lval1));
13257 goto CHECK_INT_OVERFLOW;
13260 i1 = INT32(INT16(lval1));
13261 goto CHECK_INT_OVERFLOW;
13264 i1 = INT32(UINT16(lval1));
13265 goto CHECK_UINT_OVERFLOW;
13268 i1 = INT32(UINT8(lval1));
13269 goto CHECK_UINT_OVERFLOW;
13274 CHECK_INT_OVERFLOW:
13275 if (tree->gtOverflow())
13281 if ((tree->gtFlags & GTF_UNSIGNED) && i1 < 0)
13289 i1 = UINT32(lval1);
13291 CHECK_UINT_OVERFLOW:
13292 if (tree->gtOverflow() && UINT32(i1) != lval1)
13299 if (!(tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && lval1 < 0)
13306 if ((tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && lval1 < 0)
13314 if ((tree->gtFlags & GTF_UNSIGNED) && lval1 < 0)
13316 d1 = FloatingPointUtils::convertUInt64ToDouble((unsigned __int64)lval1);
13320 d1 = (double)lval1;
13323 if (tree->CastToType() == TYP_FLOAT)
13325 f1 = forceCastToFloat(d1); // truncate precision
13330 assert(!"BAD_TYP");
13343 assert(op1->gtOper == GT_CNS_DBL);
13345 /* Fold constant DOUBLE unary operator */
13347 d1 = op1->gtDblCon.gtDconVal;
13349 switch (tree->gtOper)
13357 if (tree->gtOverflowEx())
13362 assert(genActualType(tree->CastToType()) == tree->gtType);
13364 if ((op1->gtType == TYP_FLOAT && !_finite(forceCastToFloat(d1))) ||
13365 (op1->gtType == TYP_DOUBLE && !_finite(d1)))
13367 // The floating point constant is not finite. The ECMA spec says, in
13368 // III 3.27, that "...if overflow occurs converting a floating point type
13369 // to an integer, ..., the value returned is unspecified." However, it would
13370 // at least be desirable to have the same value returned for casting an overflowing
13371 // constant to an int as would obtained by passing that constant as a parameter
13372 // then casting that parameter to an int type. We will assume that the C compiler's
13373 // cast logic will yield the desired result (and trust testing to tell otherwise).
13374 // Cross-compilation is an issue here; if that becomes an important scenario, we should
13375 // capture the target-specific values of overflow casts to the various integral types as
13376 // constants in a target-specific function.
13377 CLANG_FORMAT_COMMENT_ANCHOR;
13379 // Don't fold conversions of +inf/-inf to integral value on all platforms
13380 // as the value returned by JIT helper doesn't match with the C compiler's cast result.
13381 // We want the behavior to be same with or without folding.
13385 if (d1 <= -1.0 && varTypeIsUnsigned(tree->CastToType()))
13387 // Don't fold conversions of these cases becasue the result is unspecified per ECMA spec
13388 // and the native math doing the fold doesn't match the run-time computation on all
13390 // We want the behavior to be same with or without folding.
13394 switch (tree->CastToType())
13397 i1 = INT32(INT8(d1));
13401 i1 = INT32(INT16(d1));
13405 i1 = INT32(UINT16(d1));
13409 i1 = INT32(UINT8(d1));
13417 i1 = forceCastToUInt32(d1);
13425 lval1 = FloatingPointUtils::convertDoubleToUInt64(d1);
13429 d1 = forceCastToFloat(d1);
13433 if (op1->gtType == TYP_FLOAT)
13435 d1 = forceCastToFloat(d1); // truncate precision
13437 goto CNS_DOUBLE; // redundant cast
13440 assert(!"BAD_TYP");
13451 /* not a foldable typ - e.g. RET const */
13456 /* We have a binary operator */
13458 assert(kind & GTK_BINOP);
13460 assert(op1->OperKind() & GTK_CONST);
13461 assert(op2->OperKind() & GTK_CONST);
13463 if (tree->gtOper == GT_COMMA)
13468 if (tree->OperIsAnyList())
13473 switchType = op1->gtType;
13475 // Normally we will just switch on op1 types, but for the case where
13476 // only op2 is a GC type and op1 is not a GC type, we use the op2 type.
13477 // This makes us handle this as a case of folding for GC type.
13479 if (varTypeIsGC(op2->gtType) && !varTypeIsGC(op1->gtType))
13481 switchType = op2->gtType;
13484 switch (switchType)
13487 /*-------------------------------------------------------------------------
13488 * Fold constant REF of BYREF binary operator
13489 * These can only be comparisons or null pointers
13494 /* String nodes are an RVA at this point */
13496 if (op1->gtOper == GT_CNS_STR || op2->gtOper == GT_CNS_STR)
13505 i1 = op1->gtIntConCommon.IconValue();
13506 i2 = op2->gtIntConCommon.IconValue();
13508 switch (tree->gtOper)
13519 noway_assert(tree->gtType != TYP_REF);
13520 // We only fold a GT_ADD that involves a null reference.
13521 if (((op1->TypeGet() == TYP_REF) && (i1 == 0)) || ((op2->TypeGet() == TYP_REF) && (i2 == 0)))
13526 printf("\nFolding operator with constant nodes into a constant:\n");
13530 // Fold into GT_IND of null byref
13531 tree->ChangeOperConst(GT_CNS_INT);
13532 tree->gtType = TYP_BYREF;
13533 tree->gtIntCon.gtIconVal = 0;
13534 tree->gtIntCon.gtFieldSeq = FieldSeqStore::NotAField();
13535 if (vnStore != nullptr)
13537 fgValueNumberTreeConst(tree);
13542 printf("\nFolded to null byref:\n");
13555 /*-------------------------------------------------------------------------
13556 * Fold constant INT binary operator
13561 if (tree->OperIsCompare() && (tree->gtType == TYP_BYTE))
13563 tree->gtType = TYP_INT;
13566 assert(tree->gtType == TYP_INT || varTypeIsGC(tree->TypeGet()) || tree->gtOper == GT_MKREFANY);
13568 // No GC pointer types should be folded here...
13570 assert(!varTypeIsGC(op1->gtType) && !varTypeIsGC(op2->gtType));
13572 if (!op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13577 if (!op2->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13582 i1 = op1->gtIntConCommon.IconValue();
13583 i2 = op2->gtIntConCommon.IconValue();
13585 switch (tree->gtOper)
13588 i1 = (INT32(i1) == INT32(i2));
13591 i1 = (INT32(i1) != INT32(i2));
13595 if (tree->gtFlags & GTF_UNSIGNED)
13597 i1 = (UINT32(i1) < UINT32(i2));
13601 i1 = (INT32(i1) < INT32(i2));
13606 if (tree->gtFlags & GTF_UNSIGNED)
13608 i1 = (UINT32(i1) <= UINT32(i2));
13612 i1 = (INT32(i1) <= INT32(i2));
13617 if (tree->gtFlags & GTF_UNSIGNED)
13619 i1 = (UINT32(i1) >= UINT32(i2));
13623 i1 = (INT32(i1) >= INT32(i2));
13628 if (tree->gtFlags & GTF_UNSIGNED)
13630 i1 = (UINT32(i1) > UINT32(i2));
13634 i1 = (INT32(i1) > INT32(i2));
13640 if (tree->gtOverflow())
13642 if (tree->gtFlags & GTF_UNSIGNED)
13644 if (INT64(UINT32(itemp)) != INT64(UINT32(i1)) + INT64(UINT32(i2)))
13651 if (INT64(INT32(itemp)) != INT64(INT32(i1)) + INT64(INT32(i2)))
13658 fieldSeq = GetFieldSeqStore()->Append(op1->gtIntCon.gtFieldSeq, op2->gtIntCon.gtFieldSeq);
13662 if (tree->gtOverflow())
13664 if (tree->gtFlags & GTF_UNSIGNED)
13666 if (INT64(UINT32(itemp)) != ((INT64)((UINT32)i1) - (INT64)((UINT32)i2)))
13673 if (INT64(INT32(itemp)) != INT64(INT32(i1)) - INT64(INT32(i2)))
13683 if (tree->gtOverflow())
13685 if (tree->gtFlags & GTF_UNSIGNED)
13687 if (INT64(UINT32(itemp)) != ((INT64)((UINT32)i1) * (INT64)((UINT32)i2)))
13694 if (INT64(INT32(itemp)) != INT64(INT32(i1)) * INT64(INT32(i2)))
13700 // For the very particular case of the "constant array index" pseudo-field, we
13701 // assume that multiplication is by the field width, and preserves that field.
13702 // This could obviously be made more robust by a more complicated set of annotations...
13703 if ((op1->gtIntCon.gtFieldSeq != nullptr) && op1->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
13705 assert(op2->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField());
13706 fieldSeq = op1->gtIntCon.gtFieldSeq;
13708 else if ((op2->gtIntCon.gtFieldSeq != nullptr) &&
13709 op2->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
13711 assert(op1->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField());
13712 fieldSeq = op2->gtIntCon.gtFieldSeq;
13728 i1 <<= (i2 & 0x1f);
13731 i1 >>= (i2 & 0x1f);
13734 /* logical shift -> make it unsigned to not propagate the sign bit */
13735 i1 = UINT32(i1) >> (i2 & 0x1f);
13738 i1 = (i1 << (i2 & 0x1f)) | (UINT32(i1) >> ((32 - i2) & 0x1f));
13741 i1 = (i1 << ((32 - i2) & 0x1f)) | (UINT32(i1) >> (i2 & 0x1f));
13744 /* DIV and MOD can generate an INT 0 - if division by 0
13745 * or overflow - when dividing MIN by -1 */
13751 if (INT32(i2) == 0)
13753 // Division by zero:
13754 // We have to evaluate this expression and throw an exception
13757 else if ((INT32(i2) == -1) && (UINT32(i1) == 0x80000000))
13759 // Overflow Division:
13760 // We have to evaluate this expression and throw an exception
13764 if (tree->gtOper == GT_DIV)
13766 i1 = INT32(i1) / INT32(i2);
13768 else if (tree->gtOper == GT_MOD)
13770 i1 = INT32(i1) % INT32(i2);
13772 else if (tree->gtOper == GT_UDIV)
13774 i1 = UINT32(i1) / UINT32(i2);
13778 assert(tree->gtOper == GT_UMOD);
13779 i1 = UINT32(i1) % UINT32(i2);
13787 /* We get here after folding to a GT_CNS_INT type
13788 * change the node to the new type / value and make sure the node sizes are OK */
13795 printf("\nFolding operator with constant nodes into a constant:\n");
13800 #ifdef _TARGET_64BIT_
13801 // Some operations are performed as 64 bit instead of 32 bit so the upper 32 bits
13802 // need to be discarded. Since constant values are stored as ssize_t and the node
13803 // has TYP_INT the result needs to be sign extended rather than zero extended.
13805 #endif // _TARGET_64BIT_
13807 /* Also all conditional folding jumps here since the node hanging from
13808 * GT_JTRUE has to be a GT_CNS_INT - value 0 or 1 */
13810 tree->ChangeOperConst(GT_CNS_INT);
13811 tree->gtType = TYP_INT;
13812 tree->gtIntCon.gtIconVal = i1;
13813 tree->gtIntCon.gtFieldSeq = fieldSeq;
13814 if (vnStore != nullptr)
13816 fgValueNumberTreeConst(tree);
13821 printf("Bashed to int constant:\n");
13827 /* This operation is going to cause an overflow exception. Morph into
13828 an overflow helper. Put a dummy constant value for code generation.
13830 We could remove all subsequent trees in the current basic block,
13831 unless this node is a child of GT_COLON
13833 NOTE: Since the folded value is not constant we should not change the
13834 "tree" node - otherwise we confuse the logic that checks if the folding
13835 was successful - instead use one of the operands, e.g. op1
13839 // Don't fold overflow operations if not global morph phase.
13840 // The reason for this is that this optimization is replacing a gentree node
13841 // with another new gentree node. Say a GT_CALL(arglist) has one 'arg'
13842 // involving overflow arithmetic. During assertion prop, it is possible
13843 // that the 'arg' could be constant folded and the result could lead to an
13844 // overflow. In such a case 'arg' will get replaced with GT_COMMA node
13845 // but fgMorphArgs() - see the logic around "if(lateArgsComputed)" - doesn't
13846 // update args table. For this reason this optimization is enabled only
13847 // for global morphing phase.
13849 // TODO-CQ: Once fgMorphArgs() is fixed this restriction could be removed.
13850 CLANG_FORMAT_COMMENT_ANCHOR;
13852 if (!fgGlobalMorph)
13854 assert(tree->gtOverflow());
13858 op1 = gtNewLconNode(0);
13859 if (vnStore != nullptr)
13861 op1->gtVNPair.SetBoth(vnStore->VNZeroForType(TYP_LONG));
13866 // Don't fold overflow operations if not global morph phase.
13867 // The reason for this is that this optimization is replacing a gentree node
13868 // with another new gentree node. Say a GT_CALL(arglist) has one 'arg'
13869 // involving overflow arithmetic. During assertion prop, it is possible
13870 // that the 'arg' could be constant folded and the result could lead to an
13871 // overflow. In such a case 'arg' will get replaced with GT_COMMA node
13872 // but fgMorphArgs() - see the logic around "if(lateArgsComputed)" - doesn't
13873 // update args table. For this reason this optimization is enabled only
13874 // for global morphing phase.
13876 // TODO-CQ: Once fgMorphArgs() is fixed this restriction could be removed.
13878 if (!fgGlobalMorph)
13880 assert(tree->gtOverflow());
13884 op1 = gtNewIconNode(0);
13885 if (vnStore != nullptr)
13887 op1->gtVNPair.SetBoth(vnStore->VNZeroForType(TYP_INT));
13895 printf("\nFolding binary operator with constant nodes into a comma throw:\n");
13899 /* We will change the cast to a GT_COMMA and attach the exception helper as gtOp.gtOp1.
13900 * The constant expression zero becomes op2. */
13902 assert(tree->gtOverflow());
13903 assert(tree->gtOper == GT_ADD || tree->gtOper == GT_SUB || tree->gtOper == GT_CAST ||
13904 tree->gtOper == GT_MUL);
13908 op1 = gtNewHelperCallNode(CORINFO_HELP_OVERFLOW, TYP_VOID,
13909 gtNewArgList(gtNewIconNode(compCurBB->bbTryIndex)));
13911 // op1 is a call to the JIT helper that throws an Overflow exception
13912 // attach the ExcSet for VNF_OverflowExc(Void) to this call
13914 if (vnStore != nullptr)
13917 vnStore->VNPWithExc(ValueNumPair(ValueNumStore::VNForVoid(), ValueNumStore::VNForVoid()),
13918 vnStore->VNPExcSetSingleton(
13919 vnStore->VNPairForFunc(TYP_REF, VNF_OverflowExc, vnStore->VNPForVoid())));
13922 tree = gtNewOperNode(GT_COMMA, tree->gtType, op1, op2);
13926 /*-------------------------------------------------------------------------
13927 * Fold constant LONG binary operator
13932 // No GC pointer types should be folded here...
13934 assert(!varTypeIsGC(op1->gtType) && !varTypeIsGC(op2->gtType));
13936 // op1 is known to be a TYP_LONG, op2 is normally a TYP_LONG, unless we have a shift operator in which case
13939 assert((op2->gtType == TYP_LONG) || (op2->gtType == TYP_INT));
13941 if (!op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13946 if (!op2->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13951 lval1 = op1->gtIntConCommon.LngValue();
13953 // For the shift operators we can have a op2 that is a TYP_INT and thus will be GT_CNS_INT
13954 if (op2->OperGet() == GT_CNS_INT)
13956 lval2 = op2->gtIntConCommon.IconValue();
13960 lval2 = op2->gtIntConCommon.LngValue();
13963 switch (tree->gtOper)
13966 i1 = (lval1 == lval2);
13969 i1 = (lval1 != lval2);
13973 if (tree->gtFlags & GTF_UNSIGNED)
13975 i1 = (UINT64(lval1) < UINT64(lval2));
13979 i1 = (lval1 < lval2);
13984 if (tree->gtFlags & GTF_UNSIGNED)
13986 i1 = (UINT64(lval1) <= UINT64(lval2));
13990 i1 = (lval1 <= lval2);
13995 if (tree->gtFlags & GTF_UNSIGNED)
13997 i1 = (UINT64(lval1) >= UINT64(lval2));
14001 i1 = (lval1 >= lval2);
14006 if (tree->gtFlags & GTF_UNSIGNED)
14008 i1 = (UINT64(lval1) > UINT64(lval2));
14012 i1 = (lval1 > lval2);
14017 ltemp = lval1 + lval2;
14020 /* For the SIGNED case - If there is one positive and one negative operand, there can be no overflow
14021 * If both are positive, the result has to be positive, and similary for negatives.
14023 * For the UNSIGNED case - If a UINT32 operand is bigger than the result then OVF */
14025 if (tree->gtOverflow())
14027 if (tree->gtFlags & GTF_UNSIGNED)
14029 if ((UINT64(lval1) > UINT64(ltemp)) || (UINT64(lval2) > UINT64(ltemp)))
14034 else if (((lval1 < 0) == (lval2 < 0)) && ((lval1 < 0) != (ltemp < 0)))
14043 ltemp = lval1 - lval2;
14044 if (tree->gtOverflow())
14046 if (tree->gtFlags & GTF_UNSIGNED)
14048 if (UINT64(lval2) > UINT64(lval1))
14055 /* If both operands are +ve or both are -ve, there can be no
14056 overflow. Else use the logic for : lval1 + (-lval2) */
14058 if ((lval1 < 0) != (lval2 < 0))
14060 if (lval2 == INT64_MIN)
14065 goto LNG_ADD_CHKOVF;
14073 ltemp = lval1 * lval2;
14075 if (tree->gtOverflow() && lval2 != 0)
14078 if (tree->gtFlags & GTF_UNSIGNED)
14080 UINT64 ultemp = ltemp;
14081 UINT64 ulval1 = lval1;
14082 UINT64 ulval2 = lval2;
14083 if ((ultemp / ulval2) != ulval1)
14090 // This does a multiply and then reverses it. This test works great except for MIN_INT *
14091 //-1. In that case we mess up the sign on ltmp. Make sure to double check the sign.
14092 // if either is 0, then no overflow
14093 if (lval1 != 0) // lval2 checked above.
14095 if (((lval1 < 0) == (lval2 < 0)) && (ltemp < 0))
14099 if (((lval1 < 0) != (lval2 < 0)) && (ltemp > 0))
14104 // TODO-Amd64-Unix: Remove the code that disables optimizations for this method when the
14106 // optimizer is fixed and/or the method implementation is refactored in a simpler code.
14107 // There is a bug in the clang-3.5 optimizer. The issue is that in release build the
14108 // optimizer is mistyping (or just wrongly decides to use 32 bit operation for a corner
14109 // case of MIN_LONG) the args of the (ltemp / lval2) to int (it does a 32 bit div
14110 // operation instead of 64 bit.). For the case of lval1 and lval2 equal to MIN_LONG
14111 // (0x8000000000000000) this results in raising a SIGFPE.
14112 // Optimizations disabled for now. See compiler.h.
14113 if ((ltemp / lval2) != lval1)
14135 lval1 <<= (lval2 & 0x3f);
14138 lval1 >>= (lval2 & 0x3f);
14141 /* logical shift -> make it unsigned to not propagate the sign bit */
14142 lval1 = UINT64(lval1) >> (lval2 & 0x3f);
14145 lval1 = (lval1 << (lval2 & 0x3f)) | (UINT64(lval1) >> ((64 - lval2) & 0x3f));
14148 lval1 = (lval1 << ((64 - lval2) & 0x3f)) | (UINT64(lval1) >> (lval2 & 0x3f));
14151 // Both DIV and IDIV on x86 raise an exception for min_int (and min_long) / -1. So we preserve
14152 // that behavior here.
14159 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
14171 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
14183 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
14187 lval1 = UINT64(lval1) / UINT64(lval2);
14195 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
14199 lval1 = UINT64(lval1) % UINT64(lval2);
14207 if (fieldSeq != FieldSeqStore::NotAField())
14215 printf("\nFolding long operator with constant nodes into a constant:\n");
14219 assert((GenTree::s_gtNodeSizes[GT_CNS_NATIVELONG] == TREE_NODE_SZ_SMALL) ||
14220 (tree->gtDebugFlags & GTF_DEBUG_NODE_LARGE));
14222 tree->ChangeOperConst(GT_CNS_NATIVELONG);
14223 tree->gtIntConCommon.SetLngValue(lval1);
14224 if (vnStore != nullptr)
14226 fgValueNumberTreeConst(tree);
14232 printf("Bashed to long constant:\n");
14238 /*-------------------------------------------------------------------------
14239 * Fold constant FLOAT or DOUBLE binary operator
14245 if (tree->gtOverflowEx())
14250 assert(op1->gtOper == GT_CNS_DBL);
14251 d1 = op1->gtDblCon.gtDconVal;
14253 assert(varTypeIsFloating(op2->gtType));
14254 assert(op2->gtOper == GT_CNS_DBL);
14255 d2 = op2->gtDblCon.gtDconVal;
14257 /* Special case - check if we have NaN operands.
14258 * For comparisons if not an unordered operation always return 0.
14259 * For unordered operations (i.e. the GTF_RELOP_NAN_UN flag is set)
14260 * the result is always true - return 1. */
14262 if (_isnan(d1) || _isnan(d2))
14267 printf("Double operator(s) is NaN\n");
14270 if (tree->OperKind() & GTK_RELOP)
14272 if (tree->gtFlags & GTF_RELOP_NAN_UN)
14274 /* Unordered comparison with NaN always succeeds */
14280 /* Normal comparison with NaN always fails */
14287 switch (tree->gtOper)
14309 // Floating point arithmetic should be done in declared
14310 // precision while doing constant folding. For this reason though TYP_FLOAT
14311 // constants are stored as double constants, while performing float arithmetic,
14312 // double constants should be converted to float. Here is an example case
14313 // where performing arithmetic in double precision would lead to incorrect
14317 // float a = float.MaxValue;
14318 // float b = a*a; This will produce +inf in single precision and 1.1579207543382391e+077 in double
14320 // flaot c = b/b; This will produce NaN in single precision and 1 in double precision.
14322 if (op1->TypeGet() == TYP_FLOAT)
14324 f1 = forceCastToFloat(d1);
14325 f2 = forceCastToFloat(d2);
14326 d1 = forceCastToFloat(f1 + f2);
14335 if (op1->TypeGet() == TYP_FLOAT)
14337 f1 = forceCastToFloat(d1);
14338 f2 = forceCastToFloat(d2);
14339 d1 = forceCastToFloat(f1 - f2);
14348 if (op1->TypeGet() == TYP_FLOAT)
14350 f1 = forceCastToFloat(d1);
14351 f2 = forceCastToFloat(d2);
14352 d1 = forceCastToFloat(f1 * f2);
14365 if (op1->TypeGet() == TYP_FLOAT)
14367 f1 = forceCastToFloat(d1);
14368 f2 = forceCastToFloat(d2);
14369 d1 = forceCastToFloat(f1 / f2);
14386 printf("\nFolding fp operator with constant nodes into a fp constant:\n");
14391 assert((GenTree::s_gtNodeSizes[GT_CNS_DBL] == TREE_NODE_SZ_SMALL) ||
14392 (tree->gtDebugFlags & GTF_DEBUG_NODE_LARGE));
14394 tree->ChangeOperConst(GT_CNS_DBL);
14395 tree->gtDblCon.gtDconVal = d1;
14396 if (vnStore != nullptr)
14398 fgValueNumberTreeConst(tree);
14403 printf("Bashed to fp constant:\n");
14410 /* not a foldable typ */
14414 //-------------------------------------------------------------------------
14418 /* Make sure no side effect flags are set on this constant node */
14420 tree->gtFlags &= ~GTF_ALL_EFFECT;
14425 #pragma warning(pop)
14428 //------------------------------------------------------------------------
14429 // gtNewTempAssign: Create an assignment of the given value to a temp.
14432 // tmp - local number for a compiler temp
14433 // val - value to assign to the temp
14434 // pAfterStmt - statement to insert any additional statements after
14435 // ilOffset - il offset for new statements
14436 // block - block to insert any additional statements in
14439 // Normally a new assignment node.
14440 // However may return a nop node if val is simply a reference to the temp.
14443 // Self-assignments may be represented via NOPs.
14445 // May update the type of the temp, if it was previously unknown.
14447 // May set compFloatingPointUsed.
14449 GenTree* Compiler::gtNewTempAssign(
14450 unsigned tmp, GenTree* val, GenTree** pAfterStmt, IL_OFFSETX ilOffset, BasicBlock* block)
14452 // Self-assignment is a nop.
14453 if (val->OperGet() == GT_LCL_VAR && val->gtLclVarCommon.gtLclNum == tmp)
14455 return gtNewNothingNode();
14458 LclVarDsc* varDsc = lvaTable + tmp;
14460 if (varDsc->TypeGet() == TYP_I_IMPL && val->TypeGet() == TYP_BYREF)
14462 impBashVarAddrsToI(val);
14465 var_types valTyp = val->TypeGet();
14466 if (val->OperGet() == GT_LCL_VAR && lvaTable[val->gtLclVar.gtLclNum].lvNormalizeOnLoad())
14468 valTyp = lvaGetRealType(val->gtLclVar.gtLclNum);
14469 val->gtType = valTyp;
14471 var_types dstTyp = varDsc->TypeGet();
14473 /* If the variable's lvType is not yet set then set it here */
14474 if (dstTyp == TYP_UNDEF)
14476 varDsc->lvType = dstTyp = genActualType(valTyp);
14477 if (varTypeIsGC(dstTyp))
14479 varDsc->lvStructGcCount = 1;
14482 else if (varTypeIsSIMD(dstTyp))
14484 varDsc->lvSIMDType = 1;
14490 /* Make sure the actual types match */
14491 if (genActualType(valTyp) != genActualType(dstTyp))
14493 // Plus some other exceptions that are apparently legal:
14494 // 1) TYP_REF or BYREF = TYP_I_IMPL
14496 if (varTypeIsGC(dstTyp) && (valTyp == TYP_I_IMPL))
14500 // 2) TYP_DOUBLE = TYP_FLOAT or TYP_FLOAT = TYP_DOUBLE
14501 else if (varTypeIsFloating(dstTyp) && varTypeIsFloating(valTyp))
14509 assert(!"Incompatible types for gtNewTempAssign");
14514 // Floating Point assignments can be created during inlining
14515 // see "Zero init inlinee locals:" in fgInlinePrependStatements
14516 // thus we may need to set compFloatingPointUsed to true here.
14518 if (varTypeIsFloating(dstTyp) && (compFloatingPointUsed == false))
14520 compFloatingPointUsed = true;
14523 /* Create the assignment node */
14526 GenTree* dest = gtNewLclvNode(tmp, dstTyp);
14527 dest->gtFlags |= GTF_VAR_DEF;
14529 // With first-class structs, we should be propagating the class handle on all non-primitive
14530 // struct types. We don't have a convenient way to do that for all SIMD temps, since some
14531 // internal trees use SIMD types that are not used by the input IL. In this case, we allow
14532 // a null type handle and derive the necessary information about the type from its varType.
14533 CORINFO_CLASS_HANDLE structHnd = gtGetStructHandleIfPresent(val);
14534 if (varTypeIsStruct(valTyp) && ((structHnd != NO_CLASS_HANDLE) || (varTypeIsSIMD(valTyp))))
14536 // The struct value may be be a child of a GT_COMMA.
14537 GenTree* valx = val->gtEffectiveVal(/*commaOnly*/ true);
14539 if (structHnd != NO_CLASS_HANDLE)
14541 lvaSetStruct(tmp, structHnd, false);
14545 assert(valx->gtOper != GT_OBJ);
14547 dest->gtFlags |= GTF_DONT_CSE;
14548 valx->gtFlags |= GTF_DONT_CSE;
14549 asg = impAssignStruct(dest, val, structHnd, (unsigned)CHECK_SPILL_NONE, pAfterStmt, ilOffset, block);
14553 asg = gtNewAssignNode(dest, val);
14556 if (compRationalIRForm)
14558 Rationalizer::RewriteAssignmentIntoStoreLcl(asg->AsOp());
14564 /*****************************************************************************
14566 * Create a helper call to access a COM field (iff 'assg' is non-zero this is
14567 * an assignment and 'assg' is the new value).
14570 GenTree* Compiler::gtNewRefCOMfield(GenTree* objPtr,
14571 CORINFO_RESOLVED_TOKEN* pResolvedToken,
14572 CORINFO_ACCESS_FLAGS access,
14573 CORINFO_FIELD_INFO* pFieldInfo,
14575 CORINFO_CLASS_HANDLE structType,
14578 assert(pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER ||
14579 pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_ADDR_HELPER ||
14580 pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_ADDR_HELPER);
14582 /* If we can't access it directly, we need to call a helper function */
14583 GenTreeArgList* args = nullptr;
14584 var_types helperType = TYP_BYREF;
14586 if (pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER)
14588 if (access & CORINFO_ACCESS_SET)
14590 assert(assg != nullptr);
14591 // helper needs pointer to struct, not struct itself
14592 if (pFieldInfo->helper == CORINFO_HELP_SETFIELDSTRUCT)
14594 assert(structType != nullptr);
14595 assg = impGetStructAddr(assg, structType, (unsigned)CHECK_SPILL_ALL, true);
14597 else if (lclTyp == TYP_DOUBLE && assg->TypeGet() == TYP_FLOAT)
14599 assg = gtNewCastNode(TYP_DOUBLE, assg, false, TYP_DOUBLE);
14601 else if (lclTyp == TYP_FLOAT && assg->TypeGet() == TYP_DOUBLE)
14603 assg = gtNewCastNode(TYP_FLOAT, assg, false, TYP_FLOAT);
14606 args = gtNewArgList(assg);
14607 helperType = TYP_VOID;
14609 else if (access & CORINFO_ACCESS_GET)
14611 helperType = lclTyp;
14613 // The calling convention for the helper does not take into
14614 // account optimization of primitive structs.
14615 if ((pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT) && !varTypeIsStruct(lclTyp))
14617 helperType = TYP_STRUCT;
14622 if (pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT || pFieldInfo->helper == CORINFO_HELP_SETFIELDSTRUCT)
14624 assert(pFieldInfo->structType != nullptr);
14625 args = gtNewListNode(gtNewIconEmbClsHndNode(pFieldInfo->structType), args);
14628 GenTree* fieldHnd = impTokenToHandle(pResolvedToken);
14629 if (fieldHnd == nullptr)
14630 { // compDonotInline()
14634 args = gtNewListNode(fieldHnd, args);
14636 // If it's a static field, we shouldn't have an object node
14637 // If it's an instance field, we have an object node
14638 assert((pFieldInfo->fieldAccessor != CORINFO_FIELD_STATIC_ADDR_HELPER) ^ (objPtr == nullptr));
14640 if (objPtr != nullptr)
14642 args = gtNewListNode(objPtr, args);
14645 GenTreeCall* call = gtNewHelperCallNode(pFieldInfo->helper, genActualType(helperType), args);
14647 #if FEATURE_MULTIREG_RET
14648 if (varTypeIsStruct(call))
14650 // Initialize Return type descriptor of call node.
14651 ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc();
14652 retTypeDesc->InitializeStructReturnType(this, structType);
14654 #endif // FEATURE_MULTIREG_RET
14656 GenTree* result = call;
14658 if (pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER)
14660 if (access & CORINFO_ACCESS_GET)
14662 if (pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT)
14664 if (!varTypeIsStruct(lclTyp))
14666 // get the result as primitive type
14667 result = impGetStructAddr(result, structType, (unsigned)CHECK_SPILL_ALL, true);
14668 result = gtNewOperNode(GT_IND, lclTyp, result);
14671 else if (varTypeIsIntegral(lclTyp) && genTypeSize(lclTyp) < genTypeSize(TYP_INT))
14673 // The helper does not extend the small return types.
14674 result = gtNewCastNode(genActualType(lclTyp), result, false, lclTyp);
14680 // OK, now do the indirection
14681 if (access & CORINFO_ACCESS_GET)
14683 if (varTypeIsStruct(lclTyp))
14685 result = gtNewObjNode(structType, result);
14689 result = gtNewOperNode(GT_IND, lclTyp, result);
14691 result->gtFlags |= (GTF_EXCEPT | GTF_GLOB_REF);
14693 else if (access & CORINFO_ACCESS_SET)
14695 if (varTypeIsStruct(lclTyp))
14697 result = impAssignStructPtr(result, assg, structType, (unsigned)CHECK_SPILL_ALL);
14701 result = gtNewOperNode(GT_IND, lclTyp, result);
14702 result->gtFlags |= (GTF_EXCEPT | GTF_GLOB_REF | GTF_IND_TGTANYWHERE);
14703 result = gtNewAssignNode(result, assg);
14711 /*****************************************************************************
14713 * Return true if the given node (excluding children trees) contains side effects.
14714 * Note that it does not recurse, and children need to be handled separately.
14715 * It may return false even if the node has GTF_SIDE_EFFECT (because of its children).
14717 * Similar to OperMayThrow() (but handles GT_CALLs specially), but considers
14721 bool Compiler::gtNodeHasSideEffects(GenTree* tree, unsigned flags)
14723 if (flags & GTF_ASG)
14725 // TODO-Cleanup: This only checks for GT_ASG but according to OperRequiresAsgFlag there
14726 // are many more opers that are considered to have an assignment side effect: atomic ops
14727 // (GT_CMPXCHG & co.), GT_MEMORYBARRIER (not classified as an atomic op) and HW intrinsic
14728 // memory stores. Atomic ops have special handling in gtExtractSideEffList but the others
14729 // will simply be dropped is they are ever subject to an "extract side effects" operation.
14730 // It is possible that the reason no bugs have yet been observed in this area is that the
14731 // other nodes are likely to always be tree roots.
14732 if (tree->OperIs(GT_ASG))
14738 // Are there only GTF_CALL side effects remaining? (and no other side effect kinds)
14739 if (flags & GTF_CALL)
14741 if (tree->OperGet() == GT_CALL)
14743 GenTreeCall* const call = tree->AsCall();
14744 const bool ignoreExceptions = (flags & GTF_EXCEPT) == 0;
14745 const bool ignoreCctors = (flags & GTF_IS_IN_CSE) != 0; // We can CSE helpers that run cctors.
14746 if (!call->HasSideEffects(this, ignoreExceptions, ignoreCctors))
14748 // If this call is otherwise side effect free, check its arguments.
14749 for (GenTreeArgList* args = call->gtCallArgs; args != nullptr; args = args->Rest())
14751 if (gtTreeHasSideEffects(args->Current(), flags))
14756 // I'm a little worried that args that assign to temps that are late args will look like
14757 // side effects...but better to be conservative for now.
14758 for (GenTreeArgList* args = call->gtCallLateArgs; args != nullptr; args = args->Rest())
14760 if (gtTreeHasSideEffects(args->Current(), flags))
14770 // Otherwise the GT_CALL is considered to have side-effects.
14775 if (flags & GTF_EXCEPT)
14777 if (tree->OperMayThrow(this))
14783 // Expressions declared as CSE by (e.g.) hoisting code are considered to have relevant side
14784 // effects (if we care about GTF_MAKE_CSE).
14785 if ((flags & GTF_MAKE_CSE) && (tree->gtFlags & GTF_MAKE_CSE))
14793 /*****************************************************************************
14794 * Returns true if the expr tree has any side effects.
14797 bool Compiler::gtTreeHasSideEffects(GenTree* tree, unsigned flags /* = GTF_SIDE_EFFECT*/)
14799 // These are the side effect flags that we care about for this tree
14800 unsigned sideEffectFlags = tree->gtFlags & flags;
14802 // Does this tree have any Side-effect flags set that we care about?
14803 if (sideEffectFlags == 0)
14809 if (sideEffectFlags == GTF_CALL)
14811 if (tree->OperGet() == GT_CALL)
14813 // Generally all trees that contain GT_CALL nodes are considered to have side-effects.
14815 if (tree->gtCall.gtCallType == CT_HELPER)
14817 // If this node is a helper call we may not care about the side-effects.
14818 // Note that gtNodeHasSideEffects checks the side effects of the helper itself
14819 // as well as the side effects of its arguments.
14820 return gtNodeHasSideEffects(tree, flags);
14823 else if (tree->OperGet() == GT_INTRINSIC)
14825 if (gtNodeHasSideEffects(tree, flags))
14830 if (gtNodeHasSideEffects(tree->gtOp.gtOp1, flags))
14835 if ((tree->gtOp.gtOp2 != nullptr) && gtNodeHasSideEffects(tree->gtOp.gtOp2, flags))
14847 GenTree* Compiler::gtBuildCommaList(GenTree* list, GenTree* expr)
14849 // 'list' starts off as null,
14850 // and when it is null we haven't started the list yet.
14852 if (list != nullptr)
14854 // Create a GT_COMMA that appends 'expr' in front of the remaining set of expressions in (*list)
14855 GenTree* result = gtNewOperNode(GT_COMMA, TYP_VOID, expr, list);
14857 // Set the flags in the comma node
14858 result->gtFlags |= (list->gtFlags & GTF_ALL_EFFECT);
14859 result->gtFlags |= (expr->gtFlags & GTF_ALL_EFFECT);
14861 // 'list' and 'expr' should have valuenumbers defined for both or for neither one (unless we are remorphing,
14862 // in which case a prior transform involving either node may have discarded or otherwise invalidated the value
14864 assert((list->gtVNPair.BothDefined() == expr->gtVNPair.BothDefined()) || !fgGlobalMorph);
14866 // Set the ValueNumber 'gtVNPair' for the new GT_COMMA node
14868 if (list->gtVNPair.BothDefined() && expr->gtVNPair.BothDefined())
14870 // The result of a GT_COMMA node is op2, the normal value number is op2vnp
14871 // But we also need to include the union of side effects from op1 and op2.
14872 // we compute this value into exceptions_vnp.
14873 ValueNumPair op1vnp;
14874 ValueNumPair op1Xvnp = ValueNumStore::VNPForEmptyExcSet();
14875 ValueNumPair op2vnp;
14876 ValueNumPair op2Xvnp = ValueNumStore::VNPForEmptyExcSet();
14878 vnStore->VNPUnpackExc(expr->gtVNPair, &op1vnp, &op1Xvnp);
14879 vnStore->VNPUnpackExc(list->gtVNPair, &op2vnp, &op2Xvnp);
14881 ValueNumPair exceptions_vnp = ValueNumStore::VNPForEmptyExcSet();
14883 exceptions_vnp = vnStore->VNPExcSetUnion(exceptions_vnp, op1Xvnp);
14884 exceptions_vnp = vnStore->VNPExcSetUnion(exceptions_vnp, op2Xvnp);
14886 result->gtVNPair = vnStore->VNPWithExc(op2vnp, exceptions_vnp);
14893 // The 'expr' will start the list of expressions
14898 //------------------------------------------------------------------------
14899 // gtExtractSideEffList: Extracts side effects from the given expression.
14902 // expr - the expression tree to extract side effects from
14903 // pList - pointer to a (possibly null) GT_COMMA list that
14904 // will contain the extracted side effects
14905 // flags - side effect flags to be considered
14906 // ignoreRoot - ignore side effects on the expression root node
14909 // Side effects are prepended to the GT_COMMA list such that op1 of
14910 // each comma node holds the side effect tree and op2 points to the
14911 // next comma node. The original side effect execution order is preserved.
14913 void Compiler::gtExtractSideEffList(GenTree* expr,
14915 unsigned flags /* = GTF_SIDE_EFFECT*/,
14916 bool ignoreRoot /* = false */)
14918 class SideEffectExtractor final : public GenTreeVisitor<SideEffectExtractor>
14921 const unsigned m_flags;
14922 ArrayStack<GenTree*> m_sideEffects;
14927 UseExecutionOrder = true
14930 SideEffectExtractor(Compiler* compiler, unsigned flags)
14931 : GenTreeVisitor(compiler), m_flags(flags), m_sideEffects(compiler->getAllocator(CMK_SideEffects))
14935 fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
14937 GenTree* node = *use;
14939 bool treeHasSideEffects = m_compiler->gtTreeHasSideEffects(node, m_flags);
14941 if (treeHasSideEffects)
14943 if (m_compiler->gtNodeHasSideEffects(node, m_flags))
14945 m_sideEffects.Push(node);
14946 return Compiler::WALK_SKIP_SUBTREES;
14949 // TODO-Cleanup: These have GTF_ASG set but for some reason gtNodeHasSideEffects ignores
14950 // them. See the related gtNodeHasSideEffects comment as well.
14951 // Also, these nodes must always be preserved, no matter what side effect flags are passed
14952 // in. But then it should never be the case that gtExtractSideEffList gets called without
14953 // specifying GTF_ASG so there doesn't seem to be any reason to be inconsistent with
14954 // gtNodeHasSideEffects and make this check unconditionally.
14955 if (node->OperIsAtomicOp())
14957 m_sideEffects.Push(node);
14958 return Compiler::WALK_SKIP_SUBTREES;
14961 if ((m_flags & GTF_EXCEPT) != 0)
14963 // Special case - GT_ADDR of GT_IND nodes of TYP_STRUCT have to be kept together.
14964 if (node->OperIs(GT_ADDR) && node->gtGetOp1()->OperIsIndir() &&
14965 (node->gtGetOp1()->TypeGet() == TYP_STRUCT))
14968 if (m_compiler->verbose)
14970 printf("Keep the GT_ADDR and GT_IND together:\n");
14973 m_sideEffects.Push(node);
14974 return Compiler::WALK_SKIP_SUBTREES;
14978 // Generally all GT_CALL nodes are considered to have side-effects.
14979 // So if we get here it must be a helper call that we decided it does
14980 // not have side effects that we needed to keep.
14981 assert(!node->OperIs(GT_CALL) || (node->AsCall()->gtCallType == CT_HELPER));
14984 if ((m_flags & GTF_IS_IN_CSE) != 0)
14986 // If we're doing CSE then we also need to unmark CSE nodes. This will fail for CSE defs,
14987 // those need to be extracted as if they're side effects.
14988 if (!UnmarkCSE(node))
14990 m_sideEffects.Push(node);
14991 return Compiler::WALK_SKIP_SUBTREES;
14994 // The existence of CSE defs and uses is not propagated up the tree like side
14995 // effects are. We need to continue visiting the tree as if it has side effects.
14996 treeHasSideEffects = true;
14999 return treeHasSideEffects ? Compiler::WALK_CONTINUE : Compiler::WALK_SKIP_SUBTREES;
15003 bool UnmarkCSE(GenTree* node)
15005 assert(m_compiler->optValnumCSE_phase);
15007 if (m_compiler->optUnmarkCSE(node))
15009 // The call to optUnmarkCSE(node) should have cleared any CSE info.
15010 assert(!IS_CSE_INDEX(node->gtCSEnum));
15015 assert(IS_CSE_DEF(node->gtCSEnum));
15017 if (m_compiler->verbose)
15019 printf("Preserving the CSE def #%02d at ", GET_CSE_INDEX(node->gtCSEnum));
15020 m_compiler->printTreeID(node);
15028 assert(!expr->OperIs(GT_STMT));
15030 SideEffectExtractor extractor(this, flags);
15034 for (GenTree* op : expr->Operands())
15036 extractor.WalkTree(&op, nullptr);
15041 extractor.WalkTree(&expr, nullptr);
15044 GenTree* list = *pList;
15046 // The extractor returns side effects in execution order but gtBuildCommaList prepends
15047 // to the comma-based side effect list so we have to build the list in reverse order.
15048 // This is also why the list cannot be built while traversing the tree.
15049 // The number of side effects is usually small (<= 4), less than the ArrayStack's
15050 // built-in size, so memory allocation is avoided.
15051 while (extractor.m_sideEffects.Height() > 0)
15053 list = gtBuildCommaList(list, extractor.m_sideEffects.Pop());
15059 /*****************************************************************************
15061 * For debugging only - displays a tree node list and makes sure all the
15062 * links are correctly set.
15067 void dispNodeList(GenTree* list, bool verbose)
15069 GenTree* last = nullptr;
15079 next = list->gtNext;
15083 printf("%08X -> %08X -> %08X\n", last, list, next);
15086 assert(!last || last->gtNext == list);
15088 assert(next == nullptr || next->gtPrev == list);
15098 printf(""); // null string means flush
15101 /*****************************************************************************
15102 * Callback to assert that the nodes of a qmark-colon subtree are marked
15106 Compiler::fgWalkResult Compiler::gtAssertColonCond(GenTree** pTree, fgWalkData* data)
15108 assert(data->pCallbackData == nullptr);
15110 assert((*pTree)->gtFlags & GTF_COLON_COND);
15112 return WALK_CONTINUE;
15116 /*****************************************************************************
15117 * Callback to mark the nodes of a qmark-colon subtree that are conditionally
15122 Compiler::fgWalkResult Compiler::gtMarkColonCond(GenTree** pTree, fgWalkData* data)
15124 assert(data->pCallbackData == nullptr);
15126 (*pTree)->gtFlags |= GTF_COLON_COND;
15128 return WALK_CONTINUE;
15131 /*****************************************************************************
15132 * Callback to clear the conditionally executed flags of nodes that no longer
15133 will be conditionally executed. Note that when we find another colon we must
15134 stop, as the nodes below this one WILL be conditionally executed. This callback
15135 is called when folding a qmark condition (ie the condition is constant).
15139 Compiler::fgWalkResult Compiler::gtClearColonCond(GenTree** pTree, fgWalkData* data)
15141 GenTree* tree = *pTree;
15143 assert(data->pCallbackData == nullptr);
15145 if (tree->OperGet() == GT_COLON)
15147 // Nodes below this will be conditionally executed.
15148 return WALK_SKIP_SUBTREES;
15151 tree->gtFlags &= ~GTF_COLON_COND;
15152 return WALK_CONTINUE;
15155 struct FindLinkData
15157 GenTree* nodeToFind;
15161 /*****************************************************************************
15163 * Callback used by the tree walker to implement fgFindLink()
15165 static Compiler::fgWalkResult gtFindLinkCB(GenTree** pTree, Compiler::fgWalkData* cbData)
15167 FindLinkData* data = (FindLinkData*)cbData->pCallbackData;
15168 if (*pTree == data->nodeToFind)
15170 data->result = pTree;
15171 return Compiler::WALK_ABORT;
15174 return Compiler::WALK_CONTINUE;
15177 GenTree** Compiler::gtFindLink(GenTree* stmt, GenTree* node)
15179 assert(stmt->gtOper == GT_STMT);
15181 FindLinkData data = {node, nullptr};
15183 fgWalkResult result = fgWalkTreePre(&stmt->gtStmt.gtStmtExpr, gtFindLinkCB, &data);
15185 if (result == WALK_ABORT)
15187 assert(data.nodeToFind == *data.result);
15188 return data.result;
15196 /*****************************************************************************
15198 * Callback that checks if a tree node has oper type GT_CATCH_ARG
15201 static Compiler::fgWalkResult gtFindCatchArg(GenTree** pTree, Compiler::fgWalkData* /* data */)
15203 return ((*pTree)->OperGet() == GT_CATCH_ARG) ? Compiler::WALK_ABORT : Compiler::WALK_CONTINUE;
15206 /*****************************************************************************/
15207 bool Compiler::gtHasCatchArg(GenTree* tree)
15209 if (((tree->gtFlags & GTF_ORDER_SIDEEFF) != 0) && (fgWalkTreePre(&tree, gtFindCatchArg) == WALK_ABORT))
15216 //------------------------------------------------------------------------
15217 // gtHasCallOnStack:
15220 // parentStack: a context (stack of parent nodes)
15223 // returns true if any of the parent nodes are a GT_CALL
15226 // We have a stack of parent nodes. This generally requires that
15227 // we are performing a recursive tree walk using struct fgWalkData
15229 //------------------------------------------------------------------------
15230 /* static */ bool Compiler::gtHasCallOnStack(GenTreeStack* parentStack)
15232 for (int i = 0; i < parentStack->Height(); i++)
15234 GenTree* node = parentStack->Index(i);
15235 if (node->OperGet() == GT_CALL)
15243 //------------------------------------------------------------------------
15244 // gtGetTypeProducerKind: determine if a tree produces a runtime type, and
15248 // tree - tree to examine
15251 // TypeProducerKind for the tree.
15254 // Checks to see if this tree returns a RuntimeType value, and if so,
15255 // how that value is determined.
15257 // Currently handles these cases
15258 // 1) The result of Object::GetType
15259 // 2) The result of typeof(...)
15260 // 3) A null reference
15261 // 4) Tree is otherwise known to have type RuntimeType
15263 // The null reference case is surprisingly common because operator
15264 // overloading turns the otherwise innocuous
15269 // into a method call.
15271 Compiler::TypeProducerKind Compiler::gtGetTypeProducerKind(GenTree* tree)
15273 if (tree->gtOper == GT_CALL)
15275 if (tree->gtCall.gtCallType == CT_HELPER)
15277 if (gtIsTypeHandleToRuntimeTypeHelper(tree->AsCall()))
15282 else if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC)
15284 if (info.compCompHnd->getIntrinsicID(tree->gtCall.gtCallMethHnd) == CORINFO_INTRINSIC_Object_GetType)
15286 return TPK_GetType;
15290 else if ((tree->gtOper == GT_INTRINSIC) && (tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType))
15292 return TPK_GetType;
15294 else if ((tree->gtOper == GT_CNS_INT) && (tree->gtIntCon.gtIconVal == 0))
15300 bool isExact = false;
15301 bool isNonNull = false;
15302 CORINFO_CLASS_HANDLE clsHnd = gtGetClassHandle(tree, &isExact, &isNonNull);
15304 if (clsHnd != NO_CLASS_HANDLE && clsHnd == info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE))
15309 return TPK_Unknown;
15312 //------------------------------------------------------------------------
15313 // gtIsTypeHandleToRuntimeTypeHelperCall -- see if tree is constructing
15314 // a RuntimeType from a handle
15317 // tree - tree to examine
15322 bool Compiler::gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call)
15324 return call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE) ||
15325 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL);
15328 //------------------------------------------------------------------------
15329 // gtIsTypeHandleToRuntimeTypeHandleHelperCall -- see if tree is constructing
15330 // a RuntimeTypeHandle from a handle
15333 // tree - tree to examine
15334 // pHelper - optional pointer to a variable that receives the type of the helper
15339 bool Compiler::gtIsTypeHandleToRuntimeTypeHandleHelper(GenTreeCall* call, CorInfoHelpFunc* pHelper)
15341 CorInfoHelpFunc helper = CORINFO_HELP_UNDEF;
15343 if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE))
15345 helper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE;
15347 else if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL))
15349 helper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL;
15352 if (pHelper != nullptr)
15357 return helper != CORINFO_HELP_UNDEF;
15360 bool Compiler::gtIsActiveCSE_Candidate(GenTree* tree)
15362 return (optValnumCSE_phase && IS_CSE_INDEX(tree->gtCSEnum));
15365 /*****************************************************************************/
15367 struct ComplexityStruct
15369 unsigned m_numNodes;
15370 unsigned m_nodeLimit;
15371 ComplexityStruct(unsigned nodeLimit) : m_numNodes(0), m_nodeLimit(nodeLimit)
15376 static Compiler::fgWalkResult ComplexityExceedsWalker(GenTree** pTree, Compiler::fgWalkData* data)
15378 ComplexityStruct* pComplexity = (ComplexityStruct*)data->pCallbackData;
15379 if (++pComplexity->m_numNodes > pComplexity->m_nodeLimit)
15381 return Compiler::WALK_ABORT;
15385 return Compiler::WALK_CONTINUE;
15389 bool Compiler::gtComplexityExceeds(GenTree** tree, unsigned limit)
15391 ComplexityStruct complexity(limit);
15392 if (fgWalkTreePre(tree, &ComplexityExceedsWalker, &complexity) == WALK_ABORT)
15402 bool GenTree::IsPhiNode()
15404 return (OperGet() == GT_PHI_ARG) || (OperGet() == GT_PHI) || IsPhiDefn();
15407 bool GenTree::IsPhiDefn()
15409 bool res = ((OperGet() == GT_ASG) && (gtOp.gtOp2 != nullptr) && (gtOp.gtOp2->OperGet() == GT_PHI)) ||
15410 ((OperGet() == GT_STORE_LCL_VAR) && (gtOp.gtOp1 != nullptr) && (gtOp.gtOp1->OperGet() == GT_PHI));
15411 assert(!res || OperGet() == GT_STORE_LCL_VAR || gtOp.gtOp1->OperGet() == GT_LCL_VAR);
15415 bool GenTree::IsPhiDefnStmt()
15417 if (OperGet() != GT_STMT)
15421 GenTree* asg = gtStmt.gtStmtExpr;
15422 return asg->IsPhiDefn();
15425 // IsPartialLclFld: Check for a GT_LCL_FLD whose type is a different size than the lclVar.
15428 // comp - the Compiler object.
15431 // Returns "true" iff 'this' is a GT_LCL_FLD or GT_STORE_LCL_FLD on which the type
15432 // is not the same size as the type of the GT_LCL_VAR
15434 bool GenTree::IsPartialLclFld(Compiler* comp)
15436 return ((gtOper == GT_LCL_FLD) &&
15437 (comp->lvaTable[this->gtLclVarCommon.gtLclNum].lvExactSize != genTypeSize(gtType)));
15440 bool GenTree::DefinesLocal(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, bool* pIsEntire)
15442 GenTreeBlk* blkNode = nullptr;
15443 if (OperIs(GT_ASG))
15445 if (gtOp.gtOp1->IsLocal())
15447 GenTreeLclVarCommon* lclVarTree = gtOp.gtOp1->AsLclVarCommon();
15448 *pLclVarTree = lclVarTree;
15449 if (pIsEntire != nullptr)
15451 if (lclVarTree->IsPartialLclFld(comp))
15453 *pIsEntire = false;
15462 else if (gtOp.gtOp1->OperGet() == GT_IND)
15464 GenTree* indArg = gtOp.gtOp1->gtOp.gtOp1;
15465 return indArg->DefinesLocalAddr(comp, genTypeSize(gtOp.gtOp1->TypeGet()), pLclVarTree, pIsEntire);
15467 else if (gtOp.gtOp1->OperIsBlk())
15469 blkNode = gtOp.gtOp1->AsBlk();
15472 else if (OperIsBlk())
15474 blkNode = this->AsBlk();
15476 if (blkNode != nullptr)
15478 GenTree* destAddr = blkNode->Addr();
15479 unsigned width = blkNode->gtBlkSize;
15480 // Do we care about whether this assigns the entire variable?
15481 if (pIsEntire != nullptr && width == 0)
15483 assert(blkNode->gtOper == GT_DYN_BLK);
15484 GenTree* blockWidth = blkNode->AsDynBlk()->gtDynamicSize;
15485 if (blockWidth->IsCnsIntOrI())
15487 if (blockWidth->IsIconHandle())
15489 // If it's a handle, it must be a class handle. We only create such block operations
15490 // for initialization of struct types, so the type of the argument(s) will match this
15491 // type, by construction, and be "entire".
15492 assert(blockWidth->IsIconHandle(GTF_ICON_CLASS_HDL));
15493 width = comp->info.compCompHnd->getClassSize(
15494 CORINFO_CLASS_HANDLE(blockWidth->gtIntConCommon.IconValue()));
15498 ssize_t swidth = blockWidth->AsIntConCommon()->IconValue();
15499 assert(swidth >= 0);
15500 // cpblk of size zero exists in the wild (in yacc-generated code in SQL) and is valid IL.
15505 width = unsigned(swidth);
15509 return destAddr->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
15515 // Returns true if this GenTree defines a result which is based on the address of a local.
15516 bool GenTree::DefinesLocalAddr(Compiler* comp, unsigned width, GenTreeLclVarCommon** pLclVarTree, bool* pIsEntire)
15518 if (OperGet() == GT_ADDR || OperGet() == GT_LCL_VAR_ADDR)
15520 GenTree* addrArg = this;
15521 if (OperGet() == GT_ADDR)
15523 addrArg = gtOp.gtOp1;
15526 if (addrArg->IsLocal() || addrArg->OperIsLocalAddr())
15528 GenTreeLclVarCommon* addrArgLcl = addrArg->AsLclVarCommon();
15529 *pLclVarTree = addrArgLcl;
15530 if (pIsEntire != nullptr)
15532 unsigned lclOffset = 0;
15533 if (addrArg->OperIsLocalField())
15535 lclOffset = addrArg->gtLclFld.gtLclOffs;
15538 if (lclOffset != 0)
15540 // We aren't updating the bytes at [0..lclOffset-1] so *pIsEntire should be set to false
15541 *pIsEntire = false;
15545 unsigned lclNum = addrArgLcl->GetLclNum();
15546 unsigned varWidth = comp->lvaLclExactSize(lclNum);
15547 if (comp->lvaTable[lclNum].lvNormalizeOnStore())
15549 // It's normalize on store, so use the full storage width -- writing to low bytes won't
15550 // necessarily yield a normalized value.
15551 varWidth = genTypeStSz(var_types(comp->lvaTable[lclNum].lvType)) * sizeof(int);
15553 *pIsEntire = (varWidth == width);
15558 else if (addrArg->OperGet() == GT_IND)
15560 // A GT_ADDR of a GT_IND can both be optimized away, recurse using the child of the GT_IND
15561 return addrArg->gtOp.gtOp1->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
15564 else if (OperGet() == GT_ADD)
15566 if (gtOp.gtOp1->IsCnsIntOrI())
15568 // If we just adding a zero then we allow an IsEntire match against width
15569 // otherwise we change width to zero to disallow an IsEntire Match
15570 return gtOp.gtOp2->DefinesLocalAddr(comp, gtOp.gtOp1->IsIntegralConst(0) ? width : 0, pLclVarTree,
15573 else if (gtOp.gtOp2->IsCnsIntOrI())
15575 // If we just adding a zero then we allow an IsEntire match against width
15576 // otherwise we change width to zero to disallow an IsEntire Match
15577 return gtOp.gtOp1->DefinesLocalAddr(comp, gtOp.gtOp2->IsIntegralConst(0) ? width : 0, pLclVarTree,
15581 // Post rationalization we could have GT_IND(GT_LEA(..)) trees.
15582 else if (OperGet() == GT_LEA)
15584 // This method gets invoked during liveness computation and therefore it is critical
15585 // that we don't miss 'use' of any local. The below logic is making the assumption
15586 // that in case of LEA(base, index, offset) - only base can be a GT_LCL_VAR_ADDR
15587 // and index is not.
15588 CLANG_FORMAT_COMMENT_ANCHOR;
15591 GenTree* index = gtOp.gtOp2;
15592 if (index != nullptr)
15594 assert(!index->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire));
15599 GenTree* base = gtOp.gtOp1;
15600 if (base != nullptr)
15602 // Lea could have an Indir as its base.
15603 if (base->OperGet() == GT_IND)
15605 base = base->gtOp.gtOp1->gtEffectiveVal(/*commas only*/ true);
15607 return base->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
15614 //------------------------------------------------------------------------
15615 // IsLocalExpr: Determine if this is a LclVarCommon node and return some
15616 // additional info about it in the two out parameters.
15619 // comp - The Compiler instance
15620 // pLclVarTree - An "out" argument that returns the local tree as a
15621 // LclVarCommon, if it is indeed local.
15622 // pFldSeq - An "out" argument that returns the value numbering field
15623 // sequence for the node, if any.
15626 // Returns true, and sets the out arguments accordingly, if this is
15627 // a LclVarCommon node.
15629 bool GenTree::IsLocalExpr(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, FieldSeqNode** pFldSeq)
15631 if (IsLocal()) // Note that this covers "GT_LCL_FLD."
15633 *pLclVarTree = AsLclVarCommon();
15634 if (OperGet() == GT_LCL_FLD)
15636 // Otherwise, prepend this field to whatever we've already accumulated outside in.
15637 *pFldSeq = comp->GetFieldSeqStore()->Append(AsLclFld()->gtFieldSeq, *pFldSeq);
15647 // If this tree evaluates some sum of a local address and some constants,
15648 // return the node for the local being addressed
15650 GenTreeLclVarCommon* GenTree::IsLocalAddrExpr()
15652 if (OperGet() == GT_ADDR)
15654 return gtOp.gtOp1->IsLocal() ? gtOp.gtOp1->AsLclVarCommon() : nullptr;
15656 else if (OperIsLocalAddr())
15658 return this->AsLclVarCommon();
15660 else if (OperGet() == GT_ADD)
15662 if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
15664 return gtOp.gtOp2->IsLocalAddrExpr();
15666 else if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
15668 return gtOp.gtOp1->IsLocalAddrExpr();
15675 bool GenTree::IsLocalAddrExpr(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, FieldSeqNode** pFldSeq)
15677 if (OperGet() == GT_ADDR)
15679 assert(!comp->compRationalIRForm);
15680 GenTree* addrArg = gtOp.gtOp1;
15681 if (addrArg->IsLocal()) // Note that this covers "GT_LCL_FLD."
15683 *pLclVarTree = addrArg->AsLclVarCommon();
15684 if (addrArg->OperGet() == GT_LCL_FLD)
15686 // Otherwise, prepend this field to whatever we've already accumulated outside in.
15687 *pFldSeq = comp->GetFieldSeqStore()->Append(addrArg->AsLclFld()->gtFieldSeq, *pFldSeq);
15696 else if (OperIsLocalAddr())
15698 *pLclVarTree = this->AsLclVarCommon();
15699 if (this->OperGet() == GT_LCL_FLD_ADDR)
15701 *pFldSeq = comp->GetFieldSeqStore()->Append(this->AsLclFld()->gtFieldSeq, *pFldSeq);
15705 else if (OperGet() == GT_ADD)
15707 if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
15709 if (gtOp.gtOp1->AsIntCon()->gtFieldSeq == nullptr)
15713 // Otherwise, prepend this field to whatever we've already accumulated outside in.
15714 *pFldSeq = comp->GetFieldSeqStore()->Append(gtOp.gtOp1->AsIntCon()->gtFieldSeq, *pFldSeq);
15715 return gtOp.gtOp2->IsLocalAddrExpr(comp, pLclVarTree, pFldSeq);
15717 else if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
15719 if (gtOp.gtOp2->AsIntCon()->gtFieldSeq == nullptr)
15723 // Otherwise, prepend this field to whatever we've already accumulated outside in.
15724 *pFldSeq = comp->GetFieldSeqStore()->Append(gtOp.gtOp2->AsIntCon()->gtFieldSeq, *pFldSeq);
15725 return gtOp.gtOp1->IsLocalAddrExpr(comp, pLclVarTree, pFldSeq);
15732 //------------------------------------------------------------------------
15733 // IsLclVarUpdateTree: Determine whether this is an assignment tree of the
15734 // form Vn = Vn 'oper' 'otherTree' where Vn is a lclVar
15737 // pOtherTree - An "out" argument in which 'otherTree' will be returned.
15738 // pOper - An "out" argument in which 'oper' will be returned.
15741 // If the tree is of the above form, the lclNum of the variable being
15742 // updated is returned, and 'pOtherTree' and 'pOper' are set.
15743 // Otherwise, returns BAD_VAR_NUM.
15746 // 'otherTree' can have any shape.
15747 // We avoid worrying about whether the op is commutative by only considering the
15748 // first operand of the rhs. It is expected that most trees of this form will
15749 // already have the lclVar on the lhs.
15750 // TODO-CQ: Evaluate whether there are missed opportunities due to this, or
15751 // whether gtSetEvalOrder will already have put the lclVar on the lhs in
15752 // the cases of interest.
15754 unsigned GenTree::IsLclVarUpdateTree(GenTree** pOtherTree, genTreeOps* pOper)
15756 unsigned lclNum = BAD_VAR_NUM;
15757 if (OperIs(GT_ASG))
15759 GenTree* lhs = gtOp.gtOp1;
15760 if (lhs->OperGet() == GT_LCL_VAR)
15762 unsigned lhsLclNum = lhs->AsLclVarCommon()->gtLclNum;
15763 GenTree* rhs = gtOp.gtOp2;
15764 if (rhs->OperIsBinary() && (rhs->gtOp.gtOp1->gtOper == GT_LCL_VAR) &&
15765 (rhs->gtOp.gtOp1->AsLclVarCommon()->gtLclNum == lhsLclNum))
15767 lclNum = lhsLclNum;
15768 *pOtherTree = rhs->gtOp.gtOp2;
15769 *pOper = rhs->gtOper;
15776 //------------------------------------------------------------------------
15777 // canBeContained: check whether this tree node may be a subcomponent of its parent for purposes
15778 // of code generation.
15780 // Return value: returns true if it is possible to contain this node and false otherwise.
15781 bool GenTree::canBeContained() const
15790 // It is not possible for nodes that do not produce values or that are not containable values
15791 // to be contained.
15792 if (((OperKind() & (GTK_NOVALUE | GTK_NOCONTAIN)) != 0) || (OperIsHWIntrinsic() && !isContainableHWIntrinsic()))
15800 //------------------------------------------------------------------------
15801 // isContained: check whether this tree node is a subcomponent of its parent for codegen purposes
15804 // Returns true if there is no code generated explicitly for this node.
15805 // Essentially, it will be rolled into the code generation for the parent.
15808 // This method relies upon the value of the GTF_CONTAINED flag.
15809 // Therefore this method is only valid after Lowering.
15810 // Also note that register allocation or other subsequent phases may cause
15811 // nodes to become contained (or not) and therefore this property may change.
15813 bool GenTree::isContained() const
15816 const bool isMarkedContained = ((gtFlags & GTF_CONTAINED) != 0);
15819 if (!canBeContained())
15821 assert(!isMarkedContained);
15824 // these actually produce a register (the flags reg, we just don't model it)
15825 // and are a separate instruction from the branch that consumes the result.
15826 // They can only produce a result if the child is a SIMD equality comparison.
15827 else if (OperKind() & GTK_RELOP)
15829 // We have to cast away const-ness since AsOp() method is non-const.
15830 GenTree* childNode = const_cast<GenTree*>(this)->AsOp()->gtOp1;
15831 assert((isMarkedContained == false) || childNode->IsSIMDEqualityOrInequality());
15834 // these either produce a result in register or set flags reg.
15835 else if (IsSIMDEqualityOrInequality())
15837 assert(!isMarkedContained);
15840 // if it's contained it can't be unused.
15841 if (isMarkedContained)
15843 assert(!IsUnusedValue());
15846 return isMarkedContained;
15849 // return true if node is contained and an indir
15850 bool GenTree::isContainedIndir() const
15852 return isIndir() && isContained();
15855 bool GenTree::isIndirAddrMode()
15857 return isIndir() && AsIndir()->Addr()->OperIsAddrMode() && AsIndir()->Addr()->isContained();
15860 bool GenTree::isIndir() const
15862 return OperGet() == GT_IND || OperGet() == GT_STOREIND;
15865 bool GenTreeIndir::HasBase()
15867 return Base() != nullptr;
15870 bool GenTreeIndir::HasIndex()
15872 return Index() != nullptr;
15875 GenTree* GenTreeIndir::Base()
15877 GenTree* addr = Addr();
15879 if (isIndirAddrMode())
15881 GenTree* result = addr->AsAddrMode()->Base();
15882 if (result != nullptr)
15884 result = result->gtEffectiveVal();
15890 return addr; // TODO: why do we return 'addr' here, but we return 'nullptr' in the equivalent Index() case?
15894 GenTree* GenTreeIndir::Index()
15896 if (isIndirAddrMode())
15898 GenTree* result = Addr()->AsAddrMode()->Index();
15899 if (result != nullptr)
15901 result = result->gtEffectiveVal();
15911 unsigned GenTreeIndir::Scale()
15915 return Addr()->AsAddrMode()->gtScale;
15923 ssize_t GenTreeIndir::Offset()
15925 if (isIndirAddrMode())
15927 return Addr()->AsAddrMode()->Offset();
15929 else if (Addr()->gtOper == GT_CLS_VAR_ADDR)
15931 return static_cast<ssize_t>(reinterpret_cast<intptr_t>(Addr()->gtClsVar.gtClsVarHnd));
15933 else if (Addr()->IsCnsIntOrI() && Addr()->isContained())
15935 return Addr()->AsIntConCommon()->IconValue();
15943 //------------------------------------------------------------------------
15944 // GenTreeIntConCommon::ImmedValNeedsReloc: does this immediate value needs recording a relocation with the VM?
15947 // comp - Compiler instance
15950 // True if this immediate value requires us to record a relocation for it; false otherwise.
15952 bool GenTreeIntConCommon::ImmedValNeedsReloc(Compiler* comp)
15954 return comp->opts.compReloc && (gtOper == GT_CNS_INT) && IsIconHandle();
15957 //------------------------------------------------------------------------
15958 // ImmedValCanBeFolded: can this immediate value be folded for op?
15961 // comp - Compiler instance
15962 // op - Tree operator
15965 // True if this immediate value can be folded for op; false otherwise.
15967 bool GenTreeIntConCommon::ImmedValCanBeFolded(Compiler* comp, genTreeOps op)
15969 // In general, immediate values that need relocations can't be folded.
15970 // There are cases where we do want to allow folding of handle comparisons
15971 // (e.g., typeof(T) == typeof(int)).
15972 return !ImmedValNeedsReloc(comp) || (op == GT_EQ) || (op == GT_NE);
15975 #ifdef _TARGET_AMD64_
15976 // Returns true if this absolute address fits within the base of an addr mode.
15977 // On Amd64 this effectively means, whether an absolute indirect address can
15978 // be encoded as 32-bit offset relative to IP or zero.
15979 bool GenTreeIntConCommon::FitsInAddrBase(Compiler* comp)
15982 // Early out if PC-rel encoding of absolute addr is disabled.
15983 if (!comp->opts.compEnablePCRelAddr)
15989 if (comp->opts.compReloc)
15991 // During Ngen JIT is always asked to generate relocatable code.
15992 // Hence JIT will try to encode only icon handles as pc-relative offsets.
15993 return IsIconHandle() && (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue()));
15997 // During Jitting, we are allowed to generate non-relocatable code.
15998 // On Amd64 we can encode an absolute indirect addr as an offset relative to zero or RIP.
15999 // An absolute indir addr that can fit within 32-bits can ben encoded as an offset relative
16000 // to zero. All other absolute indir addr could be attempted to be encoded as RIP relative
16001 // based on reloc hint provided by VM. RIP relative encoding is preferred over relative
16002 // to zero, because the former is one byte smaller than the latter. For this reason
16003 // we check for reloc hint first and then whether addr fits in 32-bits next.
16005 // VM starts off with an initial state to allow both data and code address to be encoded as
16006 // pc-relative offsets. Hence JIT will attempt to encode all absolute addresses as pc-relative
16007 // offsets. It is possible while jitting a method, an address could not be encoded as a
16008 // pc-relative offset. In that case VM will note the overflow and will trigger re-jitting
16009 // of the method with reloc hints turned off for all future methods. Second time around
16010 // jitting will succeed since JIT will not attempt to encode data addresses as pc-relative
16011 // offsets. Note that JIT will always attempt to relocate code addresses (.e.g call addr).
16012 // After an overflow, VM will assume any relocation recorded is for a code address and will
16013 // emit jump thunk if it cannot be encoded as pc-relative offset.
16014 return (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue())) || FitsInI32();
16018 // Returns true if this icon value is encoded as addr needs recording a relocation with VM
16019 bool GenTreeIntConCommon::AddrNeedsReloc(Compiler* comp)
16021 if (comp->opts.compReloc)
16023 // During Ngen JIT is always asked to generate relocatable code.
16024 // Hence JIT will try to encode only icon handles as pc-relative offsets.
16025 return IsIconHandle() && (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue()));
16029 return IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue());
16033 #elif defined(_TARGET_X86_)
16034 // Returns true if this absolute address fits within the base of an addr mode.
16035 // On x86 all addresses are 4-bytes and can be directly encoded in an addr mode.
16036 bool GenTreeIntConCommon::FitsInAddrBase(Compiler* comp)
16039 // Early out if PC-rel encoding of absolute addr is disabled.
16040 if (!comp->opts.compEnablePCRelAddr)
16046 return IsCnsIntOrI();
16049 // Returns true if this icon value is encoded as addr needs recording a relocation with VM
16050 bool GenTreeIntConCommon::AddrNeedsReloc(Compiler* comp)
16052 // If generating relocatable code, icons should be reported for recording relocatons.
16053 return comp->opts.compReloc && IsIconHandle();
16055 #endif //_TARGET_X86_
16057 bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pObj, GenTree** pStatic, FieldSeqNode** pFldSeq)
16059 FieldSeqNode* newFldSeq = nullptr;
16060 GenTree* baseAddr = nullptr;
16061 bool mustBeStatic = false;
16063 FieldSeqNode* statStructFldSeq = nullptr;
16064 if (TypeGet() == TYP_REF)
16066 // Recognize struct static field patterns...
16067 if (OperGet() == GT_IND)
16069 GenTree* addr = gtOp.gtOp1;
16070 GenTreeIntCon* icon = nullptr;
16071 if (addr->OperGet() == GT_CNS_INT)
16073 icon = addr->AsIntCon();
16075 else if (addr->OperGet() == GT_ADD)
16077 // op1 should never be a field sequence (or any other kind of handle)
16078 assert((addr->gtOp.gtOp1->gtOper != GT_CNS_INT) || !addr->gtOp.gtOp1->IsIconHandle());
16079 if (addr->gtOp.gtOp2->OperGet() == GT_CNS_INT)
16081 icon = addr->gtOp.gtOp2->AsIntCon();
16084 if (icon != nullptr && !icon->IsIconHandle(GTF_ICON_STR_HDL) // String handles are a source of TYP_REFs.
16085 && icon->gtFieldSeq != nullptr &&
16086 icon->gtFieldSeq->m_next == nullptr // A static field should be a singleton
16087 // TODO-Review: A pseudoField here indicates an issue - this requires investigation
16088 // See test case src\ddsuites\src\clr\x86\CoreMangLib\Dev\Globalization\CalendarRegressions.exe
16089 && !(FieldSeqStore::IsPseudoField(icon->gtFieldSeq->m_fieldHnd)) &&
16090 icon->gtFieldSeq != FieldSeqStore::NotAField()) // Ignore non-fields.
16092 statStructFldSeq = icon->gtFieldSeq;
16096 addr = addr->gtEffectiveVal();
16098 // Perhaps it's a direct indirection of a helper call or a cse with a zero offset annotation.
16099 if ((addr->OperGet() == GT_CALL) || (addr->OperGet() == GT_LCL_VAR))
16101 FieldSeqNode* zeroFieldSeq = nullptr;
16102 if (comp->GetZeroOffsetFieldMap()->Lookup(addr, &zeroFieldSeq))
16104 if (zeroFieldSeq->m_next == nullptr)
16106 statStructFldSeq = zeroFieldSeq;
16112 else if (OperGet() == GT_CLS_VAR)
16114 GenTreeClsVar* clsVar = AsClsVar();
16115 if (clsVar->gtFieldSeq != nullptr && clsVar->gtFieldSeq->m_next == nullptr)
16117 statStructFldSeq = clsVar->gtFieldSeq;
16120 else if (OperIsLocal())
16122 // If we have a GT_LCL_VAR, it can be result of a CSE substitution
16123 // If it is then the CSE assignment will have a ValueNum that
16124 // describes the RHS of the CSE assignment.
16126 // The CSE could be a pointer to a boxed struct
16128 GenTreeLclVarCommon* lclVar = AsLclVarCommon();
16129 ValueNum vn = gtVNPair.GetLiberal();
16130 if (vn != ValueNumStore::NoVN)
16132 // Is the ValueNum a MapSelect involving a SharedStatic helper?
16133 VNFuncApp funcApp1;
16134 if (comp->vnStore->GetVNFunc(vn, &funcApp1) && (funcApp1.m_func == VNF_MapSelect) &&
16135 (comp->vnStore->IsSharedStatic(funcApp1.m_args[1])))
16137 ValueNum mapVN = funcApp1.m_args[0];
16138 // Is this new 'mapVN' ValueNum, a MapSelect involving a handle?
16139 VNFuncApp funcApp2;
16140 if (comp->vnStore->GetVNFunc(mapVN, &funcApp2) && (funcApp2.m_func == VNF_MapSelect) &&
16141 (comp->vnStore->IsVNHandle(funcApp2.m_args[1])))
16143 ValueNum fldHndVN = funcApp2.m_args[1];
16144 // Is this new 'fldHndVN' VNhandle a FieldHandle?
16145 unsigned flags = comp->vnStore->GetHandleFlags(fldHndVN);
16146 if (flags == GTF_ICON_FIELD_HDL)
16148 CORINFO_FIELD_HANDLE fieldHnd =
16149 CORINFO_FIELD_HANDLE(comp->vnStore->ConstantValue<ssize_t>(fldHndVN));
16151 // Record this field sequence in 'statStructFldSeq' as it is likely to be a Boxed Struct
16153 statStructFldSeq = comp->GetFieldSeqStore()->CreateSingleton(fieldHnd);
16160 if (statStructFldSeq != nullptr)
16162 assert(statStructFldSeq->m_next == nullptr);
16163 // Is this a pointer to a boxed struct?
16164 if (comp->gtIsStaticFieldPtrToBoxedStruct(TYP_REF, statStructFldSeq->m_fieldHnd))
16166 *pFldSeq = comp->GetFieldSeqStore()->Append(statStructFldSeq, *pFldSeq);
16175 *pStatic = nullptr;
16178 else if (OperGet() == GT_ADD)
16180 // If one operator is a field sequence/handle, the other operator must not also be a field sequence/handle.
16181 if ((gtOp.gtOp1->OperGet() == GT_CNS_INT) && gtOp.gtOp1->IsIconHandle())
16183 assert((gtOp.gtOp2->gtOper != GT_CNS_INT) || !gtOp.gtOp2->IsIconHandle());
16184 newFldSeq = gtOp.gtOp1->AsIntCon()->gtFieldSeq;
16185 baseAddr = gtOp.gtOp2;
16187 else if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
16189 assert((gtOp.gtOp1->gtOper != GT_CNS_INT) || !gtOp.gtOp1->IsIconHandle());
16190 newFldSeq = gtOp.gtOp2->AsIntCon()->gtFieldSeq;
16191 baseAddr = gtOp.gtOp1;
16196 // Check if "this" has a zero-offset annotation.
16197 if (!comp->GetZeroOffsetFieldMap()->Lookup(this, &newFldSeq))
16199 // If not, this is not a field address.
16205 mustBeStatic = true;
16209 // If not we don't have a field seq, it's not a field address.
16210 if (newFldSeq == nullptr || newFldSeq == FieldSeqStore::NotAField())
16215 // Prepend this field to whatever we've already accumulated (outside-in).
16216 *pFldSeq = comp->GetFieldSeqStore()->Append(newFldSeq, *pFldSeq);
16218 // Is it a static or instance field?
16219 if (!FieldSeqStore::IsPseudoField(newFldSeq->m_fieldHnd) &&
16220 comp->info.compCompHnd->isFieldStatic(newFldSeq->m_fieldHnd))
16222 // It is a static field. We're done.
16224 *pStatic = baseAddr;
16227 else if ((baseAddr != nullptr) && !mustBeStatic)
16229 // It's an instance field...but it must be for a struct field, since we've not yet encountered
16230 // a "TYP_REF" address. Analyze the reset of the address.
16231 return baseAddr->gtEffectiveVal()->IsFieldAddr(comp, pObj, pStatic, pFldSeq);
16238 bool Compiler::gtIsStaticFieldPtrToBoxedStruct(var_types fieldNodeType, CORINFO_FIELD_HANDLE fldHnd)
16240 if (fieldNodeType != TYP_REF)
16244 noway_assert(fldHnd != nullptr);
16245 CorInfoType cit = info.compCompHnd->getFieldType(fldHnd);
16246 var_types fieldTyp = JITtype2varType(cit);
16247 return fieldTyp != TYP_REF;
16250 #ifdef FEATURE_SIMD
16251 //------------------------------------------------------------------------
16252 // gtGetSIMDZero: Get a zero value of the appropriate SIMD type.
16255 // var_types - The simdType
16256 // baseType - The base type we need
16257 // simdHandle - The handle for the SIMD type
16260 // A node generating the appropriate Zero, if we are able to discern it,
16261 // otherwise null (note that this shouldn't happen, but callers should
16262 // be tolerant of this case).
16264 GenTree* Compiler::gtGetSIMDZero(var_types simdType, var_types baseType, CORINFO_CLASS_HANDLE simdHandle)
16266 bool found = false;
16267 bool isHWSIMD = true;
16268 noway_assert(m_simdHandleCache != nullptr);
16270 // First, determine whether this is Vector<T>.
16271 if (simdType == getSIMDVectorType())
16276 found = (simdHandle == m_simdHandleCache->SIMDFloatHandle);
16279 found = (simdHandle == m_simdHandleCache->SIMDDoubleHandle);
16282 found = (simdHandle == m_simdHandleCache->SIMDIntHandle);
16285 found = (simdHandle == m_simdHandleCache->SIMDUShortHandle);
16288 found = (simdHandle == m_simdHandleCache->SIMDUByteHandle);
16291 found = (simdHandle == m_simdHandleCache->SIMDShortHandle);
16294 found = (simdHandle == m_simdHandleCache->SIMDByteHandle);
16297 found = (simdHandle == m_simdHandleCache->SIMDLongHandle);
16300 found = (simdHandle == m_simdHandleCache->SIMDUIntHandle);
16303 found = (simdHandle == m_simdHandleCache->SIMDULongHandle);
16316 // We must still have isHWSIMD set to true, and the only non-HW types left are the fixed types.
16323 if (simdHandle == m_simdHandleCache->SIMDVector2Handle)
16327 #if defined(_TARGET_ARM64_) && defined(FEATURE_HW_INTRINSICS)
16330 assert(simdHandle == m_simdHandleCache->Vector64FloatHandle);
16334 assert(simdHandle == m_simdHandleCache->Vector64IntHandle);
16337 assert(simdHandle == m_simdHandleCache->Vector64UShortHandle);
16340 assert(simdHandle == m_simdHandleCache->Vector64UByteHandle);
16343 assert(simdHandle == m_simdHandleCache->Vector64ShortHandle);
16346 assert(simdHandle == m_simdHandleCache->Vector64ByteHandle);
16349 assert(simdHandle == m_simdHandleCache->Vector64UIntHandle);
16351 #endif // defined(_TARGET_ARM64_) && defined(FEATURE_HW_INTRINSICS)
16358 assert((baseType == TYP_FLOAT) && (simdHandle == m_simdHandleCache->SIMDVector3Handle));
16366 if (simdHandle == m_simdHandleCache->SIMDVector4Handle)
16370 #if defined(FEATURE_HW_INTRINSICS)
16373 assert(simdHandle == m_simdHandleCache->Vector128FloatHandle);
16377 assert(simdHandle == m_simdHandleCache->Vector128DoubleHandle);
16380 assert(simdHandle == m_simdHandleCache->Vector128IntHandle);
16383 assert(simdHandle == m_simdHandleCache->Vector128UShortHandle);
16386 assert(simdHandle == m_simdHandleCache->Vector128UByteHandle);
16389 assert(simdHandle == m_simdHandleCache->Vector128ShortHandle);
16392 assert(simdHandle == m_simdHandleCache->Vector128ByteHandle);
16395 assert(simdHandle == m_simdHandleCache->Vector128LongHandle);
16398 assert(simdHandle == m_simdHandleCache->Vector128UIntHandle);
16401 assert(simdHandle == m_simdHandleCache->Vector128ULongHandle);
16403 #endif // defined(FEATURE_HW_INTRINSICS)
16410 #if defined(_TARGET_XARCH4_) && defined(FEATURE_HW_INTRINSICS)
16415 assert(simdHandle == m_simdHandleCache->Vector256FloatHandle);
16418 assert(simdHandle == m_simdHandleCache->Vector256DoubleHandle);
16421 assert(simdHandle == m_simdHandleCache->Vector256IntHandle);
16424 assert(simdHandle == m_simdHandleCache->Vector256UShortHandle);
16427 assert(simdHandle == m_simdHandleCache->Vector256UByteHandle);
16430 assert(simdHandle == m_simdHandleCache->Vector256ShortHandle);
16433 assert(simdHandle == m_simdHandleCache->Vector256ByteHandle);
16436 assert(simdHandle == m_simdHandleCache->Vector256LongHandle);
16439 assert(simdHandle == m_simdHandleCache->Vector256UIntHandle);
16442 assert(simdHandle == m_simdHandleCache->Vector256ULongHandle);
16448 #endif // _TARGET_XARCH_ && FEATURE_HW_INTRINSICS
16454 unsigned size = genTypeSize(simdType);
16457 #if defined(_TARGET_XARCH_) && defined(FEATURE_HW_INTRINSICS)
16461 if (compSupports(InstructionSet_SSE))
16463 // We only return the HWIntrinsicNode if SSE is supported, since it is possible for
16464 // the user to disable the SSE HWIntrinsic support via the COMPlus configuration knobs
16465 // even though the hardware vector types are still available.
16466 return gtNewSimdHWIntrinsicNode(simdType, NI_Base_Vector128_Zero, baseType, size);
16470 if (compSupports(InstructionSet_AVX))
16472 // We only return the HWIntrinsicNode if AVX is supported, since it is possible for
16473 // the user to disable the AVX HWIntrinsic support via the COMPlus configuration knobs
16474 // even though the hardware vector types are still available.
16475 return gtNewSimdHWIntrinsicNode(simdType, NI_Base_Vector256_Zero, baseType, size);
16481 #endif // _TARGET_XARCH_ && FEATURE_HW_INTRINSICS
16482 JITDUMP("Coudn't find the matching SIMD type for %s<%s> in gtGetSIMDZero\n", varTypeName(simdType),
16483 varTypeName(baseType));
16487 return gtNewSIMDVectorZero(simdType, baseType, size);
16491 #endif // FEATURE_SIMD
16493 CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleIfPresent(GenTree* tree)
16495 CORINFO_CLASS_HANDLE structHnd = NO_CLASS_HANDLE;
16496 tree = tree->gtEffectiveVal();
16497 if (varTypeIsStruct(tree->gtType))
16499 switch (tree->gtOper)
16504 structHnd = impGetRefAnyClass();
16507 structHnd = tree->gtObj.gtClass;
16510 structHnd = tree->gtCall.gtRetClsHnd;
16513 structHnd = tree->gtRetExpr.gtRetClsHnd;
16516 structHnd = tree->gtArgPlace.gtArgPlaceClsHnd;
16519 structHnd = tree->gtIndex.gtStructElemClass;
16521 case GT_INDEX_ADDR:
16522 structHnd = tree->AsIndexAddr()->gtStructElemClass;
16525 info.compCompHnd->getFieldType(tree->gtField.gtFldHnd, &structHnd);
16528 structHnd = gtGetStructHandleIfPresent(tree->gtGetOp1());
16531 #ifdef FEATURE_SIMD
16532 if (varTypeIsSIMD(tree))
16534 structHnd = gtGetStructHandleForSIMD(tree->gtType, TYP_FLOAT);
16539 structHnd = lvaTable[tree->AsLclVarCommon()->gtLclNum].lvVerTypeInfo.GetClassHandle();
16542 structHnd = gtGetStructHandleIfPresent(tree->gtOp.gtOp1);
16545 #ifdef FEATURE_SIMD
16546 if (varTypeIsSIMD(tree))
16548 structHnd = gtGetStructHandleForSIMD(tree->gtType, TYP_FLOAT);
16554 if (TryGetArrayInfo(tree->AsIndir(), &arrInfo))
16556 structHnd = EncodeElemType(arrInfo.m_elemType, arrInfo.m_elemStructType);
16560 #ifdef FEATURE_SIMD
16562 structHnd = gtGetStructHandleForSIMD(tree->gtType, tree->AsSIMD()->gtSIMDBaseType);
16564 #endif // FEATURE_SIMD
16565 #ifdef FEATURE_HW_INTRINSICS
16566 case GT_HWIntrinsic:
16567 structHnd = gtGetStructHandleForHWSIMD(tree->gtType, tree->AsHWIntrinsic()->gtSIMDBaseType);
16576 CORINFO_CLASS_HANDLE Compiler::gtGetStructHandle(GenTree* tree)
16578 CORINFO_CLASS_HANDLE structHnd = gtGetStructHandleIfPresent(tree);
16579 assert(structHnd != NO_CLASS_HANDLE);
16583 //------------------------------------------------------------------------
16584 // gtGetClassHandle: find class handle for a ref type
16587 // tree -- tree to find handle for
16588 // pIsExact [out] -- whether handle is exact type
16589 // pIsNonNull [out] -- whether tree value is known not to be null
16592 // nullptr if class handle is unknown,
16593 // otherwise the class handle.
16594 // *pIsExact set true if tree type is known to be exactly the handle type,
16595 // otherwise actual type may be a subtype.
16596 // *pIsNonNull set true if tree value is known not to be null,
16597 // otherwise a null value is possible.
16599 CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, bool* pIsNonNull)
16601 // Set default values for our out params.
16602 *pIsNonNull = false;
16604 CORINFO_CLASS_HANDLE objClass = nullptr;
16606 // Bail out if we're just importing and not generating code, since
16607 // the jit uses TYP_REF for CORINFO_TYPE_VAR locals and args, but
16608 // these may not be ref types.
16609 if (compIsForImportOnly())
16614 // Bail out if the tree is not a ref type.
16615 var_types treeType = tree->TypeGet();
16616 if (treeType != TYP_REF)
16621 // Tunnel through commas.
16622 GenTree* obj = tree->gtEffectiveVal(false);
16623 const genTreeOps objOp = obj->OperGet();
16629 // gtEffectiveVal above means we shouldn't see commas here.
16630 assert(!"unexpected GT_COMMA");
16636 // For locals, pick up type info from the local table.
16637 const unsigned objLcl = obj->AsLclVar()->GetLclNum();
16639 objClass = lvaTable[objLcl].lvClassHnd;
16640 *pIsExact = lvaTable[objLcl].lvClassIsExact;
16646 // For fields, get the type from the field handle.
16647 CORINFO_FIELD_HANDLE fieldHnd = obj->gtField.gtFldHnd;
16649 if (fieldHnd != nullptr)
16651 objClass = gtGetFieldClassHandle(fieldHnd, pIsExact, pIsNonNull);
16659 // If we see a RET_EXPR, recurse through to examine the
16660 // return value expression.
16661 GenTree* retExpr = tree->gtRetExpr.gtInlineCandidate;
16662 objClass = gtGetClassHandle(retExpr, pIsExact, pIsNonNull);
16668 GenTreeCall* call = tree->AsCall();
16669 if (call->IsInlineCandidate())
16671 // For inline candidates, we've already cached the return
16672 // type class handle in the inline info.
16673 InlineCandidateInfo* inlInfo = call->gtInlineCandidateInfo;
16674 assert(inlInfo != nullptr);
16676 // Grab it as our first cut at a return type.
16677 assert(inlInfo->methInfo.args.retType == CORINFO_TYPE_CLASS);
16678 objClass = inlInfo->methInfo.args.retTypeClass;
16680 // If the method is shared, the above may not capture
16681 // the most precise return type information (that is,
16682 // it may represent a shared return type and as such,
16683 // have instances of __Canon). See if we can use the
16684 // context to get at something more definite.
16686 // For now, we do this here on demand rather than when
16687 // processing the call, but we could/should apply
16688 // similar sharpening to the argument and local types
16690 const unsigned retClassFlags = info.compCompHnd->getClassAttribs(objClass);
16691 if (retClassFlags & CORINFO_FLG_SHAREDINST)
16693 CORINFO_CONTEXT_HANDLE context = inlInfo->exactContextHnd;
16695 if (context != nullptr)
16697 CORINFO_CLASS_HANDLE exactClass = nullptr;
16699 if (((size_t)context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
16701 exactClass = (CORINFO_CLASS_HANDLE)((size_t)context & ~CORINFO_CONTEXTFLAGS_MASK);
16705 CORINFO_METHOD_HANDLE exactMethod =
16706 (CORINFO_METHOD_HANDLE)((size_t)context & ~CORINFO_CONTEXTFLAGS_MASK);
16707 exactClass = info.compCompHnd->getMethodClass(exactMethod);
16710 // Grab the signature in this context.
16711 CORINFO_SIG_INFO sig;
16712 eeGetMethodSig(call->gtCallMethHnd, &sig, exactClass);
16713 assert(sig.retType == CORINFO_TYPE_CLASS);
16714 objClass = sig.retTypeClass;
16718 else if (call->gtCallType == CT_USER_FUNC)
16720 // For user calls, we can fetch the approximate return
16721 // type info from the method handle. Unfortunately
16722 // we've lost the exact context, so this is the best
16723 // we can do for now.
16724 CORINFO_METHOD_HANDLE method = call->gtCallMethHnd;
16725 CORINFO_CLASS_HANDLE exactClass = nullptr;
16726 CORINFO_SIG_INFO sig;
16727 eeGetMethodSig(method, &sig, exactClass);
16728 if (sig.retType == CORINFO_TYPE_VOID)
16730 // This is a constructor call.
16731 const unsigned methodFlags = info.compCompHnd->getMethodAttribs(method);
16732 assert((methodFlags & CORINFO_FLG_CONSTRUCTOR) != 0);
16733 objClass = info.compCompHnd->getMethodClass(method);
16735 *pIsNonNull = true;
16739 assert(sig.retType == CORINFO_TYPE_CLASS);
16740 objClass = sig.retTypeClass;
16743 else if (call->gtCallType == CT_HELPER)
16745 objClass = gtGetHelperCallClassHandle(call, pIsExact, pIsNonNull);
16753 GenTreeIntrinsic* intrinsic = obj->AsIntrinsic();
16755 if (intrinsic->gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType)
16757 CORINFO_CLASS_HANDLE runtimeType = info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE);
16758 assert(runtimeType != NO_CLASS_HANDLE);
16760 objClass = runtimeType;
16762 *pIsNonNull = true;
16770 // For literal strings, we know the class and that the
16771 // value is not null.
16772 objClass = impGetStringClass();
16774 *pIsNonNull = true;
16780 GenTreeIndir* indir = obj->AsIndir();
16782 if (indir->HasBase() && !indir->HasIndex())
16784 // indir(addr(lcl)) --> lcl
16786 // This comes up during constrained callvirt on ref types.
16788 GenTree* base = indir->Base();
16789 GenTreeLclVarCommon* lcl = base->IsLocalAddrExpr();
16791 if ((lcl != nullptr) && (base->OperGet() != GT_ADD))
16793 const unsigned objLcl = lcl->GetLclNum();
16794 objClass = lvaTable[objLcl].lvClassHnd;
16795 *pIsExact = lvaTable[objLcl].lvClassIsExact;
16797 else if (base->OperGet() == GT_ARR_ELEM)
16799 // indir(arr_elem(...)) -> array element type
16801 GenTree* array = base->AsArrElem()->gtArrObj;
16803 objClass = gtGetArrayElementClassHandle(array);
16805 *pIsNonNull = false;
16807 else if (base->OperGet() == GT_ADD)
16809 // This could be a static field access.
16811 // See if op1 is a static field base helper call
16812 // and if so, op2 will have the field info.
16813 GenTree* op1 = base->gtOp.gtOp1;
16814 GenTree* op2 = base->gtOp.gtOp2;
16816 const bool op1IsStaticFieldBase = gtIsStaticGCBaseHelperCall(op1);
16818 if (op1IsStaticFieldBase && (op2->OperGet() == GT_CNS_INT))
16820 FieldSeqNode* fieldSeq = op2->AsIntCon()->gtFieldSeq;
16822 if (fieldSeq != nullptr)
16824 while (fieldSeq->m_next != nullptr)
16826 fieldSeq = fieldSeq->m_next;
16829 assert(!fieldSeq->IsPseudoField());
16831 // No benefit to calling gtGetFieldClassHandle here, as
16832 // the exact field being accessed can vary.
16833 CORINFO_FIELD_HANDLE fieldHnd = fieldSeq->m_fieldHnd;
16834 CORINFO_CLASS_HANDLE fieldClass = nullptr;
16835 CorInfoType fieldCorType = info.compCompHnd->getFieldType(fieldHnd, &fieldClass);
16837 assert(fieldCorType == CORINFO_TYPE_CLASS);
16838 objClass = fieldClass;
16849 // Box should just wrap a local var reference which has
16850 // the type we're looking for. Also box only represents a
16851 // non-nullable value type so result cannot be null.
16852 GenTreeBox* box = obj->AsBox();
16853 GenTree* boxTemp = box->BoxOp();
16854 assert(boxTemp->IsLocal());
16855 const unsigned boxTempLcl = boxTemp->AsLclVar()->GetLclNum();
16856 objClass = lvaTable[boxTempLcl].lvClassHnd;
16857 *pIsExact = lvaTable[boxTempLcl].lvClassIsExact;
16858 *pIsNonNull = true;
16864 GenTree* array = obj->AsIndex()->Arr();
16866 objClass = gtGetArrayElementClassHandle(array);
16868 *pIsNonNull = false;
16881 //------------------------------------------------------------------------
16882 // gtGetHelperCallClassHandle: find class handle for return value of a
16886 // call - helper call to examine
16887 // pIsExact - [OUT] true if type is known exactly
16888 // pIsNonNull - [OUT] true if return value is not null
16891 // nullptr if helper call result is not a ref class, or the class handle
16892 // is unknown, otherwise the class handle.
16894 CORINFO_CLASS_HANDLE Compiler::gtGetHelperCallClassHandle(GenTreeCall* call, bool* pIsExact, bool* pIsNonNull)
16896 assert(call->gtCallType == CT_HELPER);
16898 *pIsNonNull = false;
16900 CORINFO_CLASS_HANDLE objClass = nullptr;
16901 const CorInfoHelpFunc helper = eeGetHelperNum(call->gtCallMethHnd);
16905 case CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE:
16906 case CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL:
16908 // Note for some runtimes these helpers return exact types.
16910 // But in those cases the types are also sealed, so there's no
16911 // need to claim exactness here.
16912 const bool helperResultNonNull = (helper == CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE);
16913 CORINFO_CLASS_HANDLE runtimeType = info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE);
16915 assert(runtimeType != NO_CLASS_HANDLE);
16917 objClass = runtimeType;
16918 *pIsNonNull = helperResultNonNull;
16922 case CORINFO_HELP_CHKCASTCLASS:
16923 case CORINFO_HELP_CHKCASTANY:
16924 case CORINFO_HELP_CHKCASTARRAY:
16925 case CORINFO_HELP_CHKCASTINTERFACE:
16926 case CORINFO_HELP_CHKCASTCLASS_SPECIAL:
16927 case CORINFO_HELP_ISINSTANCEOFINTERFACE:
16928 case CORINFO_HELP_ISINSTANCEOFARRAY:
16929 case CORINFO_HELP_ISINSTANCEOFCLASS:
16930 case CORINFO_HELP_ISINSTANCEOFANY:
16932 // Fetch the class handle from the helper call arglist
16933 GenTreeArgList* args = call->gtCallArgs;
16934 GenTree* typeArg = args->Current();
16935 CORINFO_CLASS_HANDLE castHnd = gtGetHelperArgClassHandle(typeArg);
16937 // We generally assume the type being cast to is the best type
16938 // for the result, unless it is an interface type.
16940 // TODO-CQ: when we have default interface methods then
16941 // this might not be the best assumption. We could also
16942 // explore calling something like mergeClasses to identify
16943 // the more specific class. A similar issue arises when
16944 // typing the temp in impCastClassOrIsInstToTree, when we
16945 // expand the cast inline.
16946 if (castHnd != nullptr)
16948 DWORD attrs = info.compCompHnd->getClassAttribs(castHnd);
16950 if ((attrs & CORINFO_FLG_INTERFACE) != 0)
16956 // If we don't have a good estimate for the type we can use the
16957 // type from the value being cast instead.
16958 if (castHnd == nullptr)
16960 GenTree* valueArg = args->Rest()->Current();
16961 castHnd = gtGetClassHandle(valueArg, pIsExact, pIsNonNull);
16964 // We don't know at jit time if the cast will succeed or fail, but if it
16965 // fails at runtime then an exception is thrown for cast helpers, or the
16966 // result is set null for instance helpers.
16968 // So it safe to claim the result has the cast type.
16969 // Note we don't know for sure that it is exactly this type.
16970 if (castHnd != nullptr)
16972 objClass = castHnd;
16985 //------------------------------------------------------------------------
16986 // gtGetArrayElementClassHandle: find class handle for elements of an array
16990 // array -- array to find handle for
16993 // nullptr if element class handle is unknown, otherwise the class handle.
16995 CORINFO_CLASS_HANDLE Compiler::gtGetArrayElementClassHandle(GenTree* array)
16997 bool isArrayExact = false;
16998 bool isArrayNonNull = false;
16999 CORINFO_CLASS_HANDLE arrayClassHnd = gtGetClassHandle(array, &isArrayExact, &isArrayNonNull);
17001 if (arrayClassHnd != nullptr)
17003 // We know the class of the reference
17004 DWORD attribs = info.compCompHnd->getClassAttribs(arrayClassHnd);
17006 if ((attribs & CORINFO_FLG_ARRAY) != 0)
17008 // We know for sure it is an array
17009 CORINFO_CLASS_HANDLE elemClassHnd = nullptr;
17010 CorInfoType arrayElemType = info.compCompHnd->getChildType(arrayClassHnd, &elemClassHnd);
17012 if (arrayElemType == CORINFO_TYPE_CLASS)
17014 // We know it is an array of ref types
17015 return elemClassHnd;
17023 //------------------------------------------------------------------------
17024 // gtGetFieldClassHandle: find class handle for a field
17027 // fieldHnd - field handle for field in question
17028 // pIsExact - [OUT] true if type is known exactly
17029 // pIsNonNull - [OUT] true if field value is not null
17032 // nullptr if helper call result is not a ref class, or the class handle
17033 // is unknown, otherwise the class handle.
17035 // May examine runtime state of static field instances.
17037 CORINFO_CLASS_HANDLE Compiler::gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldHnd, bool* pIsExact, bool* pIsNonNull)
17039 CORINFO_CLASS_HANDLE fieldClass = nullptr;
17040 CorInfoType fieldCorType = info.compCompHnd->getFieldType(fieldHnd, &fieldClass);
17042 if (fieldCorType == CORINFO_TYPE_CLASS)
17044 // Optionally, look at the actual type of the field's value
17045 bool queryForCurrentClass = true;
17046 INDEBUG(queryForCurrentClass = (JitConfig.JitQueryCurrentStaticFieldClass() > 0););
17048 if (queryForCurrentClass)
17052 const char* fieldClassName = nullptr;
17053 const char* fieldName = eeGetFieldName(fieldHnd, &fieldClassName);
17054 JITDUMP("Querying runtime about current class of field %s.%s (declared as %s)\n", fieldClassName, fieldName,
17055 eeGetClassName(fieldClass));
17058 // Is this a fully initialized init-only static field?
17060 // Note we're not asking for speculative results here, yet.
17061 CORINFO_CLASS_HANDLE currentClass = info.compCompHnd->getStaticFieldCurrentClass(fieldHnd);
17063 if (currentClass != NO_CLASS_HANDLE)
17065 // Yes! We know the class exactly and can rely on this to always be true.
17066 fieldClass = currentClass;
17068 *pIsNonNull = true;
17069 JITDUMP("Runtime reports field is init-only and initialized and has class %s\n",
17070 eeGetClassName(fieldClass));
17074 JITDUMP("Field's current class not available\n");
17082 //------------------------------------------------------------------------
17083 // gtIsGCStaticBaseHelperCall: true if tree is fetching the gc static base
17084 // for a subsequent static field access
17087 // tree - tree to consider
17090 // true if the tree is a suitable helper call
17093 // Excludes R2R helpers as they specify the target field in a way
17094 // that is opaque to the jit.
17096 bool Compiler::gtIsStaticGCBaseHelperCall(GenTree* tree)
17098 if (tree->OperGet() != GT_CALL)
17103 GenTreeCall* call = tree->AsCall();
17105 if (call->gtCallType != CT_HELPER)
17110 const CorInfoHelpFunc helper = eeGetHelperNum(call->gtCallMethHnd);
17114 // We are looking for a REF type so only need to check for the GC base helpers
17115 case CORINFO_HELP_GETGENERICS_GCSTATIC_BASE:
17116 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE:
17117 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR:
17118 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS:
17119 case CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE:
17120 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE:
17121 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR:
17122 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS:
17131 void GenTree::ParseArrayAddress(
17132 Compiler* comp, ArrayInfo* arrayInfo, GenTree** pArr, ValueNum* pInxVN, FieldSeqNode** pFldSeq)
17135 ValueNum inxVN = ValueNumStore::NoVN;
17136 target_ssize_t offset = 0;
17137 FieldSeqNode* fldSeq = nullptr;
17139 ParseArrayAddressWork(comp, 1, pArr, &inxVN, &offset, &fldSeq);
17141 // If we didn't find an array reference (perhaps it is the constant null?) we will give up.
17142 if (*pArr == nullptr)
17147 // OK, new we have to figure out if any part of the "offset" is a constant contribution to the index.
17148 // First, sum the offsets of any fields in fldSeq.
17149 unsigned fieldOffsets = 0;
17150 FieldSeqNode* fldSeqIter = fldSeq;
17151 // Also, find the first non-pseudo field...
17152 assert(*pFldSeq == nullptr);
17153 while (fldSeqIter != nullptr)
17155 if (fldSeqIter == FieldSeqStore::NotAField())
17157 // TODO-Review: A NotAField here indicates a failure to properly maintain the field sequence
17158 // See test case self_host_tests_x86\jit\regression\CLR-x86-JIT\v1-m12-beta2\ b70992\ b70992.exe
17159 // Safest thing to do here is to drop back to MinOpts
17160 CLANG_FORMAT_COMMENT_ANCHOR;
17163 if (comp->opts.optRepeat)
17165 // We don't guarantee preserving these annotations through the entire optimizer, so
17166 // just conservatively return null if under optRepeat.
17171 noway_assert(!"fldSeqIter is NotAField() in ParseArrayAddress");
17174 if (!FieldSeqStore::IsPseudoField(fldSeqIter->m_fieldHnd))
17176 if (*pFldSeq == nullptr)
17178 *pFldSeq = fldSeqIter;
17180 CORINFO_CLASS_HANDLE fldCls = nullptr;
17181 noway_assert(fldSeqIter->m_fieldHnd != nullptr);
17182 CorInfoType cit = comp->info.compCompHnd->getFieldType(fldSeqIter->m_fieldHnd, &fldCls);
17183 fieldOffsets += comp->compGetTypeSize(cit, fldCls);
17185 fldSeqIter = fldSeqIter->m_next;
17188 // Is there some portion of the "offset" beyond the first-elem offset and the struct field suffix we just computed?
17189 if (!FitsIn<target_ssize_t>(fieldOffsets + arrayInfo->m_elemOffset) ||
17190 !FitsIn<target_ssize_t>(arrayInfo->m_elemSize))
17192 // This seems unlikely, but no harm in being safe...
17193 *pInxVN = comp->GetValueNumStore()->VNForExpr(nullptr, TYP_INT);
17197 target_ssize_t offsetAccountedFor = static_cast<target_ssize_t>(fieldOffsets + arrayInfo->m_elemOffset);
17198 target_ssize_t elemSize = static_cast<target_ssize_t>(arrayInfo->m_elemSize);
17200 target_ssize_t constIndOffset = offset - offsetAccountedFor;
17201 // This should be divisible by the element size...
17202 assert((constIndOffset % elemSize) == 0);
17203 target_ssize_t constInd = constIndOffset / elemSize;
17205 ValueNumStore* vnStore = comp->GetValueNumStore();
17207 if (inxVN == ValueNumStore::NoVN)
17209 // Must be a constant index.
17210 *pInxVN = vnStore->VNForPtrSizeIntCon(constInd);
17215 // Perform ((inxVN / elemSizeVN) + vnForConstInd)
17218 // The value associated with the index value number (inxVN) is the offset into the array,
17219 // which has been scaled by element size. We need to recover the array index from that offset
17220 if (vnStore->IsVNConstant(inxVN))
17222 target_ssize_t index = vnStore->CoercedConstantValue<target_ssize_t>(inxVN);
17223 noway_assert(elemSize > 0 && ((index % elemSize) == 0));
17224 *pInxVN = vnStore->VNForPtrSizeIntCon((index / elemSize) + constInd);
17228 bool canFoldDiv = false;
17230 // If the index VN is a MUL by elemSize, see if we can eliminate it instead of adding
17231 // the division by elemSize.
17233 if (vnStore->GetVNFunc(inxVN, &funcApp) && funcApp.m_func == (VNFunc)GT_MUL)
17235 ValueNum vnForElemSize = vnStore->VNForLongCon(elemSize);
17237 // One of the multiply operand is elemSize, so the resulting
17238 // index VN should simply be the other operand.
17239 if (funcApp.m_args[1] == vnForElemSize)
17241 *pInxVN = funcApp.m_args[0];
17244 else if (funcApp.m_args[0] == vnForElemSize)
17246 *pInxVN = funcApp.m_args[1];
17251 // Perform ((inxVN / elemSizeVN) + vnForConstInd)
17254 ValueNum vnForElemSize = vnStore->VNForPtrSizeIntCon(elemSize);
17255 ValueNum vnForScaledInx =
17256 vnStore->VNForFunc(TYP_I_IMPL, GetVNFuncForOper(GT_DIV, VOK_Default), inxVN, vnForElemSize);
17257 *pInxVN = vnForScaledInx;
17262 ValueNum vnForConstInd = comp->GetValueNumStore()->VNForPtrSizeIntCon(constInd);
17263 VNFunc vnFunc = GetVNFuncForOper(GT_ADD, VOK_Default);
17265 *pInxVN = comp->GetValueNumStore()->VNForFunc(TYP_I_IMPL, vnFunc, *pInxVN, vnForConstInd);
17271 void GenTree::ParseArrayAddressWork(Compiler* comp,
17272 target_ssize_t inputMul,
17275 target_ssize_t* pOffset,
17276 FieldSeqNode** pFldSeq)
17278 if (TypeGet() == TYP_REF)
17280 // This must be the array pointer.
17282 assert(inputMul == 1); // Can't multiply the array pointer by anything.
17289 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, gtIntCon.gtFieldSeq);
17290 assert(!gtIntCon.ImmedValNeedsReloc(comp));
17291 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntCon::gtIconVal had target_ssize_t
17293 *pOffset += (inputMul * (target_ssize_t)(gtIntCon.gtIconVal));
17298 gtOp.gtOp1->ParseArrayAddressWork(comp, inputMul, pArr, pInxVN, pOffset, pFldSeq);
17299 if (OperGet() == GT_SUB)
17301 inputMul = -inputMul;
17303 gtOp.gtOp2->ParseArrayAddressWork(comp, inputMul, pArr, pInxVN, pOffset, pFldSeq);
17308 // If one op is a constant, continue parsing down.
17309 target_ssize_t subMul = 0;
17310 GenTree* nonConst = nullptr;
17311 if (gtOp.gtOp1->IsCnsIntOrI())
17313 // If the other arg is an int constant, and is a "not-a-field", choose
17314 // that as the multiplier, thus preserving constant index offsets...
17315 if (gtOp.gtOp2->OperGet() == GT_CNS_INT &&
17316 gtOp.gtOp2->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField())
17318 assert(!gtOp.gtOp2->gtIntCon.ImmedValNeedsReloc(comp));
17319 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntConCommon::gtIconVal had
17320 // target_ssize_t type.
17321 subMul = (target_ssize_t)gtOp.gtOp2->gtIntConCommon.IconValue();
17322 nonConst = gtOp.gtOp1;
17326 assert(!gtOp.gtOp1->gtIntCon.ImmedValNeedsReloc(comp));
17327 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntConCommon::gtIconVal had
17328 // target_ssize_t type.
17329 subMul = (target_ssize_t)gtOp.gtOp1->gtIntConCommon.IconValue();
17330 nonConst = gtOp.gtOp2;
17333 else if (gtOp.gtOp2->IsCnsIntOrI())
17335 assert(!gtOp.gtOp2->gtIntCon.ImmedValNeedsReloc(comp));
17336 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntConCommon::gtIconVal had
17337 // target_ssize_t type.
17338 subMul = (target_ssize_t)gtOp.gtOp2->gtIntConCommon.IconValue();
17339 nonConst = gtOp.gtOp1;
17341 if (nonConst != nullptr)
17343 nonConst->ParseArrayAddressWork(comp, inputMul * subMul, pArr, pInxVN, pOffset, pFldSeq);
17346 // Otherwise, exit the switch, treat as a contribution to the index.
17351 // If one op is a constant, continue parsing down.
17352 if (gtOp.gtOp2->IsCnsIntOrI())
17354 assert(!gtOp.gtOp2->gtIntCon.ImmedValNeedsReloc(comp));
17355 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntCon::gtIconVal had target_ssize_t
17357 target_ssize_t subMul = target_ssize_t{1} << (target_ssize_t)gtOp.gtOp2->gtIntConCommon.IconValue();
17358 gtOp.gtOp1->ParseArrayAddressWork(comp, inputMul * subMul, pArr, pInxVN, pOffset, pFldSeq);
17361 // Otherwise, exit the switch, treat as a contribution to the index.
17365 // We don't care about exceptions for this purpose.
17366 if ((gtOp.gtOp1->OperGet() == GT_ARR_BOUNDS_CHECK) || gtOp.gtOp1->IsNothingNode())
17368 gtOp.gtOp2->ParseArrayAddressWork(comp, inputMul, pArr, pInxVN, pOffset, pFldSeq);
17376 // If we didn't return above, must be a contribution to the non-constant part of the index VN.
17377 ValueNum vn = comp->GetValueNumStore()->VNLiberalNormalValue(gtVNPair);
17380 ValueNum mulVN = comp->GetValueNumStore()->VNForLongCon(inputMul);
17381 vn = comp->GetValueNumStore()->VNForFunc(TypeGet(), GetVNFuncForOper(GT_MUL, VOK_Default), mulVN, vn);
17383 if (*pInxVN == ValueNumStore::NoVN)
17390 comp->GetValueNumStore()->VNForFunc(TypeGet(), GetVNFuncForOper(GT_ADD, VOK_Default), *pInxVN, vn);
17395 bool GenTree::ParseArrayElemForm(Compiler* comp, ArrayInfo* arrayInfo, FieldSeqNode** pFldSeq)
17399 if (gtFlags & GTF_IND_ARR_INDEX)
17401 bool b = comp->GetArrayInfoMap()->Lookup(this, arrayInfo);
17407 GenTree* addr = AsIndir()->Addr();
17408 return addr->ParseArrayElemAddrForm(comp, arrayInfo, pFldSeq);
17416 bool GenTree::ParseArrayElemAddrForm(Compiler* comp, ArrayInfo* arrayInfo, FieldSeqNode** pFldSeq)
17422 GenTree* arrAddr = nullptr;
17423 GenTree* offset = nullptr;
17424 if (gtOp.gtOp1->TypeGet() == TYP_BYREF)
17426 arrAddr = gtOp.gtOp1;
17427 offset = gtOp.gtOp2;
17429 else if (gtOp.gtOp2->TypeGet() == TYP_BYREF)
17431 arrAddr = gtOp.gtOp2;
17432 offset = gtOp.gtOp1;
17438 if (!offset->ParseOffsetForm(comp, pFldSeq))
17442 return arrAddr->ParseArrayElemAddrForm(comp, arrayInfo, pFldSeq);
17447 GenTree* addrArg = gtOp.gtOp1;
17448 if (addrArg->OperGet() != GT_IND)
17454 // The "Addr" node might be annotated with a zero-offset field sequence.
17455 FieldSeqNode* zeroOffsetFldSeq = nullptr;
17456 if (comp->GetZeroOffsetFieldMap()->Lookup(this, &zeroOffsetFldSeq))
17458 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, zeroOffsetFldSeq);
17460 return addrArg->ParseArrayElemForm(comp, arrayInfo, pFldSeq);
17469 bool GenTree::ParseOffsetForm(Compiler* comp, FieldSeqNode** pFldSeq)
17475 GenTreeIntCon* icon = AsIntCon();
17476 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, icon->gtFieldSeq);
17481 if (!gtOp.gtOp1->ParseOffsetForm(comp, pFldSeq))
17485 return gtOp.gtOp2->ParseOffsetForm(comp, pFldSeq);
17492 void GenTree::LabelIndex(Compiler* comp, bool isConst)
17497 // If we got here, this is a contribution to the constant part of the index.
17500 gtIntCon.gtFieldSeq =
17501 comp->GetFieldSeqStore()->CreateSingleton(FieldSeqStore::ConstantIndexPseudoField);
17506 gtFlags |= GTF_VAR_ARR_INDEX;
17511 gtOp.gtOp1->LabelIndex(comp, isConst);
17512 gtOp.gtOp2->LabelIndex(comp, isConst);
17516 gtOp.gtOp1->LabelIndex(comp, isConst);
17519 case GT_ARR_LENGTH:
17520 gtFlags |= GTF_ARRLEN_ARR_IDX;
17524 // For all other operators, peel off one constant; and then label the other if it's also a constant.
17525 if (OperIsArithmetic() || OperIsCompare())
17527 if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
17529 gtOp.gtOp1->LabelIndex(comp, isConst);
17532 else if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
17534 gtOp.gtOp2->LabelIndex(comp, isConst);
17537 // Otherwise continue downward on both, labeling vars.
17538 gtOp.gtOp1->LabelIndex(comp, false);
17539 gtOp.gtOp2->LabelIndex(comp, false);
17545 // Note that the value of the below field doesn't matter; it exists only to provide a distinguished address.
17548 FieldSeqNode FieldSeqStore::s_notAField(nullptr, nullptr);
17550 // FieldSeqStore methods.
17551 FieldSeqStore::FieldSeqStore(CompAllocator alloc) : m_alloc(alloc), m_canonMap(new (alloc) FieldSeqNodeCanonMap(alloc))
17555 FieldSeqNode* FieldSeqStore::CreateSingleton(CORINFO_FIELD_HANDLE fieldHnd)
17557 FieldSeqNode fsn(fieldHnd, nullptr);
17558 FieldSeqNode* res = nullptr;
17559 if (m_canonMap->Lookup(fsn, &res))
17565 res = m_alloc.allocate<FieldSeqNode>(1);
17567 m_canonMap->Set(fsn, res);
17572 FieldSeqNode* FieldSeqStore::Append(FieldSeqNode* a, FieldSeqNode* b)
17578 else if (a == NotAField())
17580 return NotAField();
17582 else if (b == nullptr)
17586 else if (b == NotAField())
17588 return NotAField();
17589 // Extremely special case for ConstantIndex pseudo-fields -- appending consecutive such
17590 // together collapse to one.
17592 else if (a->m_next == nullptr && a->m_fieldHnd == ConstantIndexPseudoField &&
17593 b->m_fieldHnd == ConstantIndexPseudoField)
17599 FieldSeqNode* tmp = Append(a->m_next, b);
17600 FieldSeqNode fsn(a->m_fieldHnd, tmp);
17601 FieldSeqNode* res = nullptr;
17602 if (m_canonMap->Lookup(fsn, &res))
17608 res = m_alloc.allocate<FieldSeqNode>(1);
17610 m_canonMap->Set(fsn, res);
17617 int FieldSeqStore::FirstElemPseudoFieldStruct;
17618 int FieldSeqStore::ConstantIndexPseudoFieldStruct;
17620 CORINFO_FIELD_HANDLE FieldSeqStore::FirstElemPseudoField =
17621 (CORINFO_FIELD_HANDLE)&FieldSeqStore::FirstElemPseudoFieldStruct;
17622 CORINFO_FIELD_HANDLE FieldSeqStore::ConstantIndexPseudoField =
17623 (CORINFO_FIELD_HANDLE)&FieldSeqStore::ConstantIndexPseudoFieldStruct;
17625 bool FieldSeqNode::IsFirstElemFieldSeq()
17627 // this must be non-null per ISO C++
17628 return m_fieldHnd == FieldSeqStore::FirstElemPseudoField;
17631 bool FieldSeqNode::IsConstantIndexFieldSeq()
17633 // this must be non-null per ISO C++
17634 return m_fieldHnd == FieldSeqStore::ConstantIndexPseudoField;
17637 bool FieldSeqNode::IsPseudoField()
17639 if (this == nullptr)
17643 return m_fieldHnd == FieldSeqStore::FirstElemPseudoField || m_fieldHnd == FieldSeqStore::ConstantIndexPseudoField;
17646 #ifdef FEATURE_SIMD
17647 GenTreeSIMD* Compiler::gtNewSIMDNode(
17648 var_types type, GenTree* op1, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size)
17650 assert(op1 != nullptr);
17651 SetOpLclRelatedToSIMDIntrinsic(op1);
17653 return new (this, GT_SIMD) GenTreeSIMD(type, op1, simdIntrinsicID, baseType, size);
17656 GenTreeSIMD* Compiler::gtNewSIMDNode(
17657 var_types type, GenTree* op1, GenTree* op2, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size)
17659 assert(op1 != nullptr);
17660 SetOpLclRelatedToSIMDIntrinsic(op1);
17661 SetOpLclRelatedToSIMDIntrinsic(op2);
17663 return new (this, GT_SIMD) GenTreeSIMD(type, op1, op2, simdIntrinsicID, baseType, size);
17666 //-------------------------------------------------------------------
17667 // SetOpLclRelatedToSIMDIntrinsic: Determine if the tree has a local var that needs to be set
17668 // as used by a SIMD intrinsic, and if so, set that local var appropriately.
17671 // op - The tree, to be an operand of a new GT_SIMD node, to check.
17673 void Compiler::SetOpLclRelatedToSIMDIntrinsic(GenTree* op)
17677 if (op->OperIsLocal())
17679 setLclRelatedToSIMDIntrinsic(op);
17681 else if ((op->OperGet() == GT_OBJ) && (op->gtOp.gtOp1->OperGet() == GT_ADDR) &&
17682 op->gtOp.gtOp1->gtOp.gtOp1->OperIsLocal())
17684 setLclRelatedToSIMDIntrinsic(op->gtOp.gtOp1->gtOp.gtOp1);
17689 bool GenTree::isCommutativeSIMDIntrinsic()
17691 assert(gtOper == GT_SIMD);
17692 switch (AsSIMD()->gtSIMDIntrinsicID)
17694 case SIMDIntrinsicAdd:
17695 case SIMDIntrinsicBitwiseAnd:
17696 case SIMDIntrinsicBitwiseOr:
17697 case SIMDIntrinsicBitwiseXor:
17698 case SIMDIntrinsicEqual:
17699 case SIMDIntrinsicMax:
17700 case SIMDIntrinsicMin:
17701 case SIMDIntrinsicMul:
17702 case SIMDIntrinsicOpEquality:
17703 case SIMDIntrinsicOpInEquality:
17709 #endif // FEATURE_SIMD
17711 #ifdef FEATURE_HW_INTRINSICS
17712 bool GenTree::isCommutativeHWIntrinsic() const
17714 assert(gtOper == GT_HWIntrinsic);
17716 #ifdef _TARGET_XARCH_
17717 return HWIntrinsicInfo::IsCommutative(AsHWIntrinsic()->gtHWIntrinsicId);
17720 #endif // _TARGET_XARCH_
17723 bool GenTree::isContainableHWIntrinsic() const
17725 assert(gtOper == GT_HWIntrinsic);
17727 #ifdef _TARGET_XARCH_
17728 switch (AsHWIntrinsic()->gtHWIntrinsicId)
17730 case NI_SSE_LoadAlignedVector128:
17731 case NI_SSE_LoadScalarVector128:
17732 case NI_SSE_LoadVector128:
17733 case NI_SSE2_LoadAlignedVector128:
17734 case NI_SSE2_LoadScalarVector128:
17735 case NI_SSE2_LoadVector128:
17736 case NI_AVX_LoadAlignedVector256:
17737 case NI_AVX_LoadVector256:
17749 #endif // _TARGET_XARCH_
17752 bool GenTree::isRMWHWIntrinsic(Compiler* comp)
17754 assert(gtOper == GT_HWIntrinsic);
17755 assert(comp != nullptr);
17757 #ifdef _TARGET_XARCH_
17758 if (!comp->canUseVexEncoding())
17760 return HWIntrinsicInfo::HasRMWSemantics(AsHWIntrinsic()->gtHWIntrinsicId);
17763 switch (AsHWIntrinsic()->gtHWIntrinsicId)
17765 // TODO-XArch-Cleanup: Move this switch block to be table driven.
17767 case NI_SSE42_Crc32:
17768 case NI_SSE42_X64_Crc32:
17769 case NI_FMA_MultiplyAdd:
17770 case NI_FMA_MultiplyAddNegated:
17771 case NI_FMA_MultiplyAddNegatedScalar:
17772 case NI_FMA_MultiplyAddScalar:
17773 case NI_FMA_MultiplyAddSubtract:
17774 case NI_FMA_MultiplySubtract:
17775 case NI_FMA_MultiplySubtractAdd:
17776 case NI_FMA_MultiplySubtractNegated:
17777 case NI_FMA_MultiplySubtractNegatedScalar:
17778 case NI_FMA_MultiplySubtractScalar:
17790 #endif // _TARGET_XARCH_
17793 GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type,
17794 NamedIntrinsic hwIntrinsicID,
17795 var_types baseType,
17798 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, hwIntrinsicID, baseType, size);
17801 GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(
17802 var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned simdSize)
17804 SetOpLclRelatedToSIMDIntrinsic(op1);
17806 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, hwIntrinsicID, baseType, simdSize);
17809 GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(
17810 var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned simdSize)
17812 SetOpLclRelatedToSIMDIntrinsic(op1);
17813 SetOpLclRelatedToSIMDIntrinsic(op2);
17815 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, op2, hwIntrinsicID, baseType, simdSize);
17818 GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type,
17822 NamedIntrinsic hwIntrinsicID,
17823 var_types baseType,
17826 SetOpLclRelatedToSIMDIntrinsic(op1);
17827 SetOpLclRelatedToSIMDIntrinsic(op2);
17828 SetOpLclRelatedToSIMDIntrinsic(op3);
17830 return new (this, GT_HWIntrinsic)
17831 GenTreeHWIntrinsic(type, gtNewArgList(op1, op2, op3), hwIntrinsicID, baseType, size);
17834 GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type,
17839 NamedIntrinsic hwIntrinsicID,
17840 var_types baseType,
17843 SetOpLclRelatedToSIMDIntrinsic(op1);
17844 SetOpLclRelatedToSIMDIntrinsic(op2);
17845 SetOpLclRelatedToSIMDIntrinsic(op3);
17846 SetOpLclRelatedToSIMDIntrinsic(op4);
17848 return new (this, GT_HWIntrinsic)
17849 GenTreeHWIntrinsic(type, gtNewArgList(op1, op2, op3, op4), hwIntrinsicID, baseType, size);
17852 GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID)
17854 SetOpLclRelatedToSIMDIntrinsic(op1);
17856 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, hwIntrinsicID, TYP_UNKNOWN, 0);
17859 GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type,
17862 NamedIntrinsic hwIntrinsicID)
17864 SetOpLclRelatedToSIMDIntrinsic(op1);
17865 SetOpLclRelatedToSIMDIntrinsic(op2);
17867 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, op2, hwIntrinsicID, TYP_UNKNOWN, 0);
17870 GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(
17871 var_types type, GenTree* op1, GenTree* op2, GenTree* op3, NamedIntrinsic hwIntrinsicID)
17873 SetOpLclRelatedToSIMDIntrinsic(op1);
17874 SetOpLclRelatedToSIMDIntrinsic(op2);
17875 SetOpLclRelatedToSIMDIntrinsic(op3);
17877 return new (this, GT_HWIntrinsic)
17878 GenTreeHWIntrinsic(type, gtNewArgList(op1, op2, op3), hwIntrinsicID, TYP_UNKNOWN, 0);
17881 //---------------------------------------------------------------------------------------
17882 // gtNewMustThrowException:
17883 // create a throw node (calling into JIT helper) that must be thrown.
17884 // The result would be a comma node: COMMA(jithelperthrow(void), x) where x's type should be specified.
17887 // helper - JIT helper ID
17888 // type - return type of the node
17891 // pointer to the throw node
17893 GenTree* Compiler::gtNewMustThrowException(unsigned helper, var_types type, CORINFO_CLASS_HANDLE clsHnd)
17895 GenTreeCall* node = gtNewHelperCallNode(helper, TYP_VOID);
17896 node->gtCallMoreFlags |= GTF_CALL_M_DOES_NOT_RETURN;
17897 if (type != TYP_VOID)
17899 unsigned dummyTemp = lvaGrabTemp(true DEBUGARG("dummy temp of must thrown exception"));
17900 if (type == TYP_STRUCT)
17902 lvaSetStruct(dummyTemp, clsHnd, false);
17903 type = lvaTable[dummyTemp].lvType; // struct type is normalized
17907 lvaTable[dummyTemp].lvType = type;
17909 GenTree* dummyNode = gtNewLclvNode(dummyTemp, type);
17910 return gtNewOperNode(GT_COMMA, type, node, dummyNode);
17915 // Returns true for the HW Instrinsic instructions that have MemoryLoad semantics, false otherwise
17916 bool GenTreeHWIntrinsic::OperIsMemoryLoad()
17918 #ifdef _TARGET_XARCH_
17919 // Some xarch instructions have MemoryLoad sematics
17920 HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(gtHWIntrinsicId);
17921 if (category == HW_Category_MemoryLoad)
17925 else if (HWIntrinsicInfo::MaybeMemoryLoad(gtHWIntrinsicId))
17927 // Some AVX intrinsic (without HW_Category_MemoryLoad) also have MemoryLoad semantics
17928 if (category == HW_Category_SIMDScalar)
17930 // Avx2.BroadcastScalarToVector128/256 have vector and pointer overloads both, e.g.,
17931 // Vector128<byte> BroadcastScalarToVector128(Vector128<byte> value)
17932 // Vector128<byte> BroadcastScalarToVector128(byte* source)
17933 // So, we need to check the argument's type is memory-reference (TYP_I_IMPL) or not
17934 assert(HWIntrinsicInfo::lookupNumArgs(this) == 1);
17935 return (gtHWIntrinsicId == NI_AVX2_BroadcastScalarToVector128 ||
17936 gtHWIntrinsicId == NI_AVX2_BroadcastScalarToVector256) &&
17937 gtOp.gtOp1->TypeGet() == TYP_I_IMPL;
17939 else if (category == HW_Category_IMM)
17941 // Do we have less than 3 operands?
17942 if (HWIntrinsicInfo::lookupNumArgs(this) < 3)
17946 else // We have 3 or more operands/args
17948 // All the Avx2.Gather* are "load" instructions
17949 if (HWIntrinsicInfo::isAVX2GatherIntrinsic(gtHWIntrinsicId))
17954 GenTreeArgList* argList = gtOp.gtOp1->AsArgList();
17956 // Avx/Avx2.InsertVector128 have vector and pointer overloads both, e.g.,
17957 // Vector256<sbyte> InsertVector128(Vector256<sbyte> value, Vector128<sbyte> data, byte index)
17958 // Vector256<sbyte> InsertVector128(Vector256<sbyte> value, sbyte* address, byte index)
17959 // So, we need to check the second argument's type is memory-reference (TYP_I_IMPL) or not
17960 if ((gtHWIntrinsicId == NI_AVX_InsertVector128 || gtHWIntrinsicId == NI_AVX2_InsertVector128) &&
17961 (argList->Rest()->Current()->TypeGet() == TYP_I_IMPL)) // Is the type of the second arg TYP_I_IMPL?
17963 // This is Avx/Avx2.InsertVector128
17969 #endif // _TARGET_XARCH_
17973 // Returns true for the HW Instrinsic instructions that have MemoryStore semantics, false otherwise
17974 bool GenTreeHWIntrinsic::OperIsMemoryStore()
17976 #ifdef _TARGET_XARCH_
17977 // Some xarch instructions have MemoryStore sematics
17978 HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(gtHWIntrinsicId);
17979 if (category == HW_Category_MemoryStore)
17983 else if (HWIntrinsicInfo::MaybeMemoryStore(gtHWIntrinsicId) &&
17984 (category == HW_Category_IMM || category == HW_Category_Scalar))
17986 // Some AVX intrinsic (without HW_Category_MemoryStore) also have MemoryStore semantics
17988 // Avx/Avx2.InsertVector128 have vector and pointer overloads both, e.g.,
17989 // Vector128<sbyte> ExtractVector128(Vector256<sbyte> value, byte index)
17990 // void ExtractVector128(sbyte* address, Vector256<sbyte> value, byte index)
17991 // Bmi2/Bmi2.X64.MultiplyNoFlags may return the lower half result by a out argument
17992 // unsafe ulong MultiplyNoFlags(ulong left, ulong right, ulong* low)
17994 // So, the 3-argument form is MemoryStore
17995 if (HWIntrinsicInfo::lookupNumArgs(this) == 3)
17997 switch (gtHWIntrinsicId)
17999 case NI_AVX_ExtractVector128:
18000 case NI_AVX2_ExtractVector128:
18001 case NI_BMI2_MultiplyNoFlags:
18002 case NI_BMI2_X64_MultiplyNoFlags:
18009 #endif // _TARGET_XARCH_
18013 // Returns true for the HW Instrinsic instructions that have MemoryLoad semantics, false otherwise
18014 bool GenTreeHWIntrinsic::OperIsMemoryLoadOrStore()
18016 #ifdef _TARGET_XARCH_
18017 return OperIsMemoryLoad() || OperIsMemoryStore();
18018 #endif // _TARGET_XARCH_
18022 #endif // FEATURE_HW_INTRINSICS
18024 //---------------------------------------------------------------------------------------
18025 // InitializeStructReturnType:
18026 // Initialize the Return Type Descriptor for a method that returns a struct type
18029 // comp - Compiler Instance
18030 // retClsHnd - VM handle to the struct type returned by the method
18035 void ReturnTypeDesc::InitializeStructReturnType(Compiler* comp, CORINFO_CLASS_HANDLE retClsHnd)
18039 #if FEATURE_MULTIREG_RET
18041 assert(retClsHnd != NO_CLASS_HANDLE);
18042 unsigned structSize = comp->info.compCompHnd->getClassSize(retClsHnd);
18044 Compiler::structPassingKind howToReturnStruct;
18045 var_types returnType = comp->getReturnTypeForStruct(retClsHnd, &howToReturnStruct, structSize);
18047 switch (howToReturnStruct)
18049 case Compiler::SPK_EnclosingType:
18050 m_isEnclosingType = true;
18053 case Compiler::SPK_PrimitiveType:
18055 assert(returnType != TYP_UNKNOWN);
18056 assert(!varTypeIsStruct(returnType));
18057 m_regType[0] = returnType;
18061 case Compiler::SPK_ByValueAsHfa:
18063 assert(varTypeIsStruct(returnType));
18064 var_types hfaType = comp->GetHfaType(retClsHnd);
18066 // We should have an hfa struct type
18067 assert(varTypeIsFloating(hfaType));
18069 // Note that the retail build issues a warning about a potential divsion by zero without this Max function
18070 unsigned elemSize = Max((unsigned)1, EA_SIZE_IN_BYTES(emitActualTypeSize(hfaType)));
18072 // The size of this struct should be evenly divisible by elemSize
18073 assert((structSize % elemSize) == 0);
18075 unsigned hfaCount = (structSize / elemSize);
18076 for (unsigned i = 0; i < hfaCount; ++i)
18078 m_regType[i] = hfaType;
18081 if (comp->compFloatingPointUsed == false)
18083 comp->compFloatingPointUsed = true;
18088 case Compiler::SPK_ByValue:
18090 assert(varTypeIsStruct(returnType));
18092 #ifdef UNIX_AMD64_ABI
18094 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
18095 comp->eeGetSystemVAmd64PassStructInRegisterDescriptor(retClsHnd, &structDesc);
18097 assert(structDesc.passedInRegisters);
18098 for (int i = 0; i < structDesc.eightByteCount; i++)
18100 assert(i < MAX_RET_REG_COUNT);
18101 m_regType[i] = comp->GetEightByteType(structDesc, i);
18104 #elif defined(_TARGET_ARM64_)
18106 // a non-HFA struct returned using two registers
18108 assert((structSize > TARGET_POINTER_SIZE) && (structSize <= (2 * TARGET_POINTER_SIZE)));
18110 BYTE gcPtrs[2] = {TYPE_GC_NONE, TYPE_GC_NONE};
18111 comp->info.compCompHnd->getClassGClayout(retClsHnd, &gcPtrs[0]);
18112 for (unsigned i = 0; i < 2; ++i)
18114 m_regType[i] = comp->getJitGCType(gcPtrs[i]);
18117 #else // _TARGET_XXX_
18119 // This target needs support here!
18121 NYI("Unsupported TARGET returning a TYP_STRUCT in InitializeStructReturnType");
18123 #endif // UNIX_AMD64_ABI
18125 break; // for case SPK_ByValue
18128 case Compiler::SPK_ByReference:
18130 // We are returning using the return buffer argument
18131 // There are no return registers
18136 unreached(); // By the contract of getReturnTypeForStruct we should never get here.
18138 } // end of switch (howToReturnStruct)
18140 #endif // FEATURE_MULTIREG_RET
18147 //---------------------------------------------------------------------------------------
18148 // InitializeLongReturnType:
18149 // Initialize the Return Type Descriptor for a method that returns a TYP_LONG
18152 // comp - Compiler Instance
18157 void ReturnTypeDesc::InitializeLongReturnType(Compiler* comp)
18159 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
18161 // Setups up a ReturnTypeDesc for returning a long using two registers
18163 assert(MAX_RET_REG_COUNT >= 2);
18164 m_regType[0] = TYP_INT;
18165 m_regType[1] = TYP_INT;
18167 #else // not (_TARGET_X86_ or _TARGET_ARM_)
18169 m_regType[0] = TYP_LONG;
18171 #endif // _TARGET_X86_ or _TARGET_ARM_
18178 //-------------------------------------------------------------------
18179 // GetABIReturnReg: Return ith return register as per target ABI
18182 // idx - Index of the return register.
18183 // The first return register has an index of 0 and so on.
18186 // Returns ith return register as per target ABI.
18189 // x86 and ARM return long in multiple registers.
18190 // ARM and ARM64 return HFA struct in multiple registers.
18192 regNumber ReturnTypeDesc::GetABIReturnReg(unsigned idx)
18194 unsigned count = GetReturnRegCount();
18195 assert(idx < count);
18197 regNumber resultReg = REG_NA;
18199 #ifdef UNIX_AMD64_ABI
18200 var_types regType0 = GetReturnRegType(0);
18204 if (varTypeIsIntegralOrI(regType0))
18206 resultReg = REG_INTRET;
18210 noway_assert(varTypeIsFloating(regType0));
18211 resultReg = REG_FLOATRET;
18216 var_types regType1 = GetReturnRegType(1);
18218 if (varTypeIsIntegralOrI(regType1))
18220 if (varTypeIsIntegralOrI(regType0))
18222 resultReg = REG_INTRET_1;
18226 resultReg = REG_INTRET;
18231 noway_assert(varTypeIsFloating(regType1));
18233 if (varTypeIsFloating(regType0))
18235 resultReg = REG_FLOATRET_1;
18239 resultReg = REG_FLOATRET;
18244 #elif defined(_TARGET_X86_)
18248 resultReg = REG_LNGRET_LO;
18252 resultReg = REG_LNGRET_HI;
18255 #elif defined(_TARGET_ARM_)
18257 var_types regType = GetReturnRegType(idx);
18258 if (varTypeIsIntegralOrI(regType))
18260 // Ints are returned in one return register.
18261 // Longs are returned in two return registers.
18264 resultReg = REG_LNGRET_LO;
18268 resultReg = REG_LNGRET_HI;
18273 // Floats are returned in one return register (f0).
18274 // Doubles are returned in one return register (d0).
18275 // Structs are returned in four registers with HFAs.
18276 assert(idx < MAX_RET_REG_COUNT); // Up to 4 return registers for HFA's
18277 if (regType == TYP_DOUBLE)
18279 resultReg = (regNumber)((unsigned)(REG_FLOATRET) + idx * 2); // d0, d1, d2 or d3
18283 resultReg = (regNumber)((unsigned)(REG_FLOATRET) + idx); // f0, f1, f2 or f3
18287 #elif defined(_TARGET_ARM64_)
18289 var_types regType = GetReturnRegType(idx);
18290 if (varTypeIsIntegralOrI(regType))
18292 noway_assert(idx < 2); // Up to 2 return registers for 16-byte structs
18293 resultReg = (idx == 0) ? REG_INTRET : REG_INTRET_1; // X0 or X1
18297 noway_assert(idx < 4); // Up to 4 return registers for HFA's
18298 resultReg = (regNumber)((unsigned)(REG_FLOATRET) + idx); // V0, V1, V2 or V3
18301 #endif // TARGET_XXX
18303 assert(resultReg != REG_NA);
18307 //--------------------------------------------------------------------------------
18308 // GetABIReturnRegs: get the mask of return registers as per target arch ABI.
18314 // reg mask of return registers in which the return type is returned.
18317 // This routine can be used when the caller is not particular about the order
18318 // of return registers and wants to know the set of return registers.
18321 regMaskTP ReturnTypeDesc::GetABIReturnRegs()
18323 regMaskTP resultMask = RBM_NONE;
18325 unsigned count = GetReturnRegCount();
18326 for (unsigned i = 0; i < count; ++i)
18328 resultMask |= genRegMask(GetABIReturnReg(i));
18334 //------------------------------------------------------------------------
18335 // The following functions manage the gtRsvdRegs set of temporary registers
18336 // created by LSRA during code generation.
18338 //------------------------------------------------------------------------
18339 // AvailableTempRegCount: return the number of available temporary registers in the (optional) given set
18340 // (typically, RBM_ALLINT or RBM_ALLFLOAT).
18343 // mask - (optional) Check for available temporary registers only in this set.
18346 // Count of available temporary registers in given set.
18348 unsigned GenTree::AvailableTempRegCount(regMaskTP mask /* = (regMaskTP)-1 */) const
18350 return genCountBits(gtRsvdRegs & mask);
18353 //------------------------------------------------------------------------
18354 // GetSingleTempReg: There is expected to be exactly one available temporary register
18355 // in the given mask in the gtRsvdRegs set. Get that register. No future calls to get
18356 // a temporary register are expected. Removes the register from the set, but only in
18357 // DEBUG to avoid doing unnecessary work in non-DEBUG builds.
18360 // mask - (optional) Get an available temporary register only in this set.
18363 // Available temporary register in given mask.
18365 regNumber GenTree::GetSingleTempReg(regMaskTP mask /* = (regMaskTP)-1 */)
18367 regMaskTP availableSet = gtRsvdRegs & mask;
18368 assert(genCountBits(availableSet) == 1);
18369 regNumber tempReg = genRegNumFromMask(availableSet);
18370 INDEBUG(gtRsvdRegs &= ~availableSet;) // Remove the register from the set, so it can't be used again.
18374 //------------------------------------------------------------------------
18375 // ExtractTempReg: Find the lowest number temporary register from the gtRsvdRegs set
18376 // that is also in the optional given mask (typically, RBM_ALLINT or RBM_ALLFLOAT),
18377 // and return it. Remove this register from the temporary register set, so it won't
18378 // be returned again.
18381 // mask - (optional) Extract an available temporary register only in this set.
18384 // Available temporary register in given mask.
18386 regNumber GenTree::ExtractTempReg(regMaskTP mask /* = (regMaskTP)-1 */)
18388 regMaskTP availableSet = gtRsvdRegs & mask;
18389 assert(genCountBits(availableSet) >= 1);
18390 regMaskTP tempRegMask = genFindLowestBit(availableSet);
18391 gtRsvdRegs &= ~tempRegMask;
18392 return genRegNumFromMask(tempRegMask);