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
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];
202 // We allocate tree nodes in 2 different sizes:
203 // - TREE_NODE_SZ_SMALL for most nodes
204 // - TREE_NODE_SZ_LARGE for the few nodes (such as calls) that have
205 // more fields and take up a lot more space.
208 /* GT_COUNT'th oper is overloaded as 'undefined oper', so allocate storage for GT_COUNT'th oper also */
210 unsigned char GenTree::s_gtNodeSizes[GT_COUNT + 1];
212 #if NODEBASH_STATS || MEASURE_NODE_SIZE || COUNT_AST_OPERS
214 unsigned char GenTree::s_gtTrueSizes[GT_COUNT + 1]{
215 #define GTNODE(en, st, cm, ok) sizeof(st),
219 #endif // NODEBASH_STATS || MEASURE_NODE_SIZE || COUNT_AST_OPERS
222 LONG GenTree::s_gtNodeCounts[GT_COUNT + 1] = {0};
223 #endif // COUNT_AST_OPERS
226 void GenTree::InitNodeSize()
228 /* Set all sizes to 'small' first */
230 for (unsigned op = 0; op <= GT_COUNT; op++)
232 GenTree::s_gtNodeSizes[op] = TREE_NODE_SZ_SMALL;
235 // Now set all of the appropriate entries to 'large'
236 CLANG_FORMAT_COMMENT_ANCHOR;
239 #if defined(FEATURE_HFA) || defined(UNIX_AMD64_ABI)
240 // On ARM32, ARM64 and System V for struct returning
241 // there is code that does GT_ASG-tree.CopyObj call.
242 // CopyObj is a large node and the GT_ASG is small, which triggers an exception.
243 GenTree::s_gtNodeSizes[GT_ASG] = TREE_NODE_SZ_LARGE;
244 GenTree::s_gtNodeSizes[GT_RETURN] = TREE_NODE_SZ_LARGE;
245 #endif // defined(FEATURE_HFA) || defined(UNIX_AMD64_ABI)
247 GenTree::s_gtNodeSizes[GT_CALL] = TREE_NODE_SZ_LARGE;
248 GenTree::s_gtNodeSizes[GT_CAST] = TREE_NODE_SZ_LARGE;
249 GenTree::s_gtNodeSizes[GT_FTN_ADDR] = TREE_NODE_SZ_LARGE;
250 GenTree::s_gtNodeSizes[GT_BOX] = TREE_NODE_SZ_LARGE;
251 GenTree::s_gtNodeSizes[GT_INDEX] = TREE_NODE_SZ_LARGE;
252 GenTree::s_gtNodeSizes[GT_INDEX_ADDR] = TREE_NODE_SZ_LARGE;
253 GenTree::s_gtNodeSizes[GT_ARR_BOUNDS_CHECK] = TREE_NODE_SZ_LARGE;
255 GenTree::s_gtNodeSizes[GT_SIMD_CHK] = TREE_NODE_SZ_LARGE;
256 #endif // FEATURE_SIMD
257 #ifdef FEATURE_HW_INTRINSICS
258 GenTree::s_gtNodeSizes[GT_HW_INTRINSIC_CHK] = TREE_NODE_SZ_LARGE;
259 #endif // FEATURE_HW_INTRINSICS
261 GenTree::s_gtNodeSizes[GT_ARR_ELEM] = TREE_NODE_SZ_LARGE;
262 GenTree::s_gtNodeSizes[GT_ARR_INDEX] = TREE_NODE_SZ_LARGE;
263 GenTree::s_gtNodeSizes[GT_ARR_OFFSET] = TREE_NODE_SZ_LARGE;
264 GenTree::s_gtNodeSizes[GT_RET_EXPR] = TREE_NODE_SZ_LARGE;
265 GenTree::s_gtNodeSizes[GT_OBJ] = TREE_NODE_SZ_LARGE;
266 GenTree::s_gtNodeSizes[GT_FIELD] = TREE_NODE_SZ_LARGE;
267 GenTree::s_gtNodeSizes[GT_STMT] = TREE_NODE_SZ_LARGE;
268 GenTree::s_gtNodeSizes[GT_CMPXCHG] = TREE_NODE_SZ_LARGE;
269 GenTree::s_gtNodeSizes[GT_QMARK] = TREE_NODE_SZ_LARGE;
270 GenTree::s_gtNodeSizes[GT_LEA] = TREE_NODE_SZ_LARGE;
271 GenTree::s_gtNodeSizes[GT_STORE_OBJ] = TREE_NODE_SZ_LARGE;
272 GenTree::s_gtNodeSizes[GT_DYN_BLK] = TREE_NODE_SZ_LARGE;
273 GenTree::s_gtNodeSizes[GT_STORE_DYN_BLK] = TREE_NODE_SZ_LARGE;
274 GenTree::s_gtNodeSizes[GT_INTRINSIC] = TREE_NODE_SZ_LARGE;
275 GenTree::s_gtNodeSizes[GT_ALLOCOBJ] = TREE_NODE_SZ_LARGE;
276 #if USE_HELPERS_FOR_INT_DIV
277 GenTree::s_gtNodeSizes[GT_DIV] = TREE_NODE_SZ_LARGE;
278 GenTree::s_gtNodeSizes[GT_UDIV] = TREE_NODE_SZ_LARGE;
279 GenTree::s_gtNodeSizes[GT_MOD] = TREE_NODE_SZ_LARGE;
280 GenTree::s_gtNodeSizes[GT_UMOD] = TREE_NODE_SZ_LARGE;
282 #ifdef FEATURE_PUT_STRUCT_ARG_STK
283 // TODO-Throughput: This should not need to be a large node. The object info should be
284 // obtained from the child node.
285 GenTree::s_gtNodeSizes[GT_PUTARG_STK] = TREE_NODE_SZ_LARGE;
286 #if FEATURE_ARG_SPLIT
287 GenTree::s_gtNodeSizes[GT_PUTARG_SPLIT] = TREE_NODE_SZ_LARGE;
288 #endif // FEATURE_ARG_SPLIT
289 #endif // FEATURE_PUT_STRUCT_ARG_STK
291 assert(GenTree::s_gtNodeSizes[GT_RETURN] == GenTree::s_gtNodeSizes[GT_ASG]);
293 // This list of assertions should come to contain all GenTree subtypes that are declared
295 assert(sizeof(GenTreeLclFld) <= GenTree::s_gtNodeSizes[GT_LCL_FLD]);
296 assert(sizeof(GenTreeLclVar) <= GenTree::s_gtNodeSizes[GT_LCL_VAR]);
298 static_assert_no_msg(sizeof(GenTree) <= TREE_NODE_SZ_SMALL);
299 static_assert_no_msg(sizeof(GenTreeUnOp) <= TREE_NODE_SZ_SMALL);
300 static_assert_no_msg(sizeof(GenTreeOp) <= TREE_NODE_SZ_SMALL);
301 static_assert_no_msg(sizeof(GenTreeVal) <= TREE_NODE_SZ_SMALL);
302 static_assert_no_msg(sizeof(GenTreeIntConCommon) <= TREE_NODE_SZ_SMALL);
303 static_assert_no_msg(sizeof(GenTreePhysReg) <= TREE_NODE_SZ_SMALL);
304 static_assert_no_msg(sizeof(GenTreeIntCon) <= TREE_NODE_SZ_SMALL);
305 static_assert_no_msg(sizeof(GenTreeLngCon) <= TREE_NODE_SZ_SMALL);
306 static_assert_no_msg(sizeof(GenTreeDblCon) <= TREE_NODE_SZ_SMALL);
307 static_assert_no_msg(sizeof(GenTreeStrCon) <= TREE_NODE_SZ_SMALL);
308 static_assert_no_msg(sizeof(GenTreeLclVarCommon) <= TREE_NODE_SZ_SMALL);
309 static_assert_no_msg(sizeof(GenTreeLclVar) <= TREE_NODE_SZ_SMALL);
310 static_assert_no_msg(sizeof(GenTreeLclFld) <= TREE_NODE_SZ_SMALL);
311 static_assert_no_msg(sizeof(GenTreeCC) <= TREE_NODE_SZ_SMALL);
312 static_assert_no_msg(sizeof(GenTreeCast) <= TREE_NODE_SZ_LARGE); // *** large node
313 static_assert_no_msg(sizeof(GenTreeBox) <= TREE_NODE_SZ_LARGE); // *** large node
314 static_assert_no_msg(sizeof(GenTreeField) <= TREE_NODE_SZ_LARGE); // *** large node
315 static_assert_no_msg(sizeof(GenTreeArgList) <= TREE_NODE_SZ_SMALL);
316 static_assert_no_msg(sizeof(GenTreeFieldList) <= TREE_NODE_SZ_SMALL);
317 static_assert_no_msg(sizeof(GenTreeColon) <= TREE_NODE_SZ_SMALL);
318 static_assert_no_msg(sizeof(GenTreeCall) <= TREE_NODE_SZ_LARGE); // *** large node
319 static_assert_no_msg(sizeof(GenTreeCmpXchg) <= TREE_NODE_SZ_LARGE); // *** large node
320 static_assert_no_msg(sizeof(GenTreeFptrVal) <= TREE_NODE_SZ_LARGE); // *** large node
321 static_assert_no_msg(sizeof(GenTreeQmark) <= TREE_NODE_SZ_LARGE); // *** large node
322 static_assert_no_msg(sizeof(GenTreeIntrinsic) <= TREE_NODE_SZ_LARGE); // *** large node
323 static_assert_no_msg(sizeof(GenTreeIndex) <= TREE_NODE_SZ_LARGE); // *** large node
324 static_assert_no_msg(sizeof(GenTreeArrLen) <= TREE_NODE_SZ_LARGE); // *** large node
325 static_assert_no_msg(sizeof(GenTreeBoundsChk) <= TREE_NODE_SZ_LARGE); // *** large node
326 static_assert_no_msg(sizeof(GenTreeArrElem) <= TREE_NODE_SZ_LARGE); // *** large node
327 static_assert_no_msg(sizeof(GenTreeArrIndex) <= TREE_NODE_SZ_LARGE); // *** large node
328 static_assert_no_msg(sizeof(GenTreeArrOffs) <= TREE_NODE_SZ_LARGE); // *** large node
329 static_assert_no_msg(sizeof(GenTreeIndir) <= TREE_NODE_SZ_SMALL);
330 static_assert_no_msg(sizeof(GenTreeStoreInd) <= TREE_NODE_SZ_SMALL);
331 static_assert_no_msg(sizeof(GenTreeAddrMode) <= TREE_NODE_SZ_SMALL);
332 static_assert_no_msg(sizeof(GenTreeObj) <= TREE_NODE_SZ_LARGE); // *** large node
333 static_assert_no_msg(sizeof(GenTreeBlk) <= TREE_NODE_SZ_SMALL);
334 static_assert_no_msg(sizeof(GenTreeRetExpr) <= TREE_NODE_SZ_LARGE); // *** large node
335 static_assert_no_msg(sizeof(GenTreeStmt) <= TREE_NODE_SZ_LARGE); // *** large node
336 static_assert_no_msg(sizeof(GenTreeClsVar) <= TREE_NODE_SZ_SMALL);
337 static_assert_no_msg(sizeof(GenTreeArgPlace) <= TREE_NODE_SZ_SMALL);
338 static_assert_no_msg(sizeof(GenTreePhiArg) <= TREE_NODE_SZ_SMALL);
339 static_assert_no_msg(sizeof(GenTreeAllocObj) <= TREE_NODE_SZ_LARGE); // *** large node
340 #ifndef FEATURE_PUT_STRUCT_ARG_STK
341 static_assert_no_msg(sizeof(GenTreePutArgStk) <= TREE_NODE_SZ_SMALL);
342 #else // FEATURE_PUT_STRUCT_ARG_STK
343 // TODO-Throughput: This should not need to be a large node. The object info should be
344 // obtained from the child node.
345 static_assert_no_msg(sizeof(GenTreePutArgStk) <= TREE_NODE_SZ_LARGE);
346 #if FEATURE_ARG_SPLIT
347 static_assert_no_msg(sizeof(GenTreePutArgSplit) <= TREE_NODE_SZ_LARGE);
348 #endif // FEATURE_ARG_SPLIT
349 #endif // FEATURE_PUT_STRUCT_ARG_STK
352 static_assert_no_msg(sizeof(GenTreeSIMD) <= TREE_NODE_SZ_SMALL);
353 #endif // FEATURE_SIMD
355 #ifdef FEATURE_HW_INTRINSICS
356 static_assert_no_msg(sizeof(GenTreeHWIntrinsic) <= TREE_NODE_SZ_SMALL);
357 #endif // FEATURE_HW_INTRINSICS
361 size_t GenTree::GetNodeSize() const
363 return GenTree::s_gtNodeSizes[gtOper];
367 bool GenTree::IsNodeProperlySized() const
371 if (gtDebugFlags & GTF_DEBUG_NODE_SMALL)
373 size = TREE_NODE_SZ_SMALL;
377 assert(gtDebugFlags & GTF_DEBUG_NODE_LARGE);
378 size = TREE_NODE_SZ_LARGE;
381 return GenTree::s_gtNodeSizes[gtOper] <= size;
385 //------------------------------------------------------------------------
386 // ReplaceWith: replace this with the src node. The source must be an isolated node
387 // and cannot be used after the replacement.
390 // src - source tree, that replaces this.
391 // comp - the compiler instance to transfer annotations for arrays.
393 void GenTree::ReplaceWith(GenTree* src, Compiler* comp)
395 // The source may be big only if the target is also a big node
396 assert((gtDebugFlags & GTF_DEBUG_NODE_LARGE) || GenTree::s_gtNodeSizes[src->gtOper] == TREE_NODE_SZ_SMALL);
398 // The check is effective only if nodes have been already threaded.
399 assert((src->gtPrev == nullptr) && (src->gtNext == nullptr));
401 RecordOperBashing(OperGet(), src->OperGet()); // nop unless NODEBASH_STATS is enabled
403 GenTree* prev = gtPrev;
404 GenTree* next = gtNext;
405 // The VTable pointer is copied intentionally here
406 memcpy((void*)this, (void*)src, src->GetNodeSize());
413 // Transfer any annotations.
414 if (src->OperGet() == GT_IND && src->gtFlags & GTF_IND_ARR_INDEX)
417 bool b = comp->GetArrayInfoMap()->Lookup(src, &arrInfo);
419 comp->GetArrayInfoMap()->Set(this, arrInfo);
421 DEBUG_DESTROY_NODE(src);
424 /*****************************************************************************
426 * When 'NODEBASH_STATS' is enabled in "jit.h" we record all instances of
427 * an existing GenTree node having its operator changed. This can be useful
428 * for two (related) things - to see what is being bashed (and what isn't),
429 * and to verify that the existing choices for what nodes are marked 'large'
430 * are reasonable (to minimize "wasted" space).
432 * And yes, the hash function / logic is simplistic, but it is conflict-free
433 * and transparent for what we need.
438 #define BASH_HASH_SIZE 211
440 inline unsigned hashme(genTreeOps op1, genTreeOps op2)
442 return ((op1 * 104729) ^ (op2 * 56569)) % BASH_HASH_SIZE;
447 unsigned __int32 bhFullHash; // the hash value (unique for all old->new pairs)
448 unsigned __int32 bhCount; // the same old->new bashings seen so far
449 unsigned __int8 bhOperOld; // original gtOper
450 unsigned __int8 bhOperNew; // new gtOper
453 static BashHashDsc BashHash[BASH_HASH_SIZE];
455 void GenTree::RecordOperBashing(genTreeOps operOld, genTreeOps operNew)
457 unsigned hash = hashme(operOld, operNew);
458 BashHashDsc* desc = BashHash + hash;
460 if (desc->bhFullHash != hash)
462 noway_assert(desc->bhCount == 0); // if this ever fires, need fix the hash fn
463 desc->bhFullHash = hash;
467 desc->bhOperOld = operOld;
468 desc->bhOperNew = operNew;
471 void GenTree::ReportOperBashing(FILE* f)
478 fprintf(f, "Bashed gtOper stats:\n");
480 fprintf(f, " Old operator New operator #bytes old->new Count\n");
481 fprintf(f, " ---------------------------------------------------------------\n");
483 for (unsigned h = 0; h < BASH_HASH_SIZE; h++)
485 unsigned count = BashHash[h].bhCount;
489 unsigned opOld = BashHash[h].bhOperOld;
490 unsigned opNew = BashHash[h].bhOperNew;
492 fprintf(f, " GT_%-13s -> GT_%-13s [size: %3u->%3u] %c %7u\n", OpName((genTreeOps)opOld),
493 OpName((genTreeOps)opNew), s_gtTrueSizes[opOld], s_gtTrueSizes[opNew],
494 (s_gtTrueSizes[opOld] < s_gtTrueSizes[opNew]) ? 'X' : ' ', count);
498 fprintf(f, "Total bashings: %u\n", total);
504 #endif // NODEBASH_STATS
506 /*****************************************************************************/
508 #if MEASURE_NODE_SIZE
510 void GenTree::DumpNodeSizes(FILE* fp)
512 // Dump the sizes of the various GenTree flavors
514 fprintf(fp, "Small tree node size = %3u bytes\n", TREE_NODE_SZ_SMALL);
515 fprintf(fp, "Large tree node size = %3u bytes\n", TREE_NODE_SZ_LARGE);
518 // Verify that node sizes are set kosherly and dump sizes
519 for (unsigned op = GT_NONE + 1; op < GT_COUNT; op++)
521 unsigned needSize = s_gtTrueSizes[op];
522 unsigned nodeSize = s_gtNodeSizes[op];
524 const char* structNm = OpStructName((genTreeOps)op);
525 const char* operName = OpName((genTreeOps)op);
527 bool repeated = false;
529 // Have we seen this struct flavor before?
530 for (unsigned mop = GT_NONE + 1; mop < op; mop++)
532 if (strcmp(structNm, OpStructName((genTreeOps)mop)) == 0)
539 // Don't repeat the same GenTree flavor unless we have an error
540 if (!repeated || needSize > nodeSize)
542 unsigned sizeChar = '?';
544 if (nodeSize == TREE_NODE_SZ_SMALL)
546 else if (nodeSize == TREE_NODE_SZ_LARGE)
549 fprintf(fp, "GT_%-16s ... %-19s = %3u bytes (%c)", operName, structNm, needSize, sizeChar);
550 if (needSize > nodeSize)
552 fprintf(fp, " -- ERROR -- allocation is only %u bytes!", nodeSize);
554 else if (needSize <= TREE_NODE_SZ_SMALL && nodeSize == TREE_NODE_SZ_LARGE)
556 fprintf(fp, " ... could be small");
564 #endif // MEASURE_NODE_SIZE
566 /*****************************************************************************
568 * Walk all basic blocks and call the given function pointer for all tree
569 * nodes contained therein.
572 void Compiler::fgWalkAllTreesPre(fgWalkPreFn* visitor, void* pCallBackData)
574 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
576 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->getNextStmt())
578 fgWalkTreePre(&stmt->gtStmtExpr, visitor, pCallBackData);
583 //-----------------------------------------------------------
584 // CopyReg: Copy the _gtRegNum/gtRegTag fields.
587 // from - GenTree node from which to copy
591 void GenTree::CopyReg(GenTree* from)
593 _gtRegNum = from->_gtRegNum;
594 INDEBUG(gtRegTag = from->gtRegTag;)
596 // Also copy multi-reg state if this is a call node
599 assert(from->IsCall());
600 this->AsCall()->CopyOtherRegs(from->AsCall());
602 else if (IsCopyOrReload())
604 this->AsCopyOrReload()->CopyOtherRegs(from->AsCopyOrReload());
608 //------------------------------------------------------------------
609 // gtHasReg: Whether node beeen assigned a register by LSRA
615 // Returns true if the node was assigned a register.
617 // In case of multi-reg call nodes, it is considered
618 // having a reg if regs are allocated for all its
621 // In case of GT_COPY or GT_RELOAD of a multi-reg call,
622 // GT_COPY/GT_RELOAD is considered having a reg if it
623 // has a reg assigned to any of its positions.
626 // In order for this to work properly, gtClearReg must be called
627 // prior to setting the register value.
629 bool GenTree::gtHasReg() const
633 if (IsMultiRegCall())
635 // Have to cast away const-ness because GetReturnTypeDesc() is a non-const method
636 GenTree* tree = const_cast<GenTree*>(this);
637 GenTreeCall* call = tree->AsCall();
638 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
641 // A Multi-reg call node is said to have regs, if it has
642 // reg assigned to each of its result registers.
643 for (unsigned i = 0; i < regCount; ++i)
645 hasReg = (call->GetRegNumByIdx(i) != REG_NA);
652 else if (IsCopyOrReloadOfMultiRegCall())
654 GenTree* tree = const_cast<GenTree*>(this);
655 GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
656 GenTreeCall* call = copyOrReload->gtGetOp1()->AsCall();
657 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
660 // A Multi-reg copy or reload node is said to have regs,
661 // if it has valid regs in any of the positions.
662 for (unsigned i = 0; i < regCount; ++i)
664 hasReg = (copyOrReload->GetRegNumByIdx(i) != REG_NA);
673 hasReg = (gtRegNum != REG_NA);
679 //-----------------------------------------------------------------------------
680 // GetRegisterDstCount: Get the number of registers defined by the node.
686 // The number of registers that this node defines.
689 // This should not be called on a contained node.
690 // This does not look at the actual register assignments, if any, and so
691 // is valid after Lowering.
693 int GenTree::GetRegisterDstCount() const
695 assert(!isContained());
696 if (!IsMultiRegNode())
698 return (IsValue()) ? 1 : 0;
700 else if (IsMultiRegCall())
702 // temporarily cast away const-ness as AsCall() method is not declared const
703 GenTree* temp = const_cast<GenTree*>(this);
704 return temp->AsCall()->GetReturnTypeDesc()->GetReturnRegCount();
706 else if (IsCopyOrReload())
708 return gtGetOp1()->GetRegisterDstCount();
710 #if FEATURE_ARG_SPLIT
711 else if (OperIsPutArgSplit())
713 return (const_cast<GenTree*>(this))->AsPutArgSplit()->gtNumRegs;
716 #if !defined(_TARGET_64BIT_)
717 else if (OperIsMultiRegOp())
719 // A MultiRegOp is a GT_MUL_LONG, GT_PUTARG_REG, or GT_BITCAST.
720 // For the latter two (ARM-only), they only have multiple registers if they produce a long value
721 // (GT_MUL_LONG always produces a long value).
722 CLANG_FORMAT_COMMENT_ANCHOR;
724 return (TypeGet() == TYP_LONG) ? 2 : 1;
726 assert(OperIs(GT_MUL_LONG));
731 assert(!"Unexpected multi-reg node");
735 //---------------------------------------------------------------
736 // gtGetRegMask: Get the reg mask of the node.
742 // Reg Mask of GenTree node.
744 regMaskTP GenTree::gtGetRegMask() const
746 regMaskTP resultMask;
748 if (IsMultiRegCall())
750 // temporarily cast away const-ness as AsCall() method is not declared const
751 resultMask = genRegMask(gtRegNum);
752 GenTree* temp = const_cast<GenTree*>(this);
753 resultMask |= temp->AsCall()->GetOtherRegMask();
755 else if (IsCopyOrReloadOfMultiRegCall())
757 // A multi-reg copy or reload, will have valid regs for only those
758 // positions that need to be copied or reloaded. Hence we need
759 // to consider only those registers for computing reg mask.
761 GenTree* tree = const_cast<GenTree*>(this);
762 GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
763 GenTreeCall* call = copyOrReload->gtGetOp1()->AsCall();
764 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
766 resultMask = RBM_NONE;
767 for (unsigned i = 0; i < regCount; ++i)
769 regNumber reg = copyOrReload->GetRegNumByIdx(i);
772 resultMask |= genRegMask(reg);
776 #if FEATURE_ARG_SPLIT
777 else if (OperIsPutArgSplit())
779 GenTree* tree = const_cast<GenTree*>(this);
780 GenTreePutArgSplit* splitArg = tree->AsPutArgSplit();
781 unsigned regCount = splitArg->gtNumRegs;
783 resultMask = RBM_NONE;
784 for (unsigned i = 0; i < regCount; ++i)
786 regNumber reg = splitArg->GetRegNumByIdx(i);
787 assert(reg != REG_NA);
788 resultMask |= genRegMask(reg);
791 #endif // FEATURE_ARG_SPLIT
794 resultMask = genRegMask(gtRegNum);
800 //---------------------------------------------------------------
801 // GetOtherRegMask: Get the reg mask of gtOtherRegs of call node
807 // Reg mask of gtOtherRegs of call node.
809 regMaskTP GenTreeCall::GetOtherRegMask() const
811 regMaskTP resultMask = RBM_NONE;
813 #if FEATURE_MULTIREG_RET
814 for (unsigned i = 0; i < MAX_RET_REG_COUNT - 1; ++i)
816 if (gtOtherRegs[i] != REG_NA)
818 resultMask |= genRegMask((regNumber)gtOtherRegs[i]);
828 //-------------------------------------------------------------------------
830 // Returns true if this call is pure. For now, this uses the same
831 // definition of "pure" that is that used by HelperCallProperties: a
832 // pure call does not read or write any aliased (e.g. heap) memory or
833 // have other global side effects (e.g. class constructors, finalizers),
834 // but is allowed to throw an exception.
836 // NOTE: this call currently only returns true if the call target is a
837 // helper method that is known to be pure. No other analysis is
841 // Copiler - the compiler context.
844 // True if the call is pure; false otherwise.
846 bool GenTreeCall::IsPure(Compiler* compiler) const
848 return (gtCallType == CT_HELPER) &&
849 compiler->s_helperCallProperties.IsPure(compiler->eeGetHelperNum(gtCallMethHnd));
852 //-------------------------------------------------------------------------
854 // Returns true if this call has any side effects. All non-helpers are considered to have side-effects. Only helpers
855 // that do not mutate the heap, do not run constructors, may not throw, and are either a) pure or b) non-finalizing
856 // allocation functions are considered side-effect-free.
859 // compiler - the compiler instance
860 // ignoreExceptions - when `true`, ignores exception side effects
861 // ignoreCctors - when `true`, ignores class constructor side effects
864 // true if this call has any side-effects; false otherwise.
865 bool GenTreeCall::HasSideEffects(Compiler* compiler, bool ignoreExceptions, bool ignoreCctors) const
867 // Generally all GT_CALL nodes are considered to have side-effects, but we may have extra information about helper
868 // calls that can prove them side-effect-free.
869 if (gtCallType != CT_HELPER)
874 CorInfoHelpFunc helper = compiler->eeGetHelperNum(gtCallMethHnd);
875 HelperCallProperties& helperProperties = compiler->s_helperCallProperties;
877 // We definitely care about the side effects if MutatesHeap is true
878 if (helperProperties.MutatesHeap(helper))
883 // Unless we have been instructed to ignore cctors (CSE, for example, ignores cctors), consider them side effects.
884 if (!ignoreCctors && helperProperties.MayRunCctor(helper))
889 // If we also care about exceptions then check if the helper can throw
890 if (!ignoreExceptions && !helperProperties.NoThrow(helper))
895 // If this is not a Pure helper call or an allocator (that will not need to run a finalizer)
896 // then this call has side effects.
897 return !helperProperties.IsPure(helper) &&
898 (!helperProperties.IsAllocator(helper) || ((gtCallMoreFlags & GTF_CALL_M_ALLOC_SIDE_EFFECTS) != 0));
901 //-------------------------------------------------------------------------
902 // HasNonStandardAddedArgs: Return true if the method has non-standard args added to the call
903 // argument list during argument morphing (fgMorphArgs), e.g., passed in R10 or R11 on AMD64.
904 // See also GetNonStandardAddedArgCount().
907 // compiler - the compiler instance
910 // true if there are any such args, false otherwise.
912 bool GenTreeCall::HasNonStandardAddedArgs(Compiler* compiler) const
914 return GetNonStandardAddedArgCount(compiler) != 0;
917 //-------------------------------------------------------------------------
918 // GetNonStandardAddedArgCount: Get the count of non-standard arguments that have been added
919 // during call argument morphing (fgMorphArgs). Do not count non-standard args that are already
920 // counted in the argument list prior to morphing.
922 // This function is used to help map the caller and callee arguments during tail call setup.
925 // compiler - the compiler instance
928 // The count of args, as described.
931 // It would be more general to have fgMorphArgs set a bit on the call node when such
932 // args are added to a call, and a bit on each such arg, and then have this code loop
933 // over the call args when the special call bit is set, counting the args with the special
934 // arg bit. This seems pretty heavyweight, though. Instead, this logic needs to be kept
935 // in sync with fgMorphArgs.
937 int GenTreeCall::GetNonStandardAddedArgCount(Compiler* compiler) const
939 if (IsUnmanaged() && !compiler->opts.ShouldUsePInvokeHelpers())
941 // R11 = PInvoke cookie param
944 else if (IsVirtualStub())
946 // R11 = Virtual stub param
949 else if ((gtCallType == CT_INDIRECT) && (gtCallCookie != nullptr))
951 // R10 = PInvoke target param
952 // R11 = PInvoke cookie param
958 //-------------------------------------------------------------------------
959 // TreatAsHasRetBufArg:
962 // compiler, the compiler instance so that we can call eeGetHelperNum
965 // Returns true if we treat the call as if it has a retBuf argument
966 // This method may actually have a retBuf argument
967 // or it could be a JIT helper that we are still transforming during
968 // the importer phase.
971 // On ARM64 marking the method with the GTF_CALL_M_RETBUFFARG flag
972 // will make HasRetBufArg() return true, but will also force the
973 // use of register x8 to pass the RetBuf argument.
975 // These two Jit Helpers that we handle here by returning true
976 // aren't actually defined to return a struct, so they don't expect
977 // their RetBuf to be passed in x8, instead they expect it in x0.
979 bool GenTreeCall::TreatAsHasRetBufArg(Compiler* compiler) const
987 // If we see a Jit helper call that returns a TYP_STRUCT we will
988 // transform it as if it has a Return Buffer Argument
990 if (IsHelperCall() && (gtReturnType == TYP_STRUCT))
992 // There are two possible helper calls that use this path:
993 // CORINFO_HELP_GETFIELDSTRUCT and CORINFO_HELP_UNBOX_NULLABLE
995 CorInfoHelpFunc helpFunc = compiler->eeGetHelperNum(gtCallMethHnd);
997 if (helpFunc == CORINFO_HELP_GETFIELDSTRUCT)
1001 else if (helpFunc == CORINFO_HELP_UNBOX_NULLABLE)
1007 assert(!"Unexpected JIT helper in TreatAsHasRetBufArg");
1014 //-------------------------------------------------------------------------
1015 // IsHelperCall: Determine if this GT_CALL node is a specific helper call.
1018 // compiler - the compiler instance so that we can call eeFindHelper
1021 // Returns true if this GT_CALL node is a call to the specified helper.
1023 bool GenTreeCall::IsHelperCall(Compiler* compiler, unsigned helper) const
1025 return IsHelperCall(compiler->eeFindHelper(helper));
1028 //------------------------------------------------------------------------
1029 // GenTreeCall::ReplaceCallOperand:
1030 // Replaces a given operand to a call node and updates the call
1031 // argument table if necessary.
1034 // useEdge - the use edge that points to the operand to be replaced.
1035 // replacement - the replacement node.
1037 void GenTreeCall::ReplaceCallOperand(GenTree** useEdge, GenTree* replacement)
1039 assert(useEdge != nullptr);
1040 assert(replacement != nullptr);
1041 assert(TryGetUse(*useEdge, &useEdge));
1043 GenTree* originalOperand = *useEdge;
1044 *useEdge = replacement;
1046 const bool isArgument =
1047 (replacement != gtControlExpr) &&
1048 ((gtCallType != CT_INDIRECT) || ((replacement != gtCallCookie) && (replacement != gtCallAddr)));
1052 if ((originalOperand->gtFlags & GTF_LATE_ARG) != 0)
1054 replacement->gtFlags |= GTF_LATE_ARG;
1058 assert((replacement->gtFlags & GTF_LATE_ARG) == 0);
1060 fgArgTabEntry* fp = Compiler::gtArgEntryByNode(this, originalOperand);
1061 assert(fp->node == originalOperand);
1062 fp->node = replacement;
1067 //-------------------------------------------------------------------------
1068 // AreArgsComplete: Determine if this GT_CALL node's arguments have been processed.
1071 // Returns true if fgMorphArgs has processed the arguments.
1073 bool GenTreeCall::AreArgsComplete() const
1075 if (fgArgInfo == nullptr)
1079 if (fgArgInfo->AreArgsComplete())
1081 assert((gtCallLateArgs != nullptr) || !fgArgInfo->HasRegArgs());
1084 assert(gtCallArgs == nullptr);
1088 #if !defined(FEATURE_PUT_STRUCT_ARG_STK)
1089 unsigned GenTreePutArgStk::getArgSize()
1091 return genTypeSize(genActualType(gtOp1->gtType));
1093 #endif // !defined(FEATURE_PUT_STRUCT_ARG_STK)
1095 /*****************************************************************************
1097 * Returns non-zero if the two trees are identical.
1100 bool GenTree::Compare(GenTree* op1, GenTree* op2, bool swapOK)
1105 // printf("tree1:\n"); gtDispTree(op1);
1106 // printf("tree2:\n"); gtDispTree(op2);
1112 return (op2 == nullptr);
1123 assert(op1->gtOper != GT_STMT);
1124 assert(op2->gtOper != GT_STMT);
1126 oper = op1->OperGet();
1128 /* The operators must be equal */
1130 if (oper != op2->gtOper)
1135 /* The types must be equal */
1137 if (op1->gtType != op2->gtType)
1142 /* Overflow must be equal */
1143 if (op1->gtOverflowEx() != op2->gtOverflowEx())
1148 /* Sensible flags must be equal */
1149 if ((op1->gtFlags & (GTF_UNSIGNED)) != (op2->gtFlags & (GTF_UNSIGNED)))
1154 /* Figure out what kind of nodes we're comparing */
1156 kind = op1->OperKind();
1158 /* Is this a constant node? */
1160 if (kind & GTK_CONST)
1165 if (op1->gtIntCon.gtIconVal == op2->gtIntCon.gtIconVal)
1171 // TODO-CQ: Enable this in the future
1173 if (op1->gtLngCon.gtLconVal == op2->gtLngCon.gtLconVal)
1178 if (op1->gtDblCon.gtDconVal == op2->gtDblCon.gtDconVal)
1189 /* Is this a leaf node? */
1191 if (kind & GTK_LEAF)
1196 if (op1->gtLclVarCommon.gtLclNum != op2->gtLclVarCommon.gtLclNum)
1204 if (op1->gtLclFld.gtLclNum != op2->gtLclFld.gtLclNum ||
1205 op1->gtLclFld.gtLclOffs != op2->gtLclFld.gtLclOffs)
1213 if (op1->gtClsVar.gtClsVarHnd != op2->gtClsVar.gtClsVarHnd)
1224 if ((op1->gtType == TYP_STRUCT) &&
1225 (op1->gtArgPlace.gtArgPlaceClsHnd != op2->gtArgPlace.gtArgPlaceClsHnd))
1238 /* Is it a 'simple' unary/binary operator? */
1240 if (kind & GTK_UNOP)
1244 // ExOp operators extend unary operator with extra, non-GenTree* members. In many cases,
1245 // these should be included in the comparison.
1249 if (op1->gtArrLen.ArrLenOffset() != op2->gtArrLen.ArrLenOffset())
1255 if (op1->gtCast.gtCastType != op2->gtCast.gtCastType)
1261 if (op1->AsObj()->gtClass != op2->AsObj()->gtClass)
1267 // For the ones below no extra argument matters for comparison.
1269 case GT_RUNTIMELOOKUP:
1273 assert(!"unexpected unary ExOp operator");
1276 return Compare(op1->gtOp.gtOp1, op2->gtOp.gtOp1);
1279 if (kind & GTK_BINOP)
1283 // ExOp operators extend unary operator with extra, non-GenTree* members. In many cases,
1284 // these should be included in the hash code.
1288 if (op1->gtIntrinsic.gtIntrinsicId != op2->gtIntrinsic.gtIntrinsicId)
1294 if (op1->gtAddrMode.gtScale != op2->gtAddrMode.gtScale)
1298 if (op1->gtAddrMode.Offset() != op2->gtAddrMode.Offset())
1304 if (op1->gtIndex.gtIndElemSize != op2->gtIndex.gtIndElemSize)
1310 if (op1->AsIndexAddr()->gtElemSize != op2->AsIndexAddr()->gtElemSize)
1317 if ((op1->AsSIMD()->gtSIMDIntrinsicID != op2->AsSIMD()->gtSIMDIntrinsicID) ||
1318 (op1->AsSIMD()->gtSIMDBaseType != op2->AsSIMD()->gtSIMDBaseType) ||
1319 (op1->AsSIMD()->gtSIMDSize != op2->AsSIMD()->gtSIMDSize))
1324 #endif // FEATURE_SIMD
1326 #ifdef FEATURE_HW_INTRINSICS
1327 case GT_HWIntrinsic:
1328 if ((op1->AsHWIntrinsic()->gtHWIntrinsicId != op2->AsHWIntrinsic()->gtHWIntrinsicId) ||
1329 (op1->AsHWIntrinsic()->gtSIMDBaseType != op2->AsHWIntrinsic()->gtSIMDBaseType) ||
1330 (op1->AsHWIntrinsic()->gtSIMDSize != op2->AsHWIntrinsic()->gtSIMDSize) ||
1331 (op1->AsHWIntrinsic()->gtIndexBaseType != op2->AsHWIntrinsic()->gtIndexBaseType))
1338 // For the ones below no extra argument matters for comparison.
1343 assert(!"unexpected binary ExOp operator");
1347 if (op1->gtOp.gtOp2)
1349 if (!Compare(op1->gtOp.gtOp1, op2->gtOp.gtOp1, swapOK))
1351 if (swapOK && OperIsCommutative(oper) &&
1352 ((op1->gtOp.gtOp1->gtFlags | op1->gtOp.gtOp2->gtFlags | op2->gtOp.gtOp1->gtFlags |
1353 op2->gtOp.gtOp2->gtFlags) &
1354 GTF_ALL_EFFECT) == 0)
1356 if (Compare(op1->gtOp.gtOp1, op2->gtOp.gtOp2, swapOK))
1358 op1 = op1->gtOp.gtOp2;
1359 op2 = op2->gtOp.gtOp1;
1367 op1 = op1->gtOp.gtOp2;
1368 op2 = op2->gtOp.gtOp2;
1375 op1 = op1->gtOp.gtOp1;
1376 op2 = op2->gtOp.gtOp1;
1380 return (op2 == nullptr);
1391 /* See what kind of a special operator we have here */
1396 if (op1->gtField.gtFldHnd != op2->gtField.gtFldHnd)
1401 op1 = op1->gtField.gtFldObj;
1402 op2 = op2->gtField.gtFldObj;
1416 if (op1->gtCall.gtCallType != op2->gtCall.gtCallType)
1421 if (op1->gtCall.gtCallType != CT_INDIRECT)
1423 if (op1->gtCall.gtCallMethHnd != op2->gtCall.gtCallMethHnd)
1428 #ifdef FEATURE_READYTORUN_COMPILER
1429 if (op1->gtCall.gtEntryPoint.addr != op2->gtCall.gtEntryPoint.addr)
1437 if (!Compare(op1->gtCall.gtCallAddr, op2->gtCall.gtCallAddr))
1443 if (Compare(op1->gtCall.gtCallLateArgs, op2->gtCall.gtCallLateArgs) &&
1444 Compare(op1->gtCall.gtCallArgs, op2->gtCall.gtCallArgs) &&
1445 Compare(op1->gtCall.gtControlExpr, op2->gtCall.gtControlExpr) &&
1446 Compare(op1->gtCall.gtCallObjp, op2->gtCall.gtCallObjp))
1454 if (op1->gtArrElem.gtArrRank != op2->gtArrElem.gtArrRank)
1459 // NOTE: gtArrElemSize may need to be handled
1462 for (dim = 0; dim < op1->gtArrElem.gtArrRank; dim++)
1464 if (!Compare(op1->gtArrElem.gtArrInds[dim], op2->gtArrElem.gtArrInds[dim]))
1470 op1 = op1->gtArrElem.gtArrObj;
1471 op2 = op2->gtArrElem.gtArrObj;
1475 if (op1->gtArrOffs.gtCurrDim != op2->gtArrOffs.gtCurrDim ||
1476 op1->gtArrOffs.gtArrRank != op2->gtArrOffs.gtArrRank)
1480 return (Compare(op1->gtArrOffs.gtOffset, op2->gtArrOffs.gtOffset) &&
1481 Compare(op1->gtArrOffs.gtIndex, op2->gtArrOffs.gtIndex) &&
1482 Compare(op1->gtArrOffs.gtArrObj, op2->gtArrOffs.gtArrObj));
1485 return Compare(op1->gtCmpXchg.gtOpLocation, op2->gtCmpXchg.gtOpLocation) &&
1486 Compare(op1->gtCmpXchg.gtOpValue, op2->gtCmpXchg.gtOpValue) &&
1487 Compare(op1->gtCmpXchg.gtOpComparand, op2->gtCmpXchg.gtOpComparand);
1489 case GT_ARR_BOUNDS_CHECK:
1492 #endif // FEATURE_SIMD
1493 #ifdef FEATURE_HW_INTRINSICS
1494 case GT_HW_INTRINSIC_CHK:
1495 #endif // FEATURE_HW_INTRINSICS
1496 return Compare(op1->gtBoundsChk.gtIndex, op2->gtBoundsChk.gtIndex) &&
1497 Compare(op1->gtBoundsChk.gtArrLen, op2->gtBoundsChk.gtArrLen) &&
1498 (op1->gtBoundsChk.gtThrowKind == op2->gtBoundsChk.gtThrowKind);
1500 case GT_STORE_DYN_BLK:
1502 return Compare(op1->gtDynBlk.Addr(), op2->gtDynBlk.Addr()) &&
1503 Compare(op1->gtDynBlk.Data(), op2->gtDynBlk.Data()) &&
1504 Compare(op1->gtDynBlk.gtDynamicSize, op2->gtDynBlk.gtDynamicSize);
1507 assert(!"unexpected operator");
1513 /*****************************************************************************
1515 * Returns non-zero if the given tree contains a use of a local #lclNum.
1518 bool Compiler::gtHasRef(GenTree* tree, ssize_t lclNum, bool defOnly)
1527 oper = tree->OperGet();
1528 kind = tree->OperKind();
1530 assert(oper != GT_STMT);
1532 /* Is this a constant node? */
1534 if (kind & GTK_CONST)
1539 /* Is this a leaf node? */
1541 if (kind & GTK_LEAF)
1543 if (oper == GT_LCL_VAR)
1545 if (tree->gtLclVarCommon.gtLclNum == (unsigned)lclNum)
1553 else if (oper == GT_RET_EXPR)
1555 return gtHasRef(tree->gtRetExpr.gtInlineCandidate, lclNum, defOnly);
1561 /* Is it a 'simple' unary/binary operator? */
1563 if (kind & GTK_SMPOP)
1565 if (tree->gtGetOp2IfPresent())
1567 if (gtHasRef(tree->gtOp.gtOp1, lclNum, defOnly))
1572 tree = tree->gtOp.gtOp2;
1577 tree = tree->gtOp.gtOp1;
1586 // 'tree' is the gtOp1 of an assignment node. So we can handle
1587 // the case where defOnly is either true or false.
1589 if (tree->gtOper == GT_LCL_VAR && tree->gtLclVarCommon.gtLclNum == (unsigned)lclNum)
1593 else if (tree->gtOper == GT_FIELD && lclNum == (ssize_t)tree->gtField.gtFldHnd)
1603 /* See what kind of a special operator we have here */
1608 if (lclNum == (ssize_t)tree->gtField.gtFldHnd)
1616 tree = tree->gtField.gtFldObj;
1625 if (tree->gtCall.gtCallObjp)
1627 if (gtHasRef(tree->gtCall.gtCallObjp, lclNum, defOnly))
1633 if (tree->gtCall.gtCallArgs)
1635 if (gtHasRef(tree->gtCall.gtCallArgs, lclNum, defOnly))
1641 if (tree->gtCall.gtCallLateArgs)
1643 if (gtHasRef(tree->gtCall.gtCallLateArgs, lclNum, defOnly))
1649 if (tree->gtCall.gtControlExpr)
1651 if (gtHasRef(tree->gtCall.gtControlExpr, lclNum, defOnly))
1657 if (tree->gtCall.gtCallType == CT_INDIRECT)
1659 // pinvoke-calli cookie is a constant, or constant indirection
1660 assert(tree->gtCall.gtCallCookie == nullptr || tree->gtCall.gtCallCookie->gtOper == GT_CNS_INT ||
1661 tree->gtCall.gtCallCookie->gtOper == GT_IND);
1663 tree = tree->gtCall.gtCallAddr;
1678 if (gtHasRef(tree->gtArrElem.gtArrObj, lclNum, defOnly))
1684 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
1686 if (gtHasRef(tree->gtArrElem.gtArrInds[dim], lclNum, defOnly))
1695 if (gtHasRef(tree->gtArrOffs.gtOffset, lclNum, defOnly) ||
1696 gtHasRef(tree->gtArrOffs.gtIndex, lclNum, defOnly) ||
1697 gtHasRef(tree->gtArrOffs.gtArrObj, lclNum, defOnly))
1704 if (gtHasRef(tree->gtCmpXchg.gtOpLocation, lclNum, defOnly))
1708 if (gtHasRef(tree->gtCmpXchg.gtOpValue, lclNum, defOnly))
1712 if (gtHasRef(tree->gtCmpXchg.gtOpComparand, lclNum, defOnly))
1718 case GT_ARR_BOUNDS_CHECK:
1721 #endif // FEATURE_SIMD
1722 #ifdef FEATURE_HW_INTRINSICS
1723 case GT_HW_INTRINSIC_CHK:
1724 #endif // FEATURE_HW_INTRINSICS
1725 if (gtHasRef(tree->gtBoundsChk.gtIndex, lclNum, defOnly))
1729 if (gtHasRef(tree->gtBoundsChk.gtArrLen, lclNum, defOnly))
1735 case GT_STORE_DYN_BLK:
1736 if (gtHasRef(tree->gtDynBlk.Data(), lclNum, defOnly))
1742 if (gtHasRef(tree->gtDynBlk.Addr(), lclNum, defOnly))
1746 if (gtHasRef(tree->gtDynBlk.gtDynamicSize, lclNum, defOnly))
1756 assert(!"unexpected operator");
1765 bool hasAddrTakenLcl;
1769 Compiler::fgWalkResult Compiler::gtHasLocalsWithAddrOpCB(GenTree** pTree, fgWalkData* data)
1771 GenTree* tree = *pTree;
1772 Compiler* comp = data->compiler;
1774 if (tree->gtOper == GT_LCL_VAR)
1776 unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
1777 LclVarDsc* varDsc = &comp->lvaTable[lclNum];
1779 if (varDsc->lvHasLdAddrOp || varDsc->lvAddrExposed)
1781 ((AddrTakenDsc*)data->pCallbackData)->hasAddrTakenLcl = true;
1786 return WALK_CONTINUE;
1789 /*****************************************************************************
1791 * Return true if this tree contains locals with lvHasLdAddrOp or lvAddrExposed
1795 bool Compiler::gtHasLocalsWithAddrOp(GenTree* tree)
1800 desc.hasAddrTakenLcl = false;
1802 fgWalkTreePre(&tree, gtHasLocalsWithAddrOpCB, &desc);
1804 return desc.hasAddrTakenLcl;
1809 /*****************************************************************************
1811 * Helper used to compute hash values for trees.
1814 inline unsigned genTreeHashAdd(unsigned old, unsigned add)
1816 return (old + old / 2) ^ add;
1819 inline unsigned genTreeHashAdd(unsigned old, void* add)
1821 return genTreeHashAdd(old, (unsigned)(size_t)add);
1824 /*****************************************************************************
1826 * Given an arbitrary expression tree, compute a hash value for it.
1829 unsigned Compiler::gtHashValue(GenTree* tree)
1840 assert(tree->gtOper != GT_STMT);
1842 /* Figure out what kind of a node we have */
1844 oper = tree->OperGet();
1845 kind = tree->OperKind();
1847 /* Include the operator value in the hash */
1849 hash = genTreeHashAdd(hash, oper);
1851 /* Is this a constant or leaf node? */
1853 if (kind & (GTK_CONST | GTK_LEAF))
1861 add = tree->gtLclVar.gtLclNum;
1864 hash = genTreeHashAdd(hash, tree->gtLclFld.gtLclNum);
1865 add = tree->gtLclFld.gtLclOffs;
1869 add = tree->gtIntCon.gtIconVal;
1872 bits = (UINT64)tree->gtLngCon.gtLconVal;
1875 #else // 32-bit host
1876 add = genTreeHashAdd(uhi32(bits), ulo32(bits));
1880 bits = *(UINT64*)(&tree->gtDblCon.gtDconVal);
1883 #else // 32-bit host
1884 add = genTreeHashAdd(uhi32(bits), ulo32(bits));
1888 add = tree->gtStrCon.gtSconCPX;
1892 add = tree->gtVal.gtVal1;
1901 // narrow 'add' into a 32-bit 'val'
1904 val = genTreeHashAdd(uhi32(add), ulo32(add));
1905 #else // 32-bit host
1910 hash = genTreeHashAdd(hash, val);
1914 /* Is it a 'simple' unary/binary operator? */
1918 if (kind & GTK_UNOP)
1920 op1 = tree->gtOp.gtOp1;
1921 /* Special case: no sub-operand at all */
1923 if (GenTree::IsExOp(kind))
1925 // ExOp operators extend operators with extra, non-GenTree* members. In many cases,
1926 // these should be included in the hash code.
1930 hash += tree->gtArrLen.ArrLenOffset();
1933 hash ^= tree->gtCast.gtCastType;
1936 hash += tree->gtIndex.gtIndElemSize;
1939 hash += tree->AsIndexAddr()->gtElemSize;
1942 hash = genTreeHashAdd(hash, static_cast<unsigned>(
1943 reinterpret_cast<uintptr_t>(tree->gtAllocObj.gtAllocObjClsHnd)));
1944 hash = genTreeHashAdd(hash, tree->gtAllocObj.gtNewHelper);
1946 case GT_RUNTIMELOOKUP:
1948 genTreeHashAdd(hash,
1949 static_cast<unsigned>(reinterpret_cast<uintptr_t>(tree->gtRuntimeLookup.gtHnd)));
1954 genTreeHashAdd(hash, static_cast<unsigned>(reinterpret_cast<uintptr_t>(tree->gtObj.gtClass)));
1956 // For the ones below no extra argument matters for comparison.
1961 assert(!"unexpected unary ExOp operator");
1974 if (kind & GTK_BINOP)
1976 if (GenTree::IsExOp(kind))
1978 // ExOp operators extend operators with extra, non-GenTree* members. In many cases,
1979 // these should be included in the hash code.
1983 hash += tree->gtIntrinsic.gtIntrinsicId;
1986 hash += static_cast<unsigned>(tree->gtAddrMode.Offset() << 3) + tree->gtAddrMode.gtScale;
1991 hash += tree->gtBlk.gtBlkSize;
1996 hash ^= PtrToUlong(tree->AsObj()->gtClass);
2000 case GT_STORE_DYN_BLK:
2001 hash += gtHashValue(tree->AsDynBlk()->gtDynamicSize);
2004 // For the ones below no extra argument matters for comparison.
2013 hash += tree->gtSIMD.gtSIMDIntrinsicID;
2014 hash += tree->gtSIMD.gtSIMDBaseType;
2015 hash += tree->gtSIMD.gtSIMDSize;
2017 #endif // FEATURE_SIMD
2019 #ifdef FEATURE_HW_INTRINSICS
2020 case GT_HWIntrinsic:
2021 hash += tree->gtHWIntrinsic.gtHWIntrinsicId;
2022 hash += tree->gtHWIntrinsic.gtSIMDBaseType;
2023 hash += tree->gtHWIntrinsic.gtSIMDSize;
2024 hash += tree->gtHWIntrinsic.gtIndexBaseType;
2026 #endif // FEATURE_HW_INTRINSICS
2029 assert(!"unexpected binary ExOp operator");
2033 op1 = tree->gtOp.gtOp1;
2034 GenTree* op2 = tree->gtOp.gtOp2;
2036 /* Is there a second sub-operand? */
2040 /* Special case: no sub-operands at all */
2047 /* This is a unary operator */
2053 /* This is a binary operator */
2055 unsigned hsh1 = gtHashValue(op1);
2057 /* Add op1's hash to the running value and continue with op2 */
2059 hash = genTreeHashAdd(hash, hsh1);
2065 /* See what kind of a special operator we have here */
2066 switch (tree->gtOper)
2069 if (tree->gtField.gtFldObj)
2071 temp = tree->gtField.gtFldObj;
2073 hash = genTreeHashAdd(hash, gtHashValue(temp));
2078 temp = tree->gtStmt.gtStmtExpr;
2080 hash = genTreeHashAdd(hash, gtHashValue(temp));
2085 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrElem.gtArrObj));
2088 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
2090 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrElem.gtArrInds[dim]));
2096 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrOffs.gtOffset));
2097 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrOffs.gtIndex));
2098 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrOffs.gtArrObj));
2103 if (tree->gtCall.gtCallObjp && tree->gtCall.gtCallObjp->gtOper != GT_NOP)
2105 temp = tree->gtCall.gtCallObjp;
2107 hash = genTreeHashAdd(hash, gtHashValue(temp));
2110 if (tree->gtCall.gtCallArgs)
2112 temp = tree->gtCall.gtCallArgs;
2114 hash = genTreeHashAdd(hash, gtHashValue(temp));
2117 if (tree->gtCall.gtCallType == CT_INDIRECT)
2119 temp = tree->gtCall.gtCallAddr;
2121 hash = genTreeHashAdd(hash, gtHashValue(temp));
2125 hash = genTreeHashAdd(hash, tree->gtCall.gtCallMethHnd);
2128 if (tree->gtCall.gtCallLateArgs)
2130 temp = tree->gtCall.gtCallLateArgs;
2132 hash = genTreeHashAdd(hash, gtHashValue(temp));
2137 hash = genTreeHashAdd(hash, gtHashValue(tree->gtCmpXchg.gtOpLocation));
2138 hash = genTreeHashAdd(hash, gtHashValue(tree->gtCmpXchg.gtOpValue));
2139 hash = genTreeHashAdd(hash, gtHashValue(tree->gtCmpXchg.gtOpComparand));
2142 case GT_ARR_BOUNDS_CHECK:
2145 #endif // FEATURE_SIMD
2146 #ifdef FEATURE_HW_INTRINSICS
2147 case GT_HW_INTRINSIC_CHK:
2148 #endif // FEATURE_HW_INTRINSICS
2149 hash = genTreeHashAdd(hash, gtHashValue(tree->gtBoundsChk.gtIndex));
2150 hash = genTreeHashAdd(hash, gtHashValue(tree->gtBoundsChk.gtArrLen));
2151 hash = genTreeHashAdd(hash, tree->gtBoundsChk.gtThrowKind);
2154 case GT_STORE_DYN_BLK:
2155 hash = genTreeHashAdd(hash, gtHashValue(tree->gtDynBlk.Data()));
2158 hash = genTreeHashAdd(hash, gtHashValue(tree->gtDynBlk.Addr()));
2159 hash = genTreeHashAdd(hash, gtHashValue(tree->gtDynBlk.gtDynamicSize));
2166 assert(!"unexpected operator");
2177 /*****************************************************************************
2179 * Return a relational operator that is the reverse of the given one.
2183 genTreeOps GenTree::ReverseRelop(genTreeOps relop)
2185 static const genTreeOps reverseOps[] = {
2192 GT_TEST_NE, // GT_TEST_EQ
2193 GT_TEST_EQ, // GT_TEST_NE
2196 assert(reverseOps[GT_EQ - GT_EQ] == GT_NE);
2197 assert(reverseOps[GT_NE - GT_EQ] == GT_EQ);
2199 assert(reverseOps[GT_LT - GT_EQ] == GT_GE);
2200 assert(reverseOps[GT_LE - GT_EQ] == GT_GT);
2201 assert(reverseOps[GT_GE - GT_EQ] == GT_LT);
2202 assert(reverseOps[GT_GT - GT_EQ] == GT_LE);
2204 assert(reverseOps[GT_TEST_EQ - GT_EQ] == GT_TEST_NE);
2205 assert(reverseOps[GT_TEST_NE - GT_EQ] == GT_TEST_EQ);
2207 assert(OperIsCompare(relop));
2208 assert(relop >= GT_EQ && (unsigned)(relop - GT_EQ) < sizeof(reverseOps));
2210 return reverseOps[relop - GT_EQ];
2213 /*****************************************************************************
2215 * Return a relational operator that will work for swapped operands.
2219 genTreeOps GenTree::SwapRelop(genTreeOps relop)
2221 static const genTreeOps swapOps[] = {
2228 GT_TEST_EQ, // GT_TEST_EQ
2229 GT_TEST_NE, // GT_TEST_NE
2232 assert(swapOps[GT_EQ - GT_EQ] == GT_EQ);
2233 assert(swapOps[GT_NE - GT_EQ] == GT_NE);
2235 assert(swapOps[GT_LT - GT_EQ] == GT_GT);
2236 assert(swapOps[GT_LE - GT_EQ] == GT_GE);
2237 assert(swapOps[GT_GE - GT_EQ] == GT_LE);
2238 assert(swapOps[GT_GT - GT_EQ] == GT_LT);
2240 assert(swapOps[GT_TEST_EQ - GT_EQ] == GT_TEST_EQ);
2241 assert(swapOps[GT_TEST_NE - GT_EQ] == GT_TEST_NE);
2243 assert(OperIsCompare(relop));
2244 assert(relop >= GT_EQ && (unsigned)(relop - GT_EQ) < sizeof(swapOps));
2246 return swapOps[relop - GT_EQ];
2249 /*****************************************************************************
2251 * Reverse the meaning of the given test condition.
2254 GenTree* Compiler::gtReverseCond(GenTree* tree)
2256 if (tree->OperIsCompare())
2258 tree->SetOper(GenTree::ReverseRelop(tree->OperGet()));
2260 // Flip the GTF_RELOP_NAN_UN bit
2261 // a ord b === (a != NaN && b != NaN)
2262 // a unord b === (a == NaN || b == NaN)
2263 // => !(a ord b) === (a unord b)
2264 if (varTypeIsFloating(tree->gtOp.gtOp1->TypeGet()))
2266 tree->gtFlags ^= GTF_RELOP_NAN_UN;
2269 else if (tree->OperIs(GT_JCC, GT_SETCC))
2271 GenTreeCC* cc = tree->AsCC();
2272 cc->gtCondition = GenCondition::Reverse(cc->gtCondition);
2274 else if (tree->OperIs(GT_JCMP))
2276 // Flip the GTF_JCMP_EQ
2278 // This causes switching
2281 tree->gtFlags ^= GTF_JCMP_EQ;
2285 tree = gtNewOperNode(GT_NOT, TYP_INT, tree);
2291 /*****************************************************************************/
2295 bool GenTree::gtIsValid64RsltMul()
2297 if ((gtOper != GT_MUL) || !(gtFlags & GTF_MUL_64RSLT))
2302 GenTree* op1 = gtOp.gtOp1;
2303 GenTree* op2 = gtOp.gtOp2;
2305 if (TypeGet() != TYP_LONG || op1->TypeGet() != TYP_LONG || op2->TypeGet() != TYP_LONG)
2315 // op1 has to be conv.i8(i4Expr)
2316 if ((op1->gtOper != GT_CAST) || (genActualType(op1->CastFromType()) != TYP_INT))
2321 // op2 has to be conv.i8(i4Expr)
2322 if ((op2->gtOper != GT_CAST) || (genActualType(op2->CastFromType()) != TYP_INT))
2327 // The signedness of both casts must be the same
2328 if (((op1->gtFlags & GTF_UNSIGNED) != 0) != ((op2->gtFlags & GTF_UNSIGNED) != 0))
2333 // Do unsigned mul iff both the casts are unsigned
2334 if (((op1->gtFlags & GTF_UNSIGNED) != 0) != ((gtFlags & GTF_UNSIGNED) != 0))
2344 //------------------------------------------------------------------------------
2345 // gtSetListOrder : Figure out the evaluation order for a list of values.
2349 // list - List to figure out the evaluation order for
2350 // isListCallArgs - True iff the list is a list of call arguments
2351 // callArgsInRegs - True iff the list is a list of call arguments and they are passed in registers
2354 // True if the operation can be a root of a bitwise rotation tree; false otherwise.
2356 unsigned Compiler::gtSetListOrder(GenTree* list, bool isListCallArgs, bool callArgsInRegs)
2358 assert((list != nullptr) && list->OperIsAnyList());
2359 assert(!callArgsInRegs || isListCallArgs);
2361 ArrayStack<GenTree*> listNodes(getAllocator(CMK_ArrayStack));
2365 listNodes.Push(list);
2366 list = list->gtOp.gtOp2;
2367 } while ((list != nullptr) && (list->OperIsAnyList()));
2369 unsigned nxtlvl = (list == nullptr) ? 0 : gtSetEvalOrder(list);
2370 while (!listNodes.Empty())
2372 list = listNodes.Pop();
2373 assert(list && list->OperIsAnyList());
2374 GenTree* next = list->gtOp.gtOp2;
2378 // TODO: Do we have to compute costs differently for argument lists and
2380 // https://github.com/dotnet/coreclr/issues/7095
2381 unsigned costSz = (isListCallArgs || (next == nullptr)) ? 0 : 1;
2382 unsigned costEx = (isListCallArgs || (next == nullptr)) ? 0 : 1;
2384 if (next != nullptr)
2393 costEx += next->gtCostEx;
2394 costSz += next->gtCostSz;
2397 GenTree* op1 = list->gtOp.gtOp1;
2398 unsigned lvl = gtSetEvalOrder(op1);
2400 // Swap the level counts
2401 if (list->gtFlags & GTF_REVERSE_OPS)
2410 // TODO: Do we have to compute levels differently for argument lists and
2412 // https://github.com/dotnet/coreclr/issues/7095
2426 else if (lvl == nxtlvl)
2436 if (op1->gtCostEx != 0)
2438 costEx += op1->gtCostEx;
2439 costEx += (callArgsInRegs || !isListCallArgs) ? 0 : IND_COST_EX;
2442 if (op1->gtCostSz != 0)
2444 costSz += op1->gtCostSz;
2445 #ifdef _TARGET_XARCH_
2446 if (callArgsInRegs) // push is smaller than mov to reg
2453 list->SetCosts(costEx, costSz);
2461 //-----------------------------------------------------------------------------
2462 // gtWalkOp: Traverse and mark an address expression
2465 // op1WB - An out parameter which is either the address expression, or one
2467 // op2WB - An out parameter which starts as either null or one of the operands
2468 // of the address expression.
2469 // base - The base address of the addressing mode, or null if 'constOnly' is false
2470 // constOnly - True if we will only traverse into ADDs with constant op2.
2472 // This routine is a helper routine for gtSetEvalOrder() and is used to identify the
2473 // base and index nodes, which will be validated against those identified by
2474 // genCreateAddrMode().
2475 // It also marks the ADD nodes involved in the address expression with the
2476 // GTF_ADDRMODE_NO_CSE flag which prevents them from being considered for CSE's.
2478 // Its two output parameters are modified under the following conditions:
2480 // It is called once with the original address expression as 'op1WB', and
2481 // with 'constOnly' set to false. On this first invocation, *op1WB is always
2482 // an ADD node, and it will consider the operands of the ADD even if its op2 is
2483 // not a constant. However, when it encounters a non-constant or the base in the
2484 // op2 position, it stops iterating. That operand is returned in the 'op2WB' out
2485 // parameter, and will be considered on the third invocation of this method if
2488 // It is called the second time with the two operands of the original expression, in
2489 // the original order, and the third time in reverse order. For these invocations
2490 // 'constOnly' is true, so it will only traverse cascaded ADD nodes if they have a
2493 // The result, after three invocations, is that the values of the two out parameters
2494 // correspond to the base and index in some fashion. This method doesn't attempt
2495 // to determine or validate the scale or offset, if any.
2497 // Assumptions (presumed to be ensured by genCreateAddrMode()):
2498 // If an ADD has a constant operand, it is in the op2 position.
2501 // This method, and its invocation sequence, are quite confusing, and since they
2502 // were not originally well-documented, this specification is a possibly-imperfect
2504 // The motivation for the handling of the NOP case is unclear.
2505 // Note that 'op2WB' is only modified in the initial (!constOnly) case,
2506 // or if a NOP is encountered in the op1 position.
2508 void Compiler::gtWalkOp(GenTree** op1WB, GenTree** op2WB, GenTree* base, bool constOnly)
2510 GenTree* op1 = *op1WB;
2511 GenTree* op2 = *op2WB;
2513 op1 = op1->gtEffectiveVal();
2515 // Now we look for op1's with non-overflow GT_ADDs [of constants]
2516 while ((op1->gtOper == GT_ADD) && (!op1->gtOverflow()) && (!constOnly || (op1->gtOp.gtOp2->IsCnsIntOrI())))
2518 // mark it with GTF_ADDRMODE_NO_CSE
2519 op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
2523 op2 = op1->gtOp.gtOp2;
2525 op1 = op1->gtOp.gtOp1;
2527 // If op1 is a GT_NOP then swap op1 and op2.
2528 // (Why? Also, presumably op2 is not a GT_NOP in this case?)
2529 if (op1->gtOper == GT_NOP)
2538 if (!constOnly && ((op2 == base) || (!op2->IsCnsIntOrI())))
2543 op1 = op1->gtEffectiveVal();
2551 /*****************************************************************************
2552 * This is a workaround. It is to help implement an assert in gtSetEvalOrder() that the values
2553 * gtWalkOp() leaves in op1 and op2 correspond with the values of adr, idx, mul, and cns
2554 * that are returned by genCreateAddrMode(). It's essentially impossible to determine
2555 * what gtWalkOp() *should* return for all possible trees. This simply loosens one assert
2556 * to handle the following case:
2559 const(h) int 4 field
2561 lclVar byref V00 this <-- op2
2562 comma byref <-- adr (base)
2564 lclVar byref V00 this
2566 const int 2 <-- mul == 4
2568 lclVar int V01 arg1 <-- idx
2570 * Here, we are planning to generate the address mode [edx+4*eax], where eax = idx and edx = the GT_COMMA expression.
2571 * To check adr equivalence with op2, we need to walk down the GT_ADD tree just like gtWalkOp() does.
2573 GenTree* Compiler::gtWalkOpEffectiveVal(GenTree* op)
2577 op = op->gtEffectiveVal();
2579 if ((op->gtOper != GT_ADD) || op->gtOverflow() || !op->gtOp.gtOp2->IsCnsIntOrI())
2584 op = op->gtOp.gtOp1;
2591 /*****************************************************************************
2593 * Given a tree, set the gtCostEx and gtCostSz fields which
2594 * are used to measure the relative costs of the codegen of the tree
2598 void Compiler::gtPrepareCost(GenTree* tree)
2600 gtSetEvalOrder(tree);
2603 bool Compiler::gtIsLikelyRegVar(GenTree* tree)
2605 if (tree->gtOper != GT_LCL_VAR)
2610 assert(tree->gtLclVar.gtLclNum < lvaTableCnt);
2611 LclVarDsc* varDsc = lvaTable + tree->gtLclVar.gtLclNum;
2613 if (varDsc->lvDoNotEnregister)
2618 // Be pessimistic if ref counts are not yet set up.
2620 // Perhaps we should be optimistic though.
2621 // See notes in GitHub issue 18969.
2622 if (!lvaLocalVarRefCounted())
2627 if (varDsc->lvRefCntWtd() < (BB_UNITY_WEIGHT * 3))
2633 if (varTypeIsFloating(tree->TypeGet()))
2635 if (varTypeIsLong(tree->TypeGet()))
2642 //------------------------------------------------------------------------
2643 // gtCanSwapOrder: Returns true iff the secondNode can be swapped with firstNode.
2646 // firstNode - An operand of a tree that can have GTF_REVERSE_OPS set.
2647 // secondNode - The other operand of the tree.
2650 // Returns a boolean indicating whether it is safe to reverse the execution
2651 // order of the two trees, considering any exception, global effects, or
2652 // ordering constraints.
2654 bool Compiler::gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode)
2656 // Relative of order of global / side effects can't be swapped.
2658 bool canSwap = true;
2660 if (optValnumCSE_phase)
2662 canSwap = optCSE_canSwap(firstNode, secondNode);
2665 // We cannot swap in the presence of special side effects such as GT_CATCH_ARG.
2667 if (canSwap && (firstNode->gtFlags & GTF_ORDER_SIDEEFF))
2672 // When strict side effect order is disabled we allow GTF_REVERSE_OPS to be set
2673 // when one or both sides contains a GTF_CALL or GTF_EXCEPT.
2674 // Currently only the C and C++ languages allow non strict side effect order.
2676 unsigned strictEffects = GTF_GLOB_EFFECT;
2678 if (canSwap && (firstNode->gtFlags & strictEffects))
2680 // op1 has side efects that can't be reordered.
2681 // Check for some special cases where we still may be able to swap.
2683 if (secondNode->gtFlags & strictEffects)
2685 // op2 has also has non reorderable side effects - can't swap.
2690 // No side effects in op2 - we can swap iff op1 has no way of modifying op2,
2691 // i.e. through byref assignments or calls or op2 is a constant.
2693 if (firstNode->gtFlags & strictEffects & GTF_PERSISTENT_SIDE_EFFECTS)
2695 // We have to be conservative - can swap iff op2 is constant.
2696 if (!secondNode->OperIsConst())
2706 //------------------------------------------------------------------------
2707 // Given an address expression, compute its costs and addressing mode opportunities,
2708 // and mark addressing mode candidates as GTF_DONT_CSE.
2711 // addr - The address expression
2712 // costEx - The execution cost of this address expression (in/out arg to be updated)
2713 // costEx - The size cost of this address expression (in/out arg to be updated)
2714 // type - The type of the value being referenced by the parent of this address expression.
2717 // Returns true if it finds an addressing mode.
2720 // TODO-Throughput - Consider actually instantiating these early, to avoid
2721 // having to re-run the algorithm that looks for them (might also improve CQ).
2723 bool Compiler::gtMarkAddrMode(GenTree* addr, int* pCostEx, int* pCostSz, var_types type)
2725 // These are "out" parameters on the call to genCreateAddrMode():
2726 bool rev; // This will be true if the operands will need to be reversed. At this point we
2727 // don't care about this because we're not yet instantiating this addressing mode.
2728 #if SCALED_ADDR_MODES
2729 unsigned mul; // This is the index (scale) value for the addressing mode
2731 ssize_t cns; // This is the constant offset
2732 GenTree* base; // This is the base of the address.
2733 GenTree* idx; // This is the index.
2735 if (codeGen->genCreateAddrMode(addr, false /*fold*/, &rev, &base, &idx,
2736 #if SCALED_ADDR_MODES
2738 #endif // SCALED_ADDR_MODES
2741 // We can form a complex addressing mode, so mark each of the interior
2742 // nodes with GTF_ADDRMODE_NO_CSE and calculate a more accurate cost.
2744 addr->gtFlags |= GTF_ADDRMODE_NO_CSE;
2745 #ifdef _TARGET_XARCH_
2746 // addrmodeCount is the count of items that we used to form
2747 // an addressing mode. The maximum value is 4 when we have
2748 // all of these: { base, idx, cns, mul }
2750 unsigned addrmodeCount = 0;
2753 *pCostEx += base->gtCostEx;
2754 *pCostSz += base->gtCostSz;
2760 *pCostEx += idx->gtCostEx;
2761 *pCostSz += idx->gtCostSz;
2767 if (((signed char)cns) == ((int)cns))
2781 // When we form a complex addressing mode we can reduced the costs
2782 // associated with the interior GT_ADD and GT_LSH nodes:
2784 // GT_ADD -- reduce this interior GT_ADD by (-3,-3)
2786 // GT_ADD 'cns' -- reduce this interior GT_ADD by (-2,-2)
2788 // 'base' GT_LSL -- reduce this interior GT_LSL by (-1,-1)
2792 if (addrmodeCount > 1)
2794 // The number of interior GT_ADD and GT_LSL will always be one less than addrmodeCount
2798 GenTree* tmp = addr;
2799 while (addrmodeCount > 0)
2801 // decrement the gtCosts for the interior GT_ADD or GT_LSH node by the remaining
2803 tmp->SetCosts(tmp->gtCostEx - addrmodeCount, tmp->gtCostSz - addrmodeCount);
2806 if (addrmodeCount > 0)
2808 GenTree* tmpOp1 = tmp->gtOp.gtOp1;
2809 GenTree* tmpOp2 = tmp->gtGetOp2();
2810 assert(tmpOp2 != nullptr);
2812 if ((tmpOp1 != base) && (tmpOp1->OperGet() == GT_ADD))
2816 else if (tmpOp2->OperGet() == GT_LSH)
2820 else if (tmpOp1->OperGet() == GT_LSH)
2824 else if (tmpOp2->OperGet() == GT_ADD)
2830 // We can very rarely encounter a tree that has a GT_COMMA node
2831 // that is difficult to walk, so we just early out without decrementing.
2837 #elif defined _TARGET_ARM_
2840 *pCostEx += base->gtCostEx;
2841 *pCostSz += base->gtCostSz;
2842 if ((base->gtOper == GT_LCL_VAR) && ((idx == NULL) || (cns == 0)))
2850 *pCostEx += idx->gtCostEx;
2851 *pCostSz += idx->gtCostSz;
2860 if (cns >= 128) // small offsets fits into a 16-bit instruction
2862 if (cns < 4096) // medium offsets require a 32-bit instruction
2864 if (!varTypeIsFloating(type))
2871 *pCostEx += 2; // Very large offsets require movw/movt instructions
2876 #elif defined _TARGET_ARM64_
2879 *pCostEx += base->gtCostEx;
2880 *pCostSz += base->gtCostSz;
2885 *pCostEx += idx->gtCostEx;
2886 *pCostSz += idx->gtCostSz;
2891 if (cns >= (4096 * genTypeSize(type)))
2898 #error "Unknown _TARGET_"
2901 assert(addr->gtOper == GT_ADD);
2902 assert(!addr->gtOverflow());
2905 // If we have an addressing mode, we have one of:
2907 // [ idx * mul ] // mul >= 2, else we would use base instead of idx
2908 // [ idx * mul + cns] // mul >= 2, else we would use base instead of idx
2909 // [base + idx * mul ] // mul can be 0, 2, 4, or 8
2910 // [base + idx * mul + cns] // mul can be 0, 2, 4, or 8
2911 // Note that mul == 0 is semantically equivalent to mul == 1.
2912 // Note that cns can be zero.
2913 CLANG_FORMAT_COMMENT_ANCHOR;
2915 #if SCALED_ADDR_MODES
2916 assert((base != nullptr) || (idx != nullptr && mul >= 2));
2918 assert(base != NULL);
2921 INDEBUG(GenTree* op1Save = addr);
2923 // Walk 'addr' identifying non-overflow ADDs that will be part of the address mode.
2924 // Note that we will be modifying 'op1' and 'op2' so that eventually they should
2925 // map to the base and index.
2926 GenTree* op1 = addr;
2927 GenTree* op2 = nullptr;
2928 gtWalkOp(&op1, &op2, base, false);
2930 // op1 and op2 are now descendents of the root GT_ADD of the addressing mode.
2931 assert(op1 != op1Save);
2932 assert(op2 != nullptr);
2934 // Walk the operands again (the third operand is unused in this case).
2935 // This time we will only consider adds with constant op2's, since
2936 // we have already found either a non-ADD op1 or a non-constant op2.
2937 gtWalkOp(&op1, &op2, nullptr, true);
2939 #if defined(_TARGET_XARCH_)
2940 // For XARCH we will fold GT_ADDs in the op2 position into the addressing mode, so we call
2941 // gtWalkOp on both operands of the original GT_ADD.
2942 // This is not done for ARMARCH. Though the stated reason is that we don't try to create a
2943 // scaled index, in fact we actually do create them (even base + index*scale + offset).
2945 // At this point, 'op2' may itself be an ADD of a constant that should be folded
2946 // into the addressing mode.
2947 // Walk op2 looking for non-overflow GT_ADDs of constants.
2948 gtWalkOp(&op2, &op1, nullptr, true);
2949 #endif // defined(_TARGET_XARCH_)
2951 // OK we are done walking the tree
2952 // Now assert that op1 and op2 correspond with base and idx
2953 // in one of the several acceptable ways.
2955 // Note that sometimes op1/op2 is equal to idx/base
2956 // and other times op1/op2 is a GT_COMMA node with
2957 // an effective value that is idx/base
2961 if ((op1 != base) && (op1->gtOper == GT_LSH))
2963 op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
2964 if (op1->gtOp.gtOp1->gtOper == GT_MUL)
2966 op1->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
2968 assert((base == nullptr) || (op2 == base) || (op2->gtEffectiveVal() == base->gtEffectiveVal()) ||
2969 (gtWalkOpEffectiveVal(op2) == gtWalkOpEffectiveVal(base)));
2974 assert(op2->gtOper == GT_LSH || op2->gtOper == GT_MUL);
2975 op2->gtFlags |= GTF_ADDRMODE_NO_CSE;
2976 // We may have eliminated multiple shifts and multiplies in the addressing mode,
2977 // so navigate down through them to get to "idx".
2978 GenTree* op2op1 = op2->gtOp.gtOp1;
2979 while ((op2op1->gtOper == GT_LSH || op2op1->gtOper == GT_MUL) && op2op1 != idx)
2981 op2op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
2982 op2op1 = op2op1->gtOp.gtOp1;
2984 assert(op1->gtEffectiveVal() == base);
2985 assert(op2op1 == idx);
2992 if ((op1 == idx) || (op1->gtEffectiveVal() == idx))
2996 if ((op1->gtOper == GT_MUL) || (op1->gtOper == GT_LSH))
2998 if ((op1->gtOp.gtOp1->gtOper == GT_NOP) ||
2999 (op1->gtOp.gtOp1->gtOper == GT_MUL && op1->gtOp.gtOp1->gtOp.gtOp1->gtOper == GT_NOP))
3001 op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3002 if (op1->gtOp.gtOp1->gtOper == GT_MUL)
3004 op1->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3009 assert((op2 == base) || (op2->gtEffectiveVal() == base));
3011 else if ((op1 == base) || (op1->gtEffectiveVal() == base))
3016 if ((op2->gtOper == GT_MUL) || (op2->gtOper == GT_LSH))
3018 if ((op2->gtOp.gtOp1->gtOper == GT_NOP) ||
3019 (op2->gtOp.gtOp1->gtOper == GT_MUL && op2->gtOp.gtOp1->gtOp.gtOp1->gtOper == GT_NOP))
3021 op2->gtFlags |= GTF_ADDRMODE_NO_CSE;
3022 if (op2->gtOp.gtOp1->gtOper == GT_MUL)
3024 op2->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3028 assert((op2 == idx) || (op2->gtEffectiveVal() == idx));
3033 // op1 isn't base or idx. Is this possible? Or should there be an assert?
3038 } // end if (genCreateAddrMode(...))
3042 /*****************************************************************************
3044 * Given a tree, figure out the order in which its sub-operands should be
3045 * evaluated. If the second operand of a binary operator is more expensive
3046 * than the first operand, then try to swap the operand trees. Updates the
3047 * GTF_REVERSE_OPS bit if necessary in this case.
3049 * Returns the Sethi 'complexity' estimate for this tree (the higher
3050 * the number, the higher is the tree's resources requirement).
3052 * This function sets:
3053 * 1. gtCostEx to the execution complexity estimate
3054 * 2. gtCostSz to the code size estimate
3055 * 3. Sometimes sets GTF_ADDRMODE_NO_CSE on nodes in the tree.
3056 * 4. DEBUG-only: clears GTF_DEBUG_NODE_MORPHED.
3060 #pragma warning(push)
3061 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
3063 unsigned Compiler::gtSetEvalOrder(GenTree* tree)
3066 assert(tree->gtOper != GT_STMT);
3069 /* Clear the GTF_DEBUG_NODE_MORPHED flag as well */
3070 tree->gtDebugFlags &= ~GTF_DEBUG_NODE_MORPHED;
3073 /* Is this a FP value? */
3075 bool isflt = varTypeIsFloating(tree->TypeGet());
3077 /* Figure out what kind of a node we have */
3079 const genTreeOps oper = tree->OperGet();
3080 const unsigned kind = tree->OperKind();
3082 /* Assume no fixed registers will be trashed */
3093 /* Is this a constant or a leaf node? */
3095 if (kind & (GTK_LEAF | GTK_CONST))
3113 // If the constant is a handle then it will need to have a relocation
3115 // Any constant that requires a reloc must use the movw/movt sequence
3117 GenTreeIntConCommon* con = tree->AsIntConCommon();
3119 if (con->ImmedValNeedsReloc(this) ||
3120 !codeGen->validImmForInstr(INS_mov, (target_ssize_t)tree->gtIntCon.gtIconVal))
3126 else if (((unsigned)tree->gtIntCon.gtIconVal) <= 0x00ff)
3141 #elif defined _TARGET_XARCH_
3155 // If the constant is a handle then it will need to have a relocation
3158 GenTreeIntConCommon* con = tree->AsIntConCommon();
3160 bool iconNeedsReloc = con->ImmedValNeedsReloc(this);
3162 if (!iconNeedsReloc && con->FitsInI8())
3167 #if defined(_TARGET_AMD64_)
3168 else if (iconNeedsReloc || !con->FitsInI32())
3173 #endif // _TARGET_AMD64_
3182 #elif defined(_TARGET_ARM64_)
3186 // TODO-ARM64-NYI: Need cost estimates.
3195 #error "Unknown _TARGET_"
3200 Note that some code below depends on constants always getting
3201 moved to be the second operand of a binary operator. This is
3202 easily accomplished by giving constants a level of 0, which
3203 we do on the next line. If you ever decide to change this, be
3204 aware that unless you make other arrangements for integer
3205 constants to be moved, stuff will break.
3213 /* We use fldz and fld1 to load 0.0 and 1.0, but all other */
3214 /* floating point constants are loaded using an indirection */
3215 if ((*((__int64*)&(tree->gtDblCon.gtDconVal)) == 0) ||
3216 (*((__int64*)&(tree->gtDblCon.gtDconVal)) == I64(0x3ff0000000000000)))
3223 costEx = IND_COST_EX;
3230 if (gtIsLikelyRegVar(tree))
3234 /* Sign-extend and zero-extend are more expensive to load */
3235 if (lvaTable[tree->gtLclVar.gtLclNum].lvNormalizeOnLoad())
3243 costEx = IND_COST_EX;
3245 /* Sign-extend and zero-extend are more expensive to load */
3246 if (varTypeIsSmall(tree->TypeGet()))
3252 #if defined(_TARGET_AMD64_)
3253 // increase costSz for floating point locals
3257 if (!gtIsLikelyRegVar(tree))
3267 // We generate movw/movt/ldr
3269 costEx = 3 + IND_COST_EX; // 6
3270 costSz = 4 + 4 + 2; // 10
3275 costEx = IND_COST_EX;
3277 if (varTypeIsSmall(tree->TypeGet()))
3300 /* Is it a 'simple' unary/binary operator? */
3302 if (kind & GTK_SMPOP)
3304 int lvlb; // preference for op2
3305 unsigned lvl2; // scratch variable
3307 GenTree* op1 = tree->gtOp.gtOp1;
3308 GenTree* op2 = tree->gtGetOp2IfPresent();
3313 if (tree->OperIsAddrMode())
3322 /* Check for a nilary operator */
3326 assert(op2 == nullptr);
3333 /* Is this a unary operator? */
3337 /* Process the operand of the operator */
3339 /* Most Unary ops have costEx of 1 */
3343 level = gtSetEvalOrder(op1);
3345 /* Special handling for some operators */
3360 #if defined(_TARGET_ARM_)
3363 if (isflt || varTypeIsFloating(op1->TypeGet()))
3368 #elif defined(_TARGET_ARM64_)
3371 if (isflt || varTypeIsFloating(op1->TypeGet()))
3376 #elif defined(_TARGET_XARCH_)
3380 if (isflt || varTypeIsFloating(op1->TypeGet()))
3382 /* cast involving floats always go through memory */
3383 costEx = IND_COST_EX * 2;
3387 #error "Unknown _TARGET_"
3390 /* Overflow casts are a lot more expensive */
3391 if (tree->gtOverflow())
3407 // GT_INTRINSIC intrinsics Sin, Cos, Sqrt, Abs ... have higher costs.
3408 // TODO: tune these costs target specific as some of these are
3409 // target intrinsics and would cost less to generate code.
3410 switch (tree->gtIntrinsic.gtIntrinsicId)
3413 assert(!"missing case for gtIntrinsicId");
3418 case CORINFO_INTRINSIC_Sin:
3419 case CORINFO_INTRINSIC_Cos:
3420 case CORINFO_INTRINSIC_Sqrt:
3421 case CORINFO_INTRINSIC_Cbrt:
3422 case CORINFO_INTRINSIC_Cosh:
3423 case CORINFO_INTRINSIC_Sinh:
3424 case CORINFO_INTRINSIC_Tan:
3425 case CORINFO_INTRINSIC_Tanh:
3426 case CORINFO_INTRINSIC_Asin:
3427 case CORINFO_INTRINSIC_Asinh:
3428 case CORINFO_INTRINSIC_Acos:
3429 case CORINFO_INTRINSIC_Acosh:
3430 case CORINFO_INTRINSIC_Atan:
3431 case CORINFO_INTRINSIC_Atanh:
3432 case CORINFO_INTRINSIC_Atan2:
3433 case CORINFO_INTRINSIC_Log10:
3434 case CORINFO_INTRINSIC_Pow:
3435 case CORINFO_INTRINSIC_Exp:
3436 case CORINFO_INTRINSIC_Ceiling:
3437 case CORINFO_INTRINSIC_Floor:
3438 case CORINFO_INTRINSIC_Object_GetType:
3439 // Giving intrinsics a large fixed execution cost is because we'd like to CSE
3440 // them, even if they are implemented by calls. This is different from modeling
3441 // user calls since we never CSE user calls.
3446 case CORINFO_INTRINSIC_Abs:
3451 case CORINFO_INTRINSIC_Round:
3461 // We need to ensure that -x is evaluated before x or else
3462 // we get burned while adjusting genFPstkLevel in x*-x where
3463 // the rhs x is the last use of the enregistered x.
3465 // Even in the integer case we want to prefer to
3466 // evaluate the side without the GT_NEG node, all other things
3467 // being equal. Also a GT_NOT requires a scratch register
3477 // If we have a GT_ADDR of an GT_IND we can just copy the costs from indOp1
3478 if (op1->OperGet() == GT_IND)
3480 GenTree* indOp1 = op1->gtOp.gtOp1;
3481 costEx = indOp1->gtCostEx;
3482 costSz = indOp1->gtCostSz;
3489 /* Array Len should be the same as an indirections, which have a costEx of IND_COST_EX */
3490 costEx = IND_COST_EX - 1;
3496 // We estimate the cost of a GT_OBJ or GT_MKREFANY to be two loads (GT_INDs)
3497 costEx = 2 * IND_COST_EX;
3502 // We estimate the cost of a GT_BOX to be two stores (GT_INDs)
3503 costEx = 2 * IND_COST_EX;
3507 #if defined(FEATURE_HW_INTRINSICS) && defined(_TARGET_XARCH_)
3508 case GT_HWIntrinsic:
3510 if (tree->AsHWIntrinsic()->OperIsMemoryLoadOrStore())
3512 costEx = IND_COST_EX;
3514 // See if we can form a complex addressing mode.
3516 GenTree* addr = op1->gtEffectiveVal();
3518 if (addr->OperIs(GT_ADD) && gtMarkAddrMode(addr, &costEx, &costSz, tree->TypeGet()))
3525 #endif // FEATURE_HW_INTRINSICS && _TARGET_XARCH_
3530 /* An indirection should always have a non-zero level.
3531 * Only constant leaf nodes have level 0.
3539 /* Indirections have a costEx of IND_COST_EX */
3540 costEx = IND_COST_EX;
3543 /* If we have to sign-extend or zero-extend, bump the cost */
3544 if (varTypeIsSmall(tree->TypeGet()))
3552 if (tree->TypeGet() == TYP_DOUBLE)
3558 #endif // _TARGET_ARM_
3561 // Can we form an addressing mode with this indirection?
3562 // TODO-CQ: Consider changing this to op1->gtEffectiveVal() to take into account
3563 // addressing modes hidden under a comma node.
3565 if (op1->gtOper == GT_ADD)
3567 // See if we can form a complex addressing mode.
3569 GenTree* addr = op1->gtEffectiveVal();
3571 bool doAddrMode = true;
3572 // See if we can form a complex addressing mode.
3573 // Always use an addrMode for an array index indirection.
3574 // TODO-1stClassStructs: Always do this, but first make sure it's
3575 // done in Lowering as well.
3576 if ((tree->gtFlags & GTF_IND_ARR_INDEX) == 0)
3578 if (tree->TypeGet() == TYP_STRUCT)
3582 else if (varTypeIsStruct(tree))
3584 // This is a heuristic attempting to match prior behavior when indirections
3585 // under a struct assignment would not be considered for addressing modes.
3586 if (compCurStmt != nullptr)
3588 GenTree* expr = compCurStmt->gtStmtExpr;
3589 if ((expr->OperGet() == GT_ASG) &&
3590 ((expr->gtGetOp1() == tree) || (expr->gtGetOp2() == tree)))
3597 if (doAddrMode && gtMarkAddrMode(addr, &costEx, &costSz, tree->TypeGet()))
3601 } // end if (op1->gtOper == GT_ADD)
3602 else if (gtIsLikelyRegVar(op1))
3604 /* Indirection of an enregister LCL_VAR, don't increase costEx/costSz */
3607 #ifdef _TARGET_XARCH_
3608 else if (op1->IsCnsIntOrI())
3610 // Indirection of a CNS_INT, subtract 1 from costEx
3611 // makes costEx 3 for x86 and 4 for amd64
3613 costEx += (op1->gtCostEx - 1);
3614 costSz += op1->gtCostSz;
3623 costEx += op1->gtCostEx;
3624 costSz += op1->gtCostSz;
3628 /* Binary operator - check for certain special cases */
3632 /* Default Binary ops have a cost of 1,1 */
3642 #ifndef _TARGET_64BIT_
3643 if (varTypeIsLong(op1->TypeGet()))
3645 /* Operations on longs are more expensive */
3655 /* Modulo by a power of 2 is easy */
3657 if (op2->IsCnsIntOrI())
3659 size_t ival = op2->gtIntConCommon.IconValue();
3661 if (ival > 0 && ival == genFindLowestBit(ival))
3674 /* fp division is very expensive to execute */
3675 costEx = 36; // TYP_DOUBLE
3680 /* integer division is also very expensive */
3684 // Encourage the first operand to be evaluated (into EAX/EDX) first */
3693 /* FP multiplication instructions are more expensive */
3699 /* Integer multiplication instructions are more expensive */
3703 if (tree->gtOverflow())
3705 /* Overflow check are more expensive */
3711 if ((tree->gtType == TYP_LONG) || tree->gtOverflow())
3713 /* We use imulEAX for TYP_LONG and overflow multiplications */
3714 // Encourage the first operand to be evaluated (into EAX/EDX) first */
3717 /* The 64-bit imul instruction costs more */
3720 #endif // _TARGET_X86_
3728 /* FP instructions are a bit more expensive */
3734 /* Overflow check are more expensive */
3735 if (tree->gtOverflow())
3744 /* Comma tosses the result of the left operand */
3745 gtSetEvalOrder(op1);
3746 level = gtSetEvalOrder(op2);
3748 /* GT_COMMA cost is the sum of op1 and op2 costs */
3749 costEx = (op1->gtCostEx + op2->gtCostEx);
3750 costSz = (op1->gtCostSz + op2->gtCostSz);
3756 level = gtSetEvalOrder(op1);
3757 lvl2 = gtSetEvalOrder(op2);
3763 else if (level == lvl2)
3768 costEx = op1->gtCostEx + op2->gtCostEx;
3769 costSz = op1->gtCostSz + op2->gtCostSz;
3776 const bool isListCallArgs = false;
3777 const bool callArgsInRegs = false;
3778 return gtSetListOrder(tree, isListCallArgs, callArgsInRegs);
3782 /* Assignments need a bit of special handling */
3783 /* Process the target */
3784 level = gtSetEvalOrder(op1);
3786 if (gtIsLikelyRegVar(op1))
3789 lvl2 = gtSetEvalOrder(op2);
3791 /* Assignment to an enregistered LCL_VAR */
3792 costEx = op2->gtCostEx;
3793 costSz = max(3, op2->gtCostSz); // 3 is an estimate for a reg-reg assignment
3794 goto DONE_OP1_AFTER_COST;
3802 /* Process the sub-operands */
3804 level = gtSetEvalOrder(op1);
3807 level -= lvlb; // lvlb is negative, so this increases level
3813 lvl2 = gtSetEvalOrder(op2) + lvlb;
3815 costEx += (op1->gtCostEx + op2->gtCostEx);
3816 costSz += (op1->gtCostSz + op2->gtCostSz);
3818 DONE_OP1_AFTER_COST:
3820 bool bReverseInAssignment = false;
3823 GenTree* op1Val = op1;
3825 // Skip over the GT_IND/GT_ADDR tree (if one exists)
3827 if ((op1->gtOper == GT_IND) && (op1->gtOp.gtOp1->gtOper == GT_ADDR))
3829 op1Val = op1->gtOp.gtOp1->gtOp.gtOp1;
3832 switch (op1Val->gtOper)
3839 // In an indirection, the destination address is evaluated prior to the source.
3840 // If we have any side effects on the target indirection,
3841 // we have to evaluate op1 first.
3842 // However, if the LHS is a lclVar address, SSA relies on using evaluation order for its
3843 // renaming, and therefore the RHS must be evaluated first.
3844 // If we have an assignment involving a lclVar address, the LHS may be marked as having
3846 // However the side-effects won't require that we evaluate the LHS address first:
3847 // - The GTF_GLOB_REF might have been conservatively set on a FIELD of a local.
3848 // - The local might be address-exposed, but that side-effect happens at the actual assignment (not
3849 // when its address is "evaluated") so it doesn't change the side effect to "evaluate" the address
3850 // after the RHS (note that in this case it won't be renamed by SSA anyway, but the reordering is
3853 if (op1Val->AsIndir()->Addr()->IsLocalAddrExpr())
3855 bReverseInAssignment = true;
3856 tree->gtFlags |= GTF_REVERSE_OPS;
3859 if (op1Val->AsIndir()->Addr()->gtFlags & GTF_ALL_EFFECT)
3864 // In case op2 assigns to a local var that is used in op1Val, we have to evaluate op1Val first.
3865 if (op2->gtFlags & GTF_ASG)
3870 // If op2 is simple then evaluate op1 first
3872 if (op2->OperKind() & GTK_LEAF)
3877 // fall through and set GTF_REVERSE_OPS
3882 // We evaluate op2 before op1
3883 bReverseInAssignment = true;
3884 tree->gtFlags |= GTF_REVERSE_OPS;
3891 else if (kind & GTK_RELOP)
3893 /* Float compares remove both operands from the FP stack */
3894 /* Also FP comparison uses EAX for flags */
3896 if (varTypeIsFloating(op1->TypeGet()))
3901 if ((tree->gtFlags & GTF_RELOP_JMP_USED) == 0)
3903 /* Using a setcc instruction is more expensive */
3908 /* Check for other interesting cases */
3917 /* Variable sized shifts are more expensive and use REG_SHIFT */
3919 if (!op2->IsCnsIntOrI())
3922 #ifndef _TARGET_64BIT_
3923 // Variable sized LONG shifts require the use of a helper call
3925 if (tree->gtType == TYP_LONG)
3929 costEx += 3 * IND_COST_EX;
3932 #endif // !_TARGET_64BIT_
3938 switch (tree->gtIntrinsic.gtIntrinsicId)
3940 case CORINFO_INTRINSIC_Atan2:
3941 case CORINFO_INTRINSIC_Pow:
3942 // These math intrinsics are actually implemented by user calls.
3943 // Increase the Sethi 'complexity' by two to reflect the argument
3944 // register requirement.
3948 assert(!"Unknown binary GT_INTRINSIC operator");
3958 /* We need to evalutate constants later as many places in codegen
3959 can't handle op1 being a constant. This is normally naturally
3960 enforced as constants have the least level of 0. However,
3961 sometimes we end up with a tree like "cns1 < nop(cns2)". In
3962 such cases, both sides have a level of 0. So encourage constants
3963 to be evaluated last in such cases */
3965 if ((level == 0) && (level == lvl2) && (op1->OperKind() & GTK_CONST) &&
3966 (tree->OperIsCommutative() || tree->OperIsCompare()))
3971 /* We try to swap operands if the second one is more expensive */
3976 if (tree->gtFlags & GTF_REVERSE_OPS)
3987 if (fgOrder == FGOrderLinear)
3989 // Don't swap anything if we're in linear order; we're really just interested in the costs.
3992 else if (bReverseInAssignment)
3994 // Assignments are special, we want the reverseops flags
3995 // so if possible it was set above.
3998 else if ((oper == GT_INTRINSIC) && IsIntrinsicImplementedByUserCall(tree->AsIntrinsic()->gtIntrinsicId))
4000 // We do not swap operand execution order for intrinsics that are implemented by user calls
4001 // because of trickiness around ensuring the execution order does not change during rationalization.
4006 if (tree->gtFlags & GTF_REVERSE_OPS)
4008 tryToSwap = (level > lvl2);
4012 tryToSwap = (level < lvl2);
4015 // Try to force extra swapping when in the stress mode:
4016 if (compStressCompile(STRESS_REVERSE_FLAG, 60) && ((tree->gtFlags & GTF_REVERSE_OPS) == 0) &&
4017 ((op2->OperKind() & GTK_CONST) == 0))
4025 bool canSwap = gtCanSwapOrder(opA, opB);
4029 /* Can we swap the order by commuting the operands? */
4039 if (GenTree::SwapRelop(oper) != oper)
4041 tree->SetOper(GenTree::SwapRelop(oper), GenTree::PRESERVE_VN);
4053 /* Swap the operands */
4055 tree->gtOp.gtOp1 = op2;
4056 tree->gtOp.gtOp2 = op1;
4070 /* Mark the operand's evaluation order to be swapped */
4071 if (tree->gtFlags & GTF_REVERSE_OPS)
4073 tree->gtFlags &= ~GTF_REVERSE_OPS;
4077 tree->gtFlags |= GTF_REVERSE_OPS;
4085 /* Swap the level counts */
4086 if (tree->gtFlags & GTF_REVERSE_OPS)
4095 /* Compute the sethi number for this binary operator */
4101 else if (level == lvl2)
4109 /* See what kind of a special operator we have here */
4113 unsigned lvl2; // Scratch variable
4117 assert(tree->gtFlags & GTF_CALL);
4123 /* Evaluate the 'this' argument, if present */
4125 if (tree->gtCall.gtCallObjp)
4127 GenTree* thisVal = tree->gtCall.gtCallObjp;
4129 lvl2 = gtSetEvalOrder(thisVal);
4134 costEx += thisVal->gtCostEx;
4135 costSz += thisVal->gtCostSz + 1;
4138 /* Evaluate the arguments, right to left */
4140 if (tree->gtCall.gtCallArgs)
4142 const bool isListCallArgs = true;
4143 const bool callArgsInRegs = false;
4144 lvl2 = gtSetListOrder(tree->gtCall.gtCallArgs, isListCallArgs, callArgsInRegs);
4149 costEx += tree->gtCall.gtCallArgs->gtCostEx;
4150 costSz += tree->gtCall.gtCallArgs->gtCostSz;
4153 /* Evaluate the temp register arguments list
4154 * This is a "hidden" list and its only purpose is to
4155 * extend the life of temps until we make the call */
4157 if (tree->gtCall.gtCallLateArgs)
4159 const bool isListCallArgs = true;
4160 const bool callArgsInRegs = true;
4161 lvl2 = gtSetListOrder(tree->gtCall.gtCallLateArgs, isListCallArgs, callArgsInRegs);
4166 costEx += tree->gtCall.gtCallLateArgs->gtCostEx;
4167 costSz += tree->gtCall.gtCallLateArgs->gtCostSz;
4170 if (tree->gtCall.gtCallType == CT_INDIRECT)
4172 // pinvoke-calli cookie is a constant, or constant indirection
4173 assert(tree->gtCall.gtCallCookie == nullptr || tree->gtCall.gtCallCookie->gtOper == GT_CNS_INT ||
4174 tree->gtCall.gtCallCookie->gtOper == GT_IND);
4176 GenTree* indirect = tree->gtCall.gtCallAddr;
4178 lvl2 = gtSetEvalOrder(indirect);
4183 costEx += indirect->gtCostEx + IND_COST_EX;
4184 costSz += indirect->gtCostSz;
4189 if (tree->gtCall.IsVirtualStub())
4191 // We generate movw/movt/ldr
4192 costEx += (1 + IND_COST_EX);
4194 if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT)
4196 // Must use R12 for the ldr target -- REG_JUMP_THUNK_PARAM
4200 else if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
4207 #ifdef _TARGET_XARCH_
4214 /* Virtual calls are a bit more expensive */
4215 if (tree->gtCall.IsVirtual())
4217 costEx += 2 * IND_COST_EX;
4222 costEx += 3 * IND_COST_EX;
4227 level = gtSetEvalOrder(tree->gtArrElem.gtArrObj);
4228 costEx = tree->gtArrElem.gtArrObj->gtCostEx;
4229 costSz = tree->gtArrElem.gtArrObj->gtCostSz;
4232 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
4234 lvl2 = gtSetEvalOrder(tree->gtArrElem.gtArrInds[dim]);
4239 costEx += tree->gtArrElem.gtArrInds[dim]->gtCostEx;
4240 costSz += tree->gtArrElem.gtArrInds[dim]->gtCostSz;
4243 level += tree->gtArrElem.gtArrRank;
4244 costEx += 2 + (tree->gtArrElem.gtArrRank * (IND_COST_EX + 1));
4245 costSz += 2 + (tree->gtArrElem.gtArrRank * 2);
4249 level = gtSetEvalOrder(tree->gtArrOffs.gtOffset);
4250 costEx = tree->gtArrOffs.gtOffset->gtCostEx;
4251 costSz = tree->gtArrOffs.gtOffset->gtCostSz;
4252 lvl2 = gtSetEvalOrder(tree->gtArrOffs.gtIndex);
4253 level = max(level, lvl2);
4254 costEx += tree->gtArrOffs.gtIndex->gtCostEx;
4255 costSz += tree->gtArrOffs.gtIndex->gtCostSz;
4256 lvl2 = gtSetEvalOrder(tree->gtArrOffs.gtArrObj);
4257 level = max(level, lvl2);
4258 costEx += tree->gtArrOffs.gtArrObj->gtCostEx;
4259 costSz += tree->gtArrOffs.gtArrObj->gtCostSz;
4264 level = gtSetEvalOrder(tree->gtCmpXchg.gtOpLocation);
4265 costSz = tree->gtCmpXchg.gtOpLocation->gtCostSz;
4267 lvl2 = gtSetEvalOrder(tree->gtCmpXchg.gtOpValue);
4272 costSz += tree->gtCmpXchg.gtOpValue->gtCostSz;
4274 lvl2 = gtSetEvalOrder(tree->gtCmpXchg.gtOpComparand);
4279 costSz += tree->gtCmpXchg.gtOpComparand->gtCostSz;
4281 costEx = MAX_COST; // Seriously, what could be more expensive than lock cmpxchg?
4282 costSz += 5; // size of lock cmpxchg [reg+C], reg
4285 case GT_ARR_BOUNDS_CHECK:
4288 #endif // FEATURE_SIMD
4289 #ifdef FEATURE_HW_INTRINSICS
4290 case GT_HW_INTRINSIC_CHK:
4291 #endif // FEATURE_HW_INTRINSICS
4293 costEx = 4; // cmp reg,reg and jae throw (not taken)
4294 costSz = 7; // jump to cold section
4296 level = gtSetEvalOrder(tree->gtBoundsChk.gtIndex);
4297 costEx += tree->gtBoundsChk.gtIndex->gtCostEx;
4298 costSz += tree->gtBoundsChk.gtIndex->gtCostSz;
4300 lvl2 = gtSetEvalOrder(tree->gtBoundsChk.gtArrLen);
4305 costEx += tree->gtBoundsChk.gtArrLen->gtCostEx;
4306 costSz += tree->gtBoundsChk.gtArrLen->gtCostSz;
4310 case GT_STORE_DYN_BLK:
4316 if (oper == GT_STORE_DYN_BLK)
4318 lvl2 = gtSetEvalOrder(tree->gtDynBlk.Data());
4319 level = max(level, lvl2);
4320 costEx += tree->gtDynBlk.Data()->gtCostEx;
4321 costSz += tree->gtDynBlk.Data()->gtCostSz;
4323 lvl2 = gtSetEvalOrder(tree->gtDynBlk.Addr());
4324 level = max(level, lvl2);
4325 costEx = tree->gtDynBlk.Addr()->gtCostEx;
4326 costSz = tree->gtDynBlk.Addr()->gtCostSz;
4327 unsigned sizeLevel = gtSetEvalOrder(tree->gtDynBlk.gtDynamicSize);
4329 // Determine whether the size node should be evaluated first.
4330 // We would like to do this if the sizeLevel is larger than the current level,
4331 // but we have to ensure that we obey ordering constraints.
4332 if (tree->AsDynBlk()->gtEvalSizeFirst != (level < sizeLevel))
4334 bool canChange = true;
4336 GenTree* sizeNode = tree->AsDynBlk()->gtDynamicSize;
4337 GenTree* dst = tree->AsDynBlk()->Addr();
4338 GenTree* src = tree->AsDynBlk()->Data();
4340 if (tree->AsDynBlk()->gtEvalSizeFirst)
4342 canChange = gtCanSwapOrder(sizeNode, dst);
4343 if (canChange && (src != nullptr))
4345 canChange = gtCanSwapOrder(sizeNode, src);
4350 canChange = gtCanSwapOrder(dst, sizeNode);
4351 if (canChange && (src != nullptr))
4353 gtCanSwapOrder(src, sizeNode);
4358 tree->AsDynBlk()->gtEvalSizeFirst = (level < sizeLevel);
4361 level = max(level, sizeLevel);
4362 costEx += tree->gtDynBlk.gtDynamicSize->gtCostEx;
4363 costSz += tree->gtDynBlk.gtDynamicSize->gtCostSz;
4368 costEx = 6; // cmp reg,reg; jae throw; mov reg, [addrmode] (not taken)
4369 costSz = 9; // jump to cold section
4371 level = gtSetEvalOrder(tree->AsIndexAddr()->Index());
4372 costEx += tree->AsIndexAddr()->Index()->gtCostEx;
4373 costSz += tree->AsIndexAddr()->Index()->gtCostSz;
4375 lvl2 = gtSetEvalOrder(tree->AsIndexAddr()->Arr());
4380 costEx += tree->AsIndexAddr()->Arr()->gtCostEx;
4381 costSz += tree->AsIndexAddr()->Arr()->gtCostSz;
4388 printf("unexpected operator in this tree:\n");
4392 NO_WAY("unexpected operator");
4397 #ifdef FEATURE_HW_INTRINSICS
4398 if ((oper == GT_HWIntrinsic) && (tree->gtGetOp1() == nullptr))
4400 // We can have nullary HWIntrinsic nodes, and we must have non-zero cost.
4404 #endif // FEATURE_HW_INTRINSICS
4406 // Some path through this function must have set the costs.
4407 assert(costEx != -1);
4408 assert(costSz != -1);
4410 tree->SetCosts(costEx, costSz);
4415 #pragma warning(pop)
4418 /*****************************************************************************
4420 * If the given tree is an integer constant that can be used
4421 * in a scaled index address mode as a multiplier (e.g. "[4*index]"), then return
4422 * the scale factor: 2, 4, or 8. Otherwise, return 0. Note that we never return 1,
4423 * to match the behavior of GetScaleIndexShf().
4426 unsigned GenTree::GetScaleIndexMul()
4428 if (IsCnsIntOrI() && jitIsScaleIndexMul(gtIntConCommon.IconValue()) && gtIntConCommon.IconValue() != 1)
4430 return (unsigned)gtIntConCommon.IconValue();
4436 /*****************************************************************************
4438 * If the given tree is the right-hand side of a left shift (that is,
4439 * 'y' in the tree 'x' << 'y'), and it is an integer constant that can be used
4440 * in a scaled index address mode as a multiplier (e.g. "[4*index]"), then return
4441 * the scale factor: 2, 4, or 8. Otherwise, return 0.
4444 unsigned GenTree::GetScaleIndexShf()
4446 if (IsCnsIntOrI() && jitIsScaleIndexShift(gtIntConCommon.IconValue()))
4448 return (unsigned)(1 << gtIntConCommon.IconValue());
4454 /*****************************************************************************
4456 * If the given tree is a scaled index (i.e. "op * 4" or "op << 2"), returns
4457 * the multiplier: 2, 4, or 8; otherwise returns 0. Note that "1" is never
4461 unsigned GenTree::GetScaledIndex()
4463 // with (!opts.OptEnabled(CLFLG_CONSTANTFOLD) we can have
4464 // CNS_INT * CNS_INT
4466 if (gtOp.gtOp1->IsCnsIntOrI())
4474 return gtOp.gtOp2->GetScaleIndexMul();
4477 return gtOp.gtOp2->GetScaleIndexShf();
4480 assert(!"GenTree::GetScaledIndex() called with illegal gtOper");
4487 /*****************************************************************************
4489 * Returns true if "addr" is a GT_ADD node, at least one of whose arguments is an integer (<= 32 bit)
4490 * constant. If it returns true, it sets "*offset" to (one of the) constant value(s), and
4491 * "*addr" to the other argument.
4494 bool GenTree::IsAddWithI32Const(GenTree** addr, int* offset)
4496 if (OperGet() == GT_ADD)
4498 if (gtOp.gtOp1->IsIntCnsFitsInI32())
4500 *offset = (int)gtOp.gtOp1->gtIntCon.gtIconVal;
4504 else if (gtOp.gtOp2->IsIntCnsFitsInI32())
4506 *offset = (int)gtOp.gtOp2->gtIntCon.gtIconVal;
4515 //------------------------------------------------------------------------
4516 // gtGetChildPointer: If 'parent' is the parent of this node, return the pointer
4517 // to the child node so that it can be modified; otherwise, return nullptr.
4520 // parent - The possible parent of this node
4523 // If "child" is a child of "parent", returns a pointer to the child node in the parent
4524 // (i.e. a pointer to a GenTree pointer).
4525 // Otherwise, returns nullptr.
4528 // 'parent' must be non-null
4531 // When FEATURE_MULTIREG_ARGS is defined we can get here with GT_OBJ tree.
4532 // This happens when we have a struct that is passed in multiple registers.
4534 // Also note that when UNIX_AMD64_ABI is defined the GT_LDOBJ
4535 // later gets converted to a GT_FIELD_LIST with two GT_LCL_FLDs in Lower/LowerXArch.
4538 GenTree** GenTree::gtGetChildPointer(GenTree* parent) const
4541 switch (parent->OperGet())
4544 if (!parent->OperIsSimple())
4548 if (this == parent->gtOp.gtOp1)
4550 return &(parent->gtOp.gtOp1);
4552 if (this == parent->gtOp.gtOp2)
4554 return &(parent->gtOp.gtOp2);
4559 if (this == parent->gtCmpXchg.gtOpLocation)
4561 return &(parent->gtCmpXchg.gtOpLocation);
4563 if (this == parent->gtCmpXchg.gtOpValue)
4565 return &(parent->gtCmpXchg.gtOpValue);
4567 if (this == parent->gtCmpXchg.gtOpComparand)
4569 return &(parent->gtCmpXchg.gtOpComparand);
4573 case GT_ARR_BOUNDS_CHECK:
4576 #endif // FEATURE_SIMD
4577 #ifdef FEATURE_HW_INTRINSICS
4578 case GT_HW_INTRINSIC_CHK:
4579 #endif // FEATURE_HW_INTRINSICS
4580 if (this == parent->gtBoundsChk.gtIndex)
4582 return &(parent->gtBoundsChk.gtIndex);
4584 if (this == parent->gtBoundsChk.gtArrLen)
4586 return &(parent->gtBoundsChk.gtArrLen);
4591 if (this == parent->gtArrElem.gtArrObj)
4593 return &(parent->gtArrElem.gtArrObj);
4595 for (int i = 0; i < GT_ARR_MAX_RANK; i++)
4597 if (this == parent->gtArrElem.gtArrInds[i])
4599 return &(parent->gtArrElem.gtArrInds[i]);
4605 if (this == parent->gtArrOffs.gtOffset)
4607 return &(parent->gtArrOffs.gtOffset);
4609 if (this == parent->gtArrOffs.gtIndex)
4611 return &(parent->gtArrOffs.gtIndex);
4613 if (this == parent->gtArrOffs.gtArrObj)
4615 return &(parent->gtArrOffs.gtArrObj);
4619 case GT_STORE_DYN_BLK:
4621 if (this == parent->gtDynBlk.gtOp1)
4623 return &(parent->gtDynBlk.gtOp1);
4625 if (this == parent->gtDynBlk.gtOp2)
4627 return &(parent->gtDynBlk.gtOp2);
4629 if (this == parent->gtDynBlk.gtDynamicSize)
4631 return &(parent->gtDynBlk.gtDynamicSize);
4636 if (this == parent->AsField()->gtFldObj)
4638 return &(parent->AsField()->gtFldObj);
4643 if (this == parent->gtRetExpr.gtInlineCandidate)
4645 return &(parent->gtRetExpr.gtInlineCandidate);
4651 GenTreeCall* call = parent->AsCall();
4653 if (this == call->gtCallObjp)
4655 return &(call->gtCallObjp);
4657 if (this == call->gtCallArgs)
4659 return reinterpret_cast<GenTree**>(&(call->gtCallArgs));
4661 if (this == call->gtCallLateArgs)
4663 return reinterpret_cast<GenTree**>(&(call->gtCallLateArgs));
4665 if (this == call->gtControlExpr)
4667 return &(call->gtControlExpr);
4669 if (call->gtCallType == CT_INDIRECT)
4671 if (this == call->gtCallCookie)
4673 return &(call->gtCallCookie);
4675 if (this == call->gtCallAddr)
4677 return &(call->gtCallAddr);
4684 noway_assert(!"Illegal node for gtGetChildPointer()");
4691 bool GenTree::TryGetUse(GenTree* def, GenTree*** use)
4693 assert(def != nullptr);
4694 assert(use != nullptr);
4701 case GT_LCL_VAR_ADDR:
4702 case GT_LCL_FLD_ADDR:
4711 case GT_MEMORYBARRIER:
4716 case GT_START_NONGC:
4717 case GT_START_PREEMPTGC:
4719 #if !FEATURE_EH_FUNCLETS
4721 #endif // !FEATURE_EH_FUNCLETS
4725 case GT_CLS_VAR_ADDR:
4729 case GT_PINVOKE_PROLOG:
4730 case GT_PINVOKE_EPILOG:
4734 // Standard unary operators
4735 case GT_STORE_LCL_VAR:
4736 case GT_STORE_LCL_FLD:
4752 case GT_RUNTIMELOOKUP:
4765 if (def == this->AsUnOp()->gtOp1)
4767 *use = &this->AsUnOp()->gtOp1;
4774 assert(this->AsUnOp()->gtOp1 != nullptr);
4775 return this->AsUnOp()->gtOp1->TryGetUseList(def, use);
4778 return TryGetUseList(def, use);
4780 #if FEATURE_ARG_SPLIT
4781 case GT_PUTARG_SPLIT:
4782 if (this->AsUnOp()->gtOp1->gtOper == GT_FIELD_LIST)
4784 return this->AsUnOp()->gtOp1->TryGetUseList(def, use);
4786 if (def == this->AsUnOp()->gtOp1)
4788 *use = &this->AsUnOp()->gtOp1;
4792 #endif // FEATURE_ARG_SPLIT
4796 if (this->AsSIMD()->gtSIMDIntrinsicID == SIMDIntrinsicInitN)
4798 assert(this->AsSIMD()->gtOp1 != nullptr);
4799 return this->AsSIMD()->gtOp1->TryGetUseList(def, use);
4802 return TryGetUseBinOp(def, use);
4803 #endif // FEATURE_SIMD
4805 #ifdef FEATURE_HW_INTRINSICS
4806 case GT_HWIntrinsic:
4807 if ((this->AsHWIntrinsic()->gtOp1 != nullptr) && this->AsHWIntrinsic()->gtOp1->OperIsList())
4809 return this->AsHWIntrinsic()->gtOp1->TryGetUseList(def, use);
4812 return TryGetUseBinOp(def, use);
4813 #endif // FEATURE_HW_INTRINSICS
4818 GenTreeCmpXchg* const cmpXchg = this->AsCmpXchg();
4819 if (def == cmpXchg->gtOpLocation)
4821 *use = &cmpXchg->gtOpLocation;
4824 if (def == cmpXchg->gtOpValue)
4826 *use = &cmpXchg->gtOpValue;
4829 if (def == cmpXchg->gtOpComparand)
4831 *use = &cmpXchg->gtOpComparand;
4837 case GT_ARR_BOUNDS_CHECK:
4840 #endif // FEATURE_SIMD
4841 #ifdef FEATURE_HW_INTRINSICS
4842 case GT_HW_INTRINSIC_CHK:
4843 #endif // FEATURE_HW_INTRINSICS
4845 GenTreeBoundsChk* const boundsChk = this->AsBoundsChk();
4846 if (def == boundsChk->gtIndex)
4848 *use = &boundsChk->gtIndex;
4851 if (def == boundsChk->gtArrLen)
4853 *use = &boundsChk->gtArrLen;
4860 if (def == this->AsField()->gtFldObj)
4862 *use = &this->AsField()->gtFldObj;
4868 if (def == this->AsStmt()->gtStmtExpr)
4870 *use = &this->AsStmt()->gtStmtExpr;
4877 GenTreeArrElem* const arrElem = this->AsArrElem();
4878 if (def == arrElem->gtArrObj)
4880 *use = &arrElem->gtArrObj;
4883 for (unsigned i = 0; i < arrElem->gtArrRank; i++)
4885 if (def == arrElem->gtArrInds[i])
4887 *use = &arrElem->gtArrInds[i];
4896 GenTreeArrOffs* const arrOffs = this->AsArrOffs();
4897 if (def == arrOffs->gtOffset)
4899 *use = &arrOffs->gtOffset;
4902 if (def == arrOffs->gtIndex)
4904 *use = &arrOffs->gtIndex;
4907 if (def == arrOffs->gtArrObj)
4909 *use = &arrOffs->gtArrObj;
4917 GenTreeDynBlk* const dynBlock = this->AsDynBlk();
4918 if (def == dynBlock->gtOp1)
4920 *use = &dynBlock->gtOp1;
4923 if (def == dynBlock->gtDynamicSize)
4925 *use = &dynBlock->gtDynamicSize;
4931 case GT_STORE_DYN_BLK:
4933 GenTreeDynBlk* const dynBlock = this->AsDynBlk();
4934 if (def == dynBlock->gtOp1)
4936 *use = &dynBlock->gtOp1;
4939 if (def == dynBlock->gtOp2)
4941 *use = &dynBlock->gtOp2;
4944 if (def == dynBlock->gtDynamicSize)
4946 *use = &dynBlock->gtDynamicSize;
4954 GenTreeCall* const call = this->AsCall();
4955 if (def == call->gtCallObjp)
4957 *use = &call->gtCallObjp;
4960 if (def == call->gtControlExpr)
4962 *use = &call->gtControlExpr;
4965 if (call->gtCallType == CT_INDIRECT)
4967 if (def == call->gtCallCookie)
4969 *use = &call->gtCallCookie;
4972 if (def == call->gtCallAddr)
4974 *use = &call->gtCallAddr;
4978 if ((call->gtCallArgs != nullptr) && call->gtCallArgs->TryGetUseList(def, use))
4983 return (call->gtCallLateArgs != nullptr) && call->gtCallLateArgs->TryGetUseList(def, use);
4988 assert(this->OperIsBinary());
4989 return TryGetUseBinOp(def, use);
4993 bool GenTree::TryGetUseList(GenTree* def, GenTree*** use)
4995 assert(def != nullptr);
4996 assert(use != nullptr);
4998 for (GenTreeArgList* node = this->AsArgList(); node != nullptr; node = node->Rest())
5000 if (def == node->gtOp1)
5002 *use = &node->gtOp1;
5009 bool GenTree::TryGetUseBinOp(GenTree* def, GenTree*** use)
5011 assert(def != nullptr);
5012 assert(use != nullptr);
5013 assert(this->OperIsBinary());
5015 GenTreeOp* const binOp = this->AsOp();
5016 if (def == binOp->gtOp1)
5018 *use = &binOp->gtOp1;
5021 if (def == binOp->gtOp2)
5023 *use = &binOp->gtOp2;
5029 //------------------------------------------------------------------------
5030 // GenTree::ReplaceOperand:
5031 // Replace a given operand to this node with a new operand. If the
5032 // current node is a call node, this will also udpate the call
5033 // argument table if necessary.
5036 // useEdge - the use edge that points to the operand to be replaced.
5037 // replacement - the replacement node.
5039 void GenTree::ReplaceOperand(GenTree** useEdge, GenTree* replacement)
5041 assert(useEdge != nullptr);
5042 assert(replacement != nullptr);
5043 assert(TryGetUse(*useEdge, &useEdge));
5045 if (OperGet() == GT_CALL)
5047 AsCall()->ReplaceCallOperand(useEdge, replacement);
5051 *useEdge = replacement;
5055 //------------------------------------------------------------------------
5056 // gtGetParent: Get the parent of this node, and optionally capture the
5057 // pointer to the child so that it can be modified.
5061 // parentChildPointer - A pointer to a GenTree** (yes, that's three
5062 // levels, i.e. GenTree ***), which if non-null,
5063 // will be set to point to the field in the parent
5064 // that points to this node.
5066 // Return value - The parent of this node.
5070 // This requires that the execution order must be defined (i.e. gtSetEvalOrder() has been called).
5071 // To enable the child to be replaced, it accepts an argument, parentChildPointer that, if non-null,
5072 // will be set to point to the child pointer in the parent that points to this node.
5074 GenTree* GenTree::gtGetParent(GenTree*** parentChildPtrPtr) const
5076 // Find the parent node; it must be after this node in the execution order.
5077 GenTree** parentChildPtr = nullptr;
5079 for (parent = gtNext; parent != nullptr; parent = parent->gtNext)
5081 parentChildPtr = gtGetChildPointer(parent);
5082 if (parentChildPtr != nullptr)
5087 if (parentChildPtrPtr != nullptr)
5089 *parentChildPtrPtr = parentChildPtr;
5094 //------------------------------------------------------------------------------
5095 // OperRequiresAsgFlag : Check whether the operation requires GTF_ASG flag regardless
5096 // of the children's flags.
5099 bool GenTree::OperRequiresAsgFlag()
5101 if (OperIs(GT_ASG) || OperIs(GT_XADD, GT_XCHG, GT_LOCKADD, GT_CMPXCHG, GT_MEMORYBARRIER))
5105 #ifdef FEATURE_HW_INTRINSICS
5106 if (gtOper == GT_HWIntrinsic)
5108 GenTreeHWIntrinsic* hwIntrinsicNode = this->AsHWIntrinsic();
5109 if (hwIntrinsicNode->OperIsMemoryStore())
5111 // A MemoryStore operation is an assignment
5115 #endif // FEATURE_HW_INTRINSICS
5119 //------------------------------------------------------------------------------
5120 // OperRequiresCallFlag : Check whether the operation requires GTF_CALL flag regardless
5121 // of the children's flags.
5124 bool GenTree::OperRequiresCallFlag(Compiler* comp)
5132 return comp->IsIntrinsicImplementedByUserCall(this->AsIntrinsic()->gtIntrinsicId);
5134 #if FEATURE_FIXED_OUT_ARGS && !defined(_TARGET_64BIT_)
5139 // Variable shifts of a long end up being helper calls, so mark the tree as such in morph.
5140 // This is potentially too conservative, since they'll get treated as having side effects.
5141 // It is important to mark them as calls so if they are part of an argument list,
5142 // they will get sorted and processed properly (for example, it is important to handle
5143 // all nested calls before putting struct arguments in the argument registers). We
5144 // could mark the trees just before argument processing, but it would require a full
5145 // tree walk of the argument tree, so we just do it when morphing, instead, even though we'll
5146 // mark non-argument trees (that will still get converted to calls, anyway).
5147 return (this->TypeGet() == TYP_LONG) && (gtGetOp2()->OperGet() != GT_CNS_INT);
5148 #endif // FEATURE_FIXED_OUT_ARGS && !_TARGET_64BIT_
5155 //------------------------------------------------------------------------------
5156 // OperIsImplicitIndir : Check whether the operation contains an implicit
5159 // this - a GenTree node
5162 // True if the given node contains an implicit indirection
5164 // Note that for the GT_HWIntrinsic node we have to examine the
5165 // details of the node to determine its result.
5168 bool GenTree::OperIsImplicitIndir() const
5181 case GT_STORE_DYN_BLK:
5187 #ifdef FEATURE_HW_INTRINSICS
5188 case GT_HWIntrinsic:
5190 GenTreeHWIntrinsic* hwIntrinsicNode = (const_cast<GenTree*>(this))->AsHWIntrinsic();
5191 return hwIntrinsicNode->OperIsMemoryLoadOrStore();
5193 #endif // FEATURE_HW_INTRINSICS
5199 //------------------------------------------------------------------------------
5200 // OperMayThrow : Check whether the operation may throw.
5204 // comp - Compiler instance
5207 // True if the given operator may cause an exception
5209 bool GenTree::OperMayThrow(Compiler* comp)
5220 /* Division with a non-zero, non-minus-one constant does not throw an exception */
5224 if (varTypeIsFloating(op->TypeGet()))
5226 return false; // Floating point division does not throw.
5229 // For integers only division by 0 or by -1 can throw
5230 if (op->IsIntegralConst() && !op->IsIntegralConst(0) && !op->IsIntegralConst(-1))
5237 // If this is an intrinsic that represents the object.GetType(), it can throw an NullReferenceException.
5238 // Report it as may throw.
5239 // Note: Some of the rest of the existing intrinsics could potentially throw an exception (for example
5240 // the array and string element access ones). They are handled differently than the GetType intrinsic
5241 // and are not marked with GTF_EXCEPT. If these are revisited at some point to be marked as
5243 // the code below might need to be specialized to handle them properly.
5244 if ((this->gtFlags & GTF_EXCEPT) != 0)
5253 CorInfoHelpFunc helper;
5254 helper = comp->eeGetHelperNum(this->AsCall()->gtCallMethHnd);
5255 return ((helper == CORINFO_HELP_UNDEF) || !comp->s_helperCallProperties.NoThrow(helper));
5263 return (((this->gtFlags & GTF_IND_NONFAULTING) == 0) && comp->fgAddrCouldBeNull(this->AsIndir()->Addr()));
5266 return (((this->gtFlags & GTF_IND_NONFAULTING) == 0) &&
5267 comp->fgAddrCouldBeNull(this->AsArrLen()->ArrRef()));
5270 return comp->fgAddrCouldBeNull(this->gtArrElem.gtArrObj);
5272 case GT_ARR_BOUNDS_CHECK:
5279 #endif // FEATURE_SIMD
5280 #ifdef FEATURE_HW_INTRINSICS
5281 case GT_HW_INTRINSIC_CHK:
5282 #endif // FEATURE_HW_INTRINSICS
5286 #ifdef FEATURE_HW_INTRINSICS
5287 case GT_HWIntrinsic:
5289 GenTreeHWIntrinsic* hwIntrinsicNode = this->AsHWIntrinsic();
5290 assert(hwIntrinsicNode != nullptr);
5291 if (hwIntrinsicNode->OperIsMemoryLoadOrStore())
5293 // This operation contains an implicit indirection
5294 // it could throw a null reference exception.
5299 #endif // FEATURE_HW_INTRINSICS
5305 /* Overflow arithmetic operations also throw exceptions */
5315 #if DEBUGGABLE_GENTREE
5317 GenTree::VtablePtr GenTree::s_vtablesForOpers[] = {nullptr};
5318 GenTree::VtablePtr GenTree::s_vtableForOp = nullptr;
5320 GenTree::VtablePtr GenTree::GetVtableForOper(genTreeOps oper)
5322 noway_assert(oper < GT_COUNT);
5324 // First, check a cache.
5326 if (s_vtablesForOpers[oper] != nullptr)
5328 return s_vtablesForOpers[oper];
5331 // Otherwise, look up the correct vtable entry. Note that we want the most derived GenTree subtype
5332 // for an oper. E.g., GT_LCL_VAR is defined in GTSTRUCT_3 as GenTreeLclVar and in GTSTRUCT_N as
5333 // GenTreeLclVarCommon. We want the GenTreeLclVar vtable, since nothing should actually be
5334 // instantiated as a GenTreeLclVarCommon.
5336 VtablePtr res = nullptr;
5342 #define GTSTRUCT_0(nm, tag) /*handle explicitly*/
5343 #define GTSTRUCT_1(nm, tag) \
5347 res = *reinterpret_cast<VtablePtr*>(>); \
5350 #define GTSTRUCT_2(nm, tag, tag2) \
5355 res = *reinterpret_cast<VtablePtr*>(>); \
5358 #define GTSTRUCT_3(nm, tag, tag2, tag3) \
5364 res = *reinterpret_cast<VtablePtr*>(>); \
5367 #define GTSTRUCT_4(nm, tag, tag2, tag3, tag4) \
5374 res = *reinterpret_cast<VtablePtr*>(>); \
5377 #define GTSTRUCT_N(nm, ...) /*handle explicitly*/
5378 #define GTSTRUCT_2_SPECIAL(nm, tag, tag2) /*handle explicitly*/
5379 #define GTSTRUCT_3_SPECIAL(nm, tag, tag2, tag3) /*handle explicitly*/
5380 #include "gtstructs.h"
5384 // Handle the special cases.
5385 // The following opers are in GTSTRUCT_N but no other place (namely, no subtypes).
5391 res = *reinterpret_cast<VtablePtr*>(>);
5399 res = *reinterpret_cast<VtablePtr*>(>);
5403 // Handle GT_LIST (but not GT_FIELD_LIST, which is also in a GTSTRUCT_1).
5408 res = *reinterpret_cast<VtablePtr*>(>);
5412 // We don't need to handle GTSTRUCT_N for LclVarCommon, since all those allowed opers are specified
5413 // in their proper subtype. Similarly for GenTreeIndir.
5417 // Should be unary or binary op.
5418 if (s_vtableForOp == nullptr)
5420 unsigned opKind = OperKind(oper);
5421 assert(!IsExOp(opKind));
5422 assert(OperIsSimple(oper) || OperIsLeaf(oper));
5423 // Need to provide non-null operands.
5424 GenTreeIntCon dummyOp(TYP_INT, 0);
5425 GenTreeOp gt(oper, TYP_INT, &dummyOp, ((opKind & GTK_UNOP) ? nullptr : &dummyOp));
5426 s_vtableForOp = *reinterpret_cast<VtablePtr*>(>);
5428 res = s_vtableForOp;
5432 s_vtablesForOpers[oper] = res;
5436 void GenTree::SetVtableForOper(genTreeOps oper)
5438 *reinterpret_cast<VtablePtr*>(this) = GetVtableForOper(oper);
5440 #endif // DEBUGGABLE_GENTREE
5442 GenTree* Compiler::gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, GenTree* op2)
5444 assert(op1 != nullptr);
5445 assert(op2 != nullptr);
5447 // We should not be allocating nodes that extend GenTreeOp with this;
5448 // should call the appropriate constructor for the extended type.
5449 assert(!GenTree::IsExOp(GenTree::OperKind(oper)));
5451 GenTree* node = new (this, oper) GenTreeOp(oper, type, op1, op2);
5456 GenTree* Compiler::gtNewQmarkNode(var_types type, GenTree* cond, GenTree* colon)
5458 compQmarkUsed = true;
5459 cond->gtFlags |= GTF_RELOP_QMARK;
5460 GenTree* result = new (this, GT_QMARK) GenTreeQmark(type, cond, colon, this);
5462 if (compQmarkRationalized)
5464 fgCheckQmarkAllowedForm(result);
5470 GenTreeQmark::GenTreeQmark(var_types type, GenTree* cond, GenTree* colonOp, Compiler* comp)
5471 : GenTreeOp(GT_QMARK, type, cond, colonOp)
5473 // These must follow a specific form.
5474 assert(cond != nullptr && cond->TypeGet() == TYP_INT);
5475 assert(colonOp != nullptr && colonOp->OperGet() == GT_COLON);
5478 GenTreeIntCon* Compiler::gtNewIconNode(ssize_t value, var_types type)
5480 return new (this, GT_CNS_INT) GenTreeIntCon(type, value);
5483 // return a new node representing the value in a physical register
5484 GenTree* Compiler::gtNewPhysRegNode(regNumber reg, var_types type)
5486 assert(genIsValidIntReg(reg) || (reg == REG_SPBASE));
5487 GenTree* result = new (this, GT_PHYSREG) GenTreePhysReg(reg, type);
5491 GenTree* Compiler::gtNewJmpTableNode()
5493 return new (this, GT_JMPTABLE) GenTree(GT_JMPTABLE, TYP_I_IMPL);
5496 /*****************************************************************************
5498 * Converts an annotated token into an icon flags (so that we will later be
5499 * able to tell the type of the handle that will be embedded in the icon
5503 unsigned Compiler::gtTokenToIconFlags(unsigned token)
5507 switch (TypeFromToken(token))
5512 flags = GTF_ICON_CLASS_HDL;
5516 flags = GTF_ICON_METHOD_HDL;
5520 flags = GTF_ICON_FIELD_HDL;
5524 flags = GTF_ICON_TOKEN_HDL;
5531 //-----------------------------------------------------------------------------------------
5532 // gtNewIndOfIconHandleNode: Creates an indirection GenTree node of a constant handle
5535 // indType - The type returned by the indirection node
5536 // addr - The constant address to read from
5537 // iconFlags - The GTF_ICON flag value that specifies the kind of handle that we have
5538 // isInvariant - The indNode should also be marked as invariant
5541 // Returns a GT_IND node representing value at the address provided by 'value'
5544 // The GT_IND node is marked as non-faulting
5545 // If the indType is GT_REF we also mark the indNode as GTF_GLOB_REF
5548 GenTree* Compiler::gtNewIndOfIconHandleNode(var_types indType, size_t addr, unsigned iconFlags, bool isInvariant)
5550 GenTree* addrNode = gtNewIconHandleNode(addr, iconFlags);
5551 GenTree* indNode = gtNewOperNode(GT_IND, indType, addrNode);
5553 // This indirection won't cause an exception.
5555 indNode->gtFlags |= GTF_IND_NONFAULTING;
5557 // String Literal handles are indirections that return a TYP_REF.
5558 // They are pointers into the GC heap and they are not invariant
5559 // as the address is a reportable GC-root and as such it can be
5560 // modified during a GC collection
5562 if (indType == TYP_REF)
5564 // This indirection points into the gloabal heap
5565 indNode->gtFlags |= GTF_GLOB_REF;
5569 // This indirection also is invariant.
5570 indNode->gtFlags |= GTF_IND_INVARIANT;
5575 /*****************************************************************************
5577 * Allocates a integer constant entry that represents a HANDLE to something.
5578 * It may not be allowed to embed HANDLEs directly into the JITed code (for eg,
5579 * as arguments to JIT helpers). Get a corresponding value that can be embedded.
5580 * If the handle needs to be accessed via an indirection, pValue points to it.
5583 GenTree* Compiler::gtNewIconEmbHndNode(void* value, void* pValue, unsigned iconFlags, void* compileTimeHandle)
5586 GenTree* handleNode;
5588 if (value != nullptr)
5590 // When 'value' is non-null, pValue is required to be null
5591 assert(pValue == nullptr);
5593 // use 'value' to construct an integer constant node
5594 iconNode = gtNewIconHandleNode((size_t)value, iconFlags);
5596 // 'value' is the handle
5597 handleNode = iconNode;
5601 // When 'value' is null, pValue is required to be non-null
5602 assert(pValue != nullptr);
5604 // use 'pValue' to construct an integer constant node
5605 iconNode = gtNewIconHandleNode((size_t)pValue, iconFlags);
5607 // 'pValue' is an address of a location that contains the handle
5609 // construct the indirection of 'pValue'
5610 handleNode = gtNewOperNode(GT_IND, TYP_I_IMPL, iconNode);
5612 // This indirection won't cause an exception.
5613 handleNode->gtFlags |= GTF_IND_NONFAULTING;
5615 // It should also be invariant, but marking it as such leads to bad diffs.
5617 // This indirection also is invariant.
5618 handleNode->gtFlags |= GTF_IND_INVARIANT;
5622 iconNode->gtIntCon.gtCompileTimeHandle = (size_t)compileTimeHandle;
5627 /*****************************************************************************/
5628 GenTree* Compiler::gtNewStringLiteralNode(InfoAccessType iat, void* pValue)
5630 GenTree* tree = nullptr;
5634 case IAT_VALUE: // constructStringLiteral in CoreRT case can return IAT_VALUE
5635 tree = gtNewIconEmbHndNode(pValue, nullptr, GTF_ICON_STR_HDL, nullptr);
5636 tree->gtType = TYP_REF;
5637 tree = gtNewOperNode(GT_NOP, TYP_REF, tree); // prevents constant folding
5640 case IAT_PVALUE: // The value needs to be accessed via an indirection
5641 // Create an indirection
5642 tree = gtNewIndOfIconHandleNode(TYP_REF, (size_t)pValue, GTF_ICON_STR_HDL, false);
5645 case IAT_PPVALUE: // The value needs to be accessed via a double indirection
5646 // Create the first indirection
5647 tree = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)pValue, GTF_ICON_PSTR_HDL, true);
5649 // Create the second indirection
5650 tree = gtNewOperNode(GT_IND, TYP_REF, tree);
5651 // This indirection won't cause an exception.
5652 tree->gtFlags |= GTF_IND_NONFAULTING;
5653 // This indirection points into the gloabal heap (it is String Object)
5654 tree->gtFlags |= GTF_GLOB_REF;
5658 noway_assert(!"Unexpected InfoAccessType");
5664 /*****************************************************************************/
5666 GenTree* Compiler::gtNewLconNode(__int64 value)
5668 #ifdef _TARGET_64BIT_
5669 GenTree* node = new (this, GT_CNS_INT) GenTreeIntCon(TYP_LONG, value);
5671 GenTree* node = new (this, GT_CNS_LNG) GenTreeLngCon(value);
5677 GenTree* Compiler::gtNewDconNode(double value, var_types type)
5679 GenTree* node = new (this, GT_CNS_DBL) GenTreeDblCon(value, type);
5684 GenTree* Compiler::gtNewSconNode(int CPX, CORINFO_MODULE_HANDLE scpHandle)
5686 // 'GT_CNS_STR' nodes later get transformed into 'GT_CALL'
5687 assert(GenTree::s_gtNodeSizes[GT_CALL] > GenTree::s_gtNodeSizes[GT_CNS_STR]);
5688 GenTree* node = new (this, GT_CALL) GenTreeStrCon(CPX, scpHandle DEBUGARG(/*largeNode*/ true));
5692 GenTree* Compiler::gtNewZeroConNode(var_types type)
5698 zero = gtNewIconNode(0);
5705 zero = gtNewIconNode(0);
5706 zero->gtType = type;
5710 zero = gtNewLconNode(0);
5714 zero = gtNewDconNode(0.0);
5715 zero->gtType = type;
5719 zero = gtNewDconNode(0.0);
5723 noway_assert(!"Bad type in gtNewZeroConNode");
5730 GenTree* Compiler::gtNewOneConNode(var_types type)
5737 one = gtNewIconNode(1);
5742 one = gtNewLconNode(1);
5747 one = gtNewDconNode(1.0);
5752 noway_assert(!"Bad type in gtNewOneConNode");
5760 //---------------------------------------------------------------------
5761 // gtNewSIMDVectorZero: create a GT_SIMD node for Vector<T>.Zero
5764 // simdType - simd vector type
5765 // baseType - element type of vector
5766 // size - size of vector in bytes
5767 GenTree* Compiler::gtNewSIMDVectorZero(var_types simdType, var_types baseType, unsigned size)
5769 baseType = genActualType(baseType);
5770 GenTree* initVal = gtNewZeroConNode(baseType);
5771 initVal->gtType = baseType;
5772 return gtNewSIMDNode(simdType, initVal, nullptr, SIMDIntrinsicInit, baseType, size);
5775 //---------------------------------------------------------------------
5776 // gtNewSIMDVectorOne: create a GT_SIMD node for Vector<T>.One
5779 // simdType - simd vector type
5780 // baseType - element type of vector
5781 // size - size of vector in bytes
5782 GenTree* Compiler::gtNewSIMDVectorOne(var_types simdType, var_types baseType, unsigned size)
5785 if (varTypeIsSmallInt(baseType))
5787 unsigned baseSize = genTypeSize(baseType);
5797 initVal = gtNewIconNode(val);
5801 initVal = gtNewOneConNode(baseType);
5804 baseType = genActualType(baseType);
5805 initVal->gtType = baseType;
5806 return gtNewSIMDNode(simdType, initVal, nullptr, SIMDIntrinsicInit, baseType, size);
5808 #endif // FEATURE_SIMD
5810 GenTreeCall* Compiler::gtNewIndCallNode(GenTree* addr, var_types type, GenTreeArgList* args, IL_OFFSETX ilOffset)
5812 return gtNewCallNode(CT_INDIRECT, (CORINFO_METHOD_HANDLE)addr, type, args, ilOffset);
5815 GenTreeCall* Compiler::gtNewCallNode(
5816 gtCallTypes callType, CORINFO_METHOD_HANDLE callHnd, var_types type, GenTreeArgList* args, IL_OFFSETX ilOffset)
5818 GenTreeCall* node = new (this, GT_CALL) GenTreeCall(genActualType(type));
5820 node->gtFlags |= (GTF_CALL | GTF_GLOB_REF);
5823 node->gtFlags |= (args->gtFlags & GTF_ALL_EFFECT);
5825 node->gtCallType = callType;
5826 node->gtCallMethHnd = callHnd;
5827 node->gtCallArgs = args;
5828 node->gtCallObjp = nullptr;
5829 node->fgArgInfo = nullptr;
5830 node->callSig = nullptr;
5831 node->gtRetClsHnd = nullptr;
5832 node->gtControlExpr = nullptr;
5833 node->gtCallMoreFlags = 0;
5835 if (callType == CT_INDIRECT)
5837 node->gtCallCookie = nullptr;
5841 node->gtInlineCandidateInfo = nullptr;
5843 node->gtCallLateArgs = nullptr;
5844 node->gtReturnType = type;
5846 #ifdef FEATURE_READYTORUN_COMPILER
5847 node->gtEntryPoint.addr = nullptr;
5848 node->gtEntryPoint.accessType = IAT_VALUE;
5851 #if defined(DEBUG) || defined(INLINE_DATA)
5852 // These get updated after call node is built.
5853 node->gtInlineObservation = InlineObservation::CALLEE_UNUSED_INITIAL;
5854 node->gtRawILOffset = BAD_IL_OFFSET;
5857 // Spec: Managed Retval sequence points needs to be generated while generating debug info for debuggable code.
5859 // Implementation note: if not generating MRV info genCallSite2ILOffsetMap will be NULL and
5860 // codegen will pass BAD_IL_OFFSET as IL offset of a call node to emitter, which will cause emitter
5861 // not to emit IP mapping entry.
5862 if (opts.compDbgCode && opts.compDbgInfo)
5864 // Managed Retval - IL offset of the call. This offset is used to emit a
5865 // CALL_INSTRUCTION type sequence point while emitting corresponding native call.
5868 // a) (Opt) We need not store this offset if the method doesn't return a
5869 // value. Rather it can be made BAD_IL_OFFSET to prevent a sequence
5870 // point being emitted.
5872 // b) (Opt) Add new sequence points only if requested by debugger through
5873 // a new boundary type - ICorDebugInfo::BoundaryTypes
5874 if (genCallSite2ILOffsetMap == nullptr)
5876 genCallSite2ILOffsetMap = new (getAllocator()) CallSiteILOffsetTable(getAllocator());
5879 // Make sure that there are no duplicate entries for a given call node
5880 assert(!genCallSite2ILOffsetMap->Lookup(node));
5881 genCallSite2ILOffsetMap->Set(node, ilOffset);
5884 // Initialize gtOtherRegs
5885 node->ClearOtherRegs();
5887 // Initialize spill flags of gtOtherRegs
5888 node->ClearOtherRegFlags();
5890 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
5891 // Initialize the multi-reg long return info if necessary
5892 if (varTypeIsLong(node))
5894 // The return type will remain as the incoming long type
5895 node->gtReturnType = node->gtType;
5897 // Initialize Return type descriptor of call node
5898 ReturnTypeDesc* retTypeDesc = node->GetReturnTypeDesc();
5899 retTypeDesc->InitializeLongReturnType(this);
5901 // must be a long returned in two registers
5902 assert(retTypeDesc->GetReturnRegCount() == 2);
5904 #endif // defined(_TARGET_X86_) || defined(_TARGET_ARM_)
5909 GenTree* Compiler::gtNewLclvNode(unsigned lnum, var_types type DEBUGARG(IL_OFFSETX ILoffs))
5911 // We need to ensure that all struct values are normalized.
5912 // It might be nice to assert this in general, but we have assignments of int to long.
5913 if (varTypeIsStruct(type))
5915 // Make an exception for implicit by-ref parameters during global morph, since
5916 // their lvType has been updated to byref but their appearances have not yet all
5917 // been rewritten and so may have struct type still.
5918 assert(type == lvaTable[lnum].lvType ||
5919 (lvaIsImplicitByRefLocal(lnum) && fgGlobalMorph && (lvaTable[lnum].lvType == TYP_BYREF)));
5921 GenTree* node = new (this, GT_LCL_VAR) GenTreeLclVar(type, lnum DEBUGARG(ILoffs));
5923 /* Cannot have this assert because the inliner uses this function
5924 * to add temporaries */
5926 // assert(lnum < lvaCount);
5931 GenTree* Compiler::gtNewLclLNode(unsigned lnum, var_types type DEBUGARG(IL_OFFSETX ILoffs))
5933 // We need to ensure that all struct values are normalized.
5934 // It might be nice to assert this in general, but we have assignments of int to long.
5935 if (varTypeIsStruct(type))
5937 // Make an exception for implicit by-ref parameters during global morph, since
5938 // their lvType has been updated to byref but their appearances have not yet all
5939 // been rewritten and so may have struct type still.
5940 assert(type == lvaTable[lnum].lvType ||
5941 (lvaIsImplicitByRefLocal(lnum) && fgGlobalMorph && (lvaTable[lnum].lvType == TYP_BYREF)));
5943 // This local variable node may later get transformed into a large node
5944 assert(GenTree::s_gtNodeSizes[GT_CALL] > GenTree::s_gtNodeSizes[GT_LCL_VAR]);
5945 GenTree* node = new (this, GT_CALL) GenTreeLclVar(type, lnum DEBUGARG(ILoffs) DEBUGARG(/*largeNode*/ true));
5949 GenTreeLclFld* Compiler::gtNewLclFldNode(unsigned lnum, var_types type, unsigned offset)
5951 GenTreeLclFld* node = new (this, GT_LCL_FLD) GenTreeLclFld(type, lnum, offset);
5953 /* Cannot have this assert because the inliner uses this function
5954 * to add temporaries */
5956 // assert(lnum < lvaCount);
5958 node->gtFieldSeq = FieldSeqStore::NotAField();
5962 GenTree* Compiler::gtNewInlineCandidateReturnExpr(GenTree* inlineCandidate, var_types type)
5965 assert(GenTree::s_gtNodeSizes[GT_RET_EXPR] == TREE_NODE_SZ_LARGE);
5967 GenTree* node = new (this, GT_RET_EXPR) GenTreeRetExpr(type);
5969 node->gtRetExpr.gtInlineCandidate = inlineCandidate;
5971 if (varTypeIsStruct(inlineCandidate) && !inlineCandidate->OperIsBlkOp())
5973 node->gtRetExpr.gtRetClsHnd = gtGetStructHandle(inlineCandidate);
5976 // GT_RET_EXPR node eventually might be bashed back to GT_CALL (when inlining is aborted for example).
5977 // Therefore it should carry the GTF_CALL flag so that all the rules about spilling can apply to it as well.
5978 // For example, impImportLeave or CEE_POP need to spill GT_RET_EXPR before empty the evaluation stack.
5979 node->gtFlags |= GTF_CALL;
5984 GenTreeArgList* Compiler::gtNewListNode(GenTree* op1, GenTreeArgList* op2)
5986 assert((op1 != nullptr) && (op1->OperGet() != GT_LIST));
5988 return new (this, GT_LIST) GenTreeArgList(op1, op2);
5991 /*****************************************************************************
5993 * Create a list out of one value.
5996 GenTreeArgList* Compiler::gtNewArgList(GenTree* arg)
5998 return new (this, GT_LIST) GenTreeArgList(arg);
6001 /*****************************************************************************
6003 * Create a list out of the two values.
6006 GenTreeArgList* Compiler::gtNewArgList(GenTree* arg1, GenTree* arg2)
6008 return new (this, GT_LIST) GenTreeArgList(arg1, gtNewArgList(arg2));
6011 /*****************************************************************************
6013 * Create a list out of the three values.
6016 GenTreeArgList* Compiler::gtNewArgList(GenTree* arg1, GenTree* arg2, GenTree* arg3)
6018 return new (this, GT_LIST) GenTreeArgList(arg1, gtNewArgList(arg2, arg3));
6021 /*****************************************************************************
6023 * Create a list out of the three values.
6026 GenTreeArgList* Compiler::gtNewArgList(GenTree* arg1, GenTree* arg2, GenTree* arg3, GenTree* arg4)
6028 return new (this, GT_LIST) GenTreeArgList(arg1, gtNewArgList(arg2, arg3, arg4));
6031 /*****************************************************************************
6033 * Given a GT_CALL node, access the fgArgInfo and find the entry
6034 * that has the matching argNum and return the fgArgTableEntryPtr
6037 fgArgTabEntry* Compiler::gtArgEntryByArgNum(GenTreeCall* call, unsigned argNum)
6039 fgArgInfo* argInfo = call->fgArgInfo;
6040 noway_assert(argInfo != nullptr);
6041 return argInfo->GetArgEntry(argNum);
6044 /*****************************************************************************
6046 * Given a GT_CALL node, access the fgArgInfo and find the entry
6047 * that has the matching node and return the fgArgTableEntryPtr
6050 fgArgTabEntry* Compiler::gtArgEntryByNode(GenTreeCall* call, GenTree* node)
6052 fgArgInfo* argInfo = call->fgArgInfo;
6053 noway_assert(argInfo != nullptr);
6055 unsigned argCount = argInfo->ArgCount();
6056 fgArgTabEntry** argTable = argInfo->ArgTable();
6057 fgArgTabEntry* curArgTabEntry = nullptr;
6059 for (unsigned i = 0; i < argCount; i++)
6061 curArgTabEntry = argTable[i];
6063 if (curArgTabEntry->node == node)
6065 return curArgTabEntry;
6067 else if (curArgTabEntry->parent != nullptr)
6069 assert(curArgTabEntry->parent->OperIsList());
6070 if (curArgTabEntry->parent->Current() == node)
6072 return curArgTabEntry;
6075 else // (curArgTabEntry->parent == NULL)
6077 if (call->gtCallObjp == node)
6079 return curArgTabEntry;
6083 noway_assert(!"gtArgEntryByNode: node not found");
6087 /*****************************************************************************
6089 * Find and return the entry with the given "lateArgInx". Requires that one is found
6092 fgArgTabEntry* Compiler::gtArgEntryByLateArgIndex(GenTreeCall* call, unsigned lateArgInx)
6094 fgArgInfo* argInfo = call->fgArgInfo;
6095 noway_assert(argInfo != nullptr);
6096 assert(lateArgInx != UINT_MAX);
6098 unsigned argCount = argInfo->ArgCount();
6099 fgArgTabEntry** argTable = argInfo->ArgTable();
6100 fgArgTabEntry* curArgTabEntry = nullptr;
6102 for (unsigned i = 0; i < argCount; i++)
6104 curArgTabEntry = argTable[i];
6105 if (curArgTabEntry->isLateArg() && curArgTabEntry->lateArgInx == lateArgInx)
6107 return curArgTabEntry;
6110 noway_assert(!"gtArgEntryByNode: node not found");
6114 //------------------------------------------------------------------------
6115 // gtArgNodeByLateArgInx: Given a call instruction, find the argument with the given
6116 // late arg index (i.e. the given position in the gtCallLateArgs list).
6118 // call - the call node
6119 // lateArgInx - the index into the late args list
6122 // The late argument node.
6124 GenTree* Compiler::gtArgNodeByLateArgInx(GenTreeCall* call, unsigned lateArgInx)
6126 GenTree* argx = nullptr;
6127 unsigned regIndex = 0;
6129 for (GenTreeArgList *list = call->gtCall.gtCallLateArgs; list != nullptr; regIndex++, list = list->Rest())
6131 argx = list->Current();
6132 assert(!argx->IsArgPlaceHolderNode()); // No placeholder nodes are in gtCallLateArgs;
6133 if (regIndex == lateArgInx)
6138 noway_assert(argx != nullptr);
6142 /*****************************************************************************
6144 * Given an fgArgTabEntry*, return true if it is the 'this' pointer argument.
6146 bool Compiler::gtArgIsThisPtr(fgArgTabEntry* argEntry)
6148 return (argEntry->parent == nullptr);
6151 /*****************************************************************************
6153 * Create a node that will assign 'src' to 'dst'.
6156 GenTree* Compiler::gtNewAssignNode(GenTree* dst, GenTree* src)
6158 /* Mark the target as being assigned */
6160 if ((dst->gtOper == GT_LCL_VAR) || (dst->OperGet() == GT_LCL_FLD))
6162 dst->gtFlags |= GTF_VAR_DEF;
6163 if (dst->IsPartialLclFld(this))
6165 // We treat these partial writes as combined uses and defs.
6166 dst->gtFlags |= GTF_VAR_USEASG;
6169 dst->gtFlags |= GTF_DONT_CSE;
6171 /* Create the assignment node */
6173 GenTree* asg = gtNewOperNode(GT_ASG, dst->TypeGet(), dst, src);
6175 /* Mark the expression as containing an assignment */
6177 asg->gtFlags |= GTF_ASG;
6182 //------------------------------------------------------------------------
6183 // gtNewObjNode: Creates a new Obj node.
6186 // structHnd - The class handle of the struct type.
6187 // addr - The address of the struct.
6190 // Returns a node representing the struct value at the given address.
6193 // Any entry and exit conditions, such as required preconditions of
6194 // data structures, memory to be freed by caller, etc.
6197 // It will currently return a GT_OBJ node for any struct type, but may
6198 // return a GT_IND or a non-indirection for a scalar type.
6199 // The node will not yet have its GC info initialized. This is because
6200 // we may not need this info if this is an r-value.
6202 GenTree* Compiler::gtNewObjNode(CORINFO_CLASS_HANDLE structHnd, GenTree* addr)
6204 var_types nodeType = impNormStructType(structHnd);
6205 assert(varTypeIsStruct(nodeType));
6206 unsigned size = info.compCompHnd->getClassSize(structHnd);
6208 // It would be convenient to set the GC info at this time, but we don't actually require
6209 // it unless this is going to be a destination.
6210 if (!varTypeIsStruct(nodeType))
6212 if ((addr->gtOper == GT_ADDR) && (addr->gtGetOp1()->TypeGet() == nodeType))
6214 return addr->gtGetOp1();
6218 return gtNewOperNode(GT_IND, nodeType, addr);
6221 GenTreeBlk* newBlkOrObjNode = new (this, GT_OBJ) GenTreeObj(nodeType, addr, structHnd, size);
6223 // An Obj is not a global reference, if it is known to be a local struct.
6224 if ((addr->gtFlags & GTF_GLOB_REF) == 0)
6226 GenTreeLclVarCommon* lclNode = addr->IsLocalAddrExpr();
6227 if (lclNode != nullptr)
6229 newBlkOrObjNode->gtFlags |= GTF_IND_NONFAULTING;
6230 if (!lvaIsImplicitByRefLocal(lclNode->gtLclNum))
6232 newBlkOrObjNode->gtFlags &= ~GTF_GLOB_REF;
6236 return newBlkOrObjNode;
6239 //------------------------------------------------------------------------
6240 // gtSetObjGcInfo: Set the GC info on an object node
6243 // objNode - The object node of interest
6245 void Compiler::gtSetObjGcInfo(GenTreeObj* objNode)
6247 CORINFO_CLASS_HANDLE structHnd = objNode->gtClass;
6248 var_types nodeType = objNode->TypeGet();
6249 unsigned size = objNode->gtBlkSize;
6251 unsigned gcPtrCount = 0;
6252 BYTE* gcPtrs = nullptr;
6254 assert(varTypeIsStruct(nodeType));
6255 assert(size == info.compCompHnd->getClassSize(structHnd));
6256 assert(nodeType == impNormStructType(structHnd));
6258 if (nodeType == TYP_STRUCT)
6260 if (size >= TARGET_POINTER_SIZE)
6262 // Get the GC fields info
6263 var_types simdBaseType; // Dummy argument
6264 slots = roundUp(size, TARGET_POINTER_SIZE) / TARGET_POINTER_SIZE;
6265 gcPtrs = new (this, CMK_ASTNode) BYTE[slots];
6266 nodeType = impNormStructType(structHnd, gcPtrs, &gcPtrCount, &simdBaseType);
6269 objNode->SetGCInfo(gcPtrs, gcPtrCount, slots);
6270 assert(objNode->gtType == nodeType);
6273 //------------------------------------------------------------------------
6274 // gtNewStructVal: Return a node that represents a struct value
6277 // structHnd - The class for the struct
6278 // addr - The address of the struct
6281 // A block, object or local node that represents the struct value pointed to by 'addr'.
6283 GenTree* Compiler::gtNewStructVal(CORINFO_CLASS_HANDLE structHnd, GenTree* addr)
6285 if (addr->gtOper == GT_ADDR)
6287 GenTree* val = addr->gtGetOp1();
6288 if (val->OperGet() == GT_LCL_VAR)
6290 unsigned lclNum = addr->gtGetOp1()->AsLclVarCommon()->gtLclNum;
6291 LclVarDsc* varDsc = &(lvaTable[lclNum]);
6292 if (varTypeIsStruct(varDsc) && (varDsc->lvVerTypeInfo.GetClassHandle() == structHnd) &&
6293 !lvaIsImplicitByRefLocal(lclNum))
6295 return addr->gtGetOp1();
6299 return gtNewObjNode(structHnd, addr);
6302 //------------------------------------------------------------------------
6303 // gtNewBlockVal: Return a node that represents a possibly untyped block value
6306 // addr - The address of the block
6307 // size - The size of the block
6310 // A block, object or local node that represents the block value pointed to by 'addr'.
6312 GenTree* Compiler::gtNewBlockVal(GenTree* addr, unsigned size)
6314 // By default we treat this as an opaque struct type with known size.
6315 var_types blkType = TYP_STRUCT;
6316 if ((addr->gtOper == GT_ADDR) && (addr->gtGetOp1()->OperGet() == GT_LCL_VAR))
6318 GenTree* val = addr->gtGetOp1();
6320 if (varTypeIsSIMD(val))
6322 if (genTypeSize(val->TypeGet()) == size)
6324 blkType = val->TypeGet();
6325 return addr->gtGetOp1();
6329 #endif // FEATURE_SIMD
6330 if (val->TypeGet() == TYP_STRUCT)
6332 GenTreeLclVarCommon* lcl = addr->gtGetOp1()->AsLclVarCommon();
6333 LclVarDsc* varDsc = &(lvaTable[lcl->gtLclNum]);
6334 if ((varDsc->TypeGet() == TYP_STRUCT) && (varDsc->lvExactSize == size))
6336 return addr->gtGetOp1();
6340 return new (this, GT_BLK) GenTreeBlk(GT_BLK, blkType, addr, size);
6343 // Creates a new assignment node for a CpObj.
6344 // Parameters (exactly the same as MSIL CpObj):
6346 // dstAddr - The target to copy the struct to
6347 // srcAddr - The source to copy the struct from
6348 // structHnd - A class token that represents the type of object being copied. May be null
6349 // if FEATURE_SIMD is enabled and the source has a SIMD type.
6350 // isVolatile - Is this marked as volatile memory?
6352 GenTree* Compiler::gtNewCpObjNode(GenTree* dstAddr, GenTree* srcAddr, CORINFO_CLASS_HANDLE structHnd, bool isVolatile)
6354 GenTree* lhs = gtNewStructVal(structHnd, dstAddr);
6355 GenTree* src = nullptr;
6358 if (lhs->OperIsBlk())
6360 size = lhs->AsBlk()->gtBlkSize;
6361 if (lhs->OperGet() == GT_OBJ)
6363 gtSetObjGcInfo(lhs->AsObj());
6368 size = genTypeSize(lhs->gtType);
6371 if (srcAddr->OperGet() == GT_ADDR)
6373 src = srcAddr->gtOp.gtOp1;
6377 src = gtNewOperNode(GT_IND, lhs->TypeGet(), srcAddr);
6380 GenTree* result = gtNewBlkOpNode(lhs, src, size, isVolatile, true);
6384 //------------------------------------------------------------------------
6385 // FixupInitBlkValue: Fixup the init value for an initBlk operation
6388 // asgType - The type of assignment that the initBlk is being transformed into
6391 // Modifies the constant value on this node to be the appropriate "fill"
6392 // value for the initblk.
6395 // The initBlk MSIL instruction takes a byte value, which must be
6396 // extended to the size of the assignment when an initBlk is transformed
6397 // to an assignment of a primitive type.
6398 // This performs the appropriate extension.
6400 void GenTreeIntCon::FixupInitBlkValue(var_types asgType)
6402 assert(varTypeIsIntegralOrI(asgType));
6403 unsigned size = genTypeSize(asgType);
6406 size_t cns = gtIconVal;
6412 #ifdef _TARGET_64BIT_
6417 #endif // _TARGET_64BIT_
6419 // Make the type match for evaluation types.
6422 // if we are initializing a GC type the value being assigned must be zero (null).
6423 assert(!varTypeIsGC(asgType) || (cns == 0));
6431 //------------------------------------------------------------------------
6432 // gtBlockOpInit: Initializes a BlkOp GenTree
6435 // result - an assignment node that is to be initialized.
6436 // dst - the target (destination) we want to either initialize or copy to.
6437 // src - the init value for InitBlk or the source struct for CpBlk/CpObj.
6438 // isVolatile - specifies whether this node is a volatile memory operation.
6441 // 'result' is an assignment that is newly constructed.
6442 // If 'dst' is TYP_STRUCT, then it must be a block node or lclVar.
6445 // This procedure centralizes all the logic to both enforce proper structure and
6446 // to properly construct any InitBlk/CpBlk node.
6448 void Compiler::gtBlockOpInit(GenTree* result, GenTree* dst, GenTree* srcOrFillVal, bool isVolatile)
6450 if (!result->OperIsBlkOp())
6452 assert(dst->TypeGet() != TYP_STRUCT);
6456 // If the copy involves GC pointers, the caller must have already set
6457 // the node additional members (gtGcPtrs, gtGcPtrCount, gtSlots) on the dst.
6458 if ((dst->gtOper == GT_OBJ) && dst->AsBlk()->HasGCPtr())
6460 GenTreeObj* objNode = dst->AsObj();
6461 assert(objNode->gtGcPtrs != nullptr);
6462 assert(!IsUninitialized(objNode->gtGcPtrs));
6463 assert(!IsUninitialized(objNode->gtGcPtrCount));
6464 assert(!IsUninitialized(objNode->gtSlots) && objNode->gtSlots > 0);
6466 for (unsigned i = 0; i < objNode->gtGcPtrCount; ++i)
6468 CorInfoGCType t = (CorInfoGCType)objNode->gtGcPtrs[i];
6483 /* In the case of CpBlk, we want to avoid generating
6484 * nodes where the source and destination are the same
6485 * because of two reasons, first, is useless, second
6486 * it introduces issues in liveness and also copying
6487 * memory from an overlapping memory location is
6488 * undefined both as per the ECMA standard and also
6489 * the memcpy semantics specify that.
6491 * NOTE: In this case we'll only detect the case for addr of a local
6492 * and a local itself, any other complex expressions won't be
6495 * TODO-Cleanup: though having this logic is goodness (i.e. avoids self-assignment
6496 * of struct vars very early), it was added because fgInterBlockLocalVarLiveness()
6497 * isn't handling self-assignment of struct variables correctly. This issue may not
6498 * surface if struct promotion is ON (which is the case on x86/arm). But still the
6499 * fundamental issue exists that needs to be addressed.
6501 if (result->OperIsCopyBlkOp())
6503 GenTree* currSrc = srcOrFillVal;
6504 GenTree* currDst = dst;
6506 if (currSrc->OperIsBlk() && (currSrc->AsBlk()->Addr()->OperGet() == GT_ADDR))
6508 currSrc = currSrc->AsBlk()->Addr()->gtGetOp1();
6510 if (currDst->OperIsBlk() && (currDst->AsBlk()->Addr()->OperGet() == GT_ADDR))
6512 currDst = currDst->AsBlk()->Addr()->gtGetOp1();
6515 if (currSrc->OperGet() == GT_LCL_VAR && currDst->OperGet() == GT_LCL_VAR &&
6516 currSrc->gtLclVarCommon.gtLclNum == currDst->gtLclVarCommon.gtLclNum)
6519 // TODO-Cleanup: probably doesn't matter, but could do this earlier and avoid creating a GT_ASG
6520 result->gtBashToNOP();
6525 // Propagate all effect flags from children
6526 result->gtFlags |= dst->gtFlags & GTF_ALL_EFFECT;
6527 result->gtFlags |= result->gtOp.gtOp2->gtFlags & GTF_ALL_EFFECT;
6529 result->gtFlags |= (dst->gtFlags & GTF_EXCEPT) | (srcOrFillVal->gtFlags & GTF_EXCEPT);
6533 result->gtFlags |= GTF_BLK_VOLATILE;
6537 if (result->OperIsCopyBlkOp() && varTypeIsSIMD(srcOrFillVal))
6539 // If the source is a GT_SIMD node of SIMD type, then the dst lclvar struct
6540 // should be labeled as simd intrinsic related struct.
6541 // This is done so that the morpher can transform any field accesses into
6542 // intrinsics, thus avoiding conflicting access methods (fields vs. whole-register).
6544 GenTree* src = srcOrFillVal;
6545 if (src->OperIsIndir() && (src->AsIndir()->Addr()->OperGet() == GT_ADDR))
6547 src = src->AsIndir()->Addr()->gtGetOp1();
6549 #ifdef FEATURE_HW_INTRINSICS
6550 if ((src->OperGet() == GT_SIMD) || (src->OperGet() == GT_HWIntrinsic))
6552 if (src->OperGet() == GT_SIMD)
6553 #endif // FEATURE_HW_INTRINSICS
6555 if (dst->OperIsBlk() && (dst->AsIndir()->Addr()->OperGet() == GT_ADDR))
6557 dst = dst->AsIndir()->Addr()->gtGetOp1();
6560 if (dst->OperIsLocal() && varTypeIsStruct(dst))
6562 setLclRelatedToSIMDIntrinsic(dst);
6566 #endif // FEATURE_SIMD
6569 //------------------------------------------------------------------------
6570 // gtNewBlkOpNode: Creates a GenTree for a block (struct) assignment.
6573 // dst - Destination or target to copy to / initialize the buffer.
6574 // srcOrFillVall - the size of the buffer to copy/initialize or zero, in the case of CpObj.
6575 // size - The size of the buffer or a class token (in the case of CpObj).
6576 // isVolatile - Whether this is a volatile memory operation or not.
6577 // isCopyBlock - True if this is a block copy (rather than a block init).
6580 // Returns the newly constructed and initialized block operation.
6583 // If size is zero, the dst must be a GT_OBJ with the class handle.
6584 // 'dst' must be a block node or lclVar.
6586 GenTree* Compiler::gtNewBlkOpNode(GenTree* dst, GenTree* srcOrFillVal, unsigned size, bool isVolatile, bool isCopyBlock)
6588 assert(dst->OperIsBlk() || dst->OperIsLocal());
6591 srcOrFillVal->gtFlags |= GTF_DONT_CSE;
6592 if (srcOrFillVal->OperIsIndir() && (srcOrFillVal->gtGetOp1()->gtOper == GT_ADDR))
6594 srcOrFillVal = srcOrFillVal->gtGetOp1()->gtGetOp1();
6600 assert(varTypeIsIntegral(srcOrFillVal));
6601 if (varTypeIsStruct(dst))
6603 if (!srcOrFillVal->IsIntegralConst(0))
6605 srcOrFillVal = gtNewOperNode(GT_INIT_VAL, TYP_INT, srcOrFillVal);
6610 GenTree* result = gtNewAssignNode(dst, srcOrFillVal);
6611 gtBlockOpInit(result, dst, srcOrFillVal, isVolatile);
6615 //------------------------------------------------------------------------
6616 // gtNewPutArgReg: Creates a new PutArgReg node.
6619 // type - The actual type of the argument
6620 // arg - The argument node
6621 // argReg - The register that the argument will be passed in
6624 // Returns the newly created PutArgReg node.
6627 // The node is generated as GenTreeMultiRegOp on RyuJIT/armel, GenTreeOp on all the other archs.
6629 GenTree* Compiler::gtNewPutArgReg(var_types type, GenTree* arg, regNumber argReg)
6631 assert(arg != nullptr);
6633 GenTree* node = nullptr;
6634 #if defined(_TARGET_ARM_)
6635 // A PUTARG_REG could be a MultiRegOp on arm since we could move a double register to two int registers.
6636 node = new (this, GT_PUTARG_REG) GenTreeMultiRegOp(GT_PUTARG_REG, type, arg, nullptr);
6637 if (type == TYP_LONG)
6639 node->AsMultiRegOp()->gtOtherReg = REG_NEXT(argReg);
6642 node = gtNewOperNode(GT_PUTARG_REG, type, arg);
6644 node->gtRegNum = argReg;
6649 //------------------------------------------------------------------------
6650 // gtNewBitCastNode: Creates a new BitCast node.
6653 // type - The actual type of the argument
6654 // arg - The argument node
6655 // argReg - The register that the argument will be passed in
6658 // Returns the newly created BitCast node.
6661 // The node is generated as GenTreeMultiRegOp on RyuJIT/arm, as GenTreeOp on all the other archs.
6663 GenTree* Compiler::gtNewBitCastNode(var_types type, GenTree* arg)
6665 assert(arg != nullptr);
6667 GenTree* node = nullptr;
6668 #if defined(_TARGET_ARM_)
6669 // A BITCAST could be a MultiRegOp on arm since we could move a double register to two int registers.
6670 node = new (this, GT_BITCAST) GenTreeMultiRegOp(GT_BITCAST, type, arg, nullptr);
6672 node = gtNewOperNode(GT_BITCAST, type, arg);
6678 //------------------------------------------------------------------------
6679 // gtNewAllocObjNode: Helper to create an object allocation node.
6682 // pResolvedToken - Resolved token for the object being allocated
6683 // useParent - true iff the token represents a child of the object's class
6686 // Returns GT_ALLOCOBJ node that will be later morphed into an
6687 // allocation helper call or local variable allocation on the stack.
6689 GenTreeAllocObj* Compiler::gtNewAllocObjNode(CORINFO_RESOLVED_TOKEN* pResolvedToken, BOOL useParent)
6691 const BOOL mustRestoreHandle = TRUE;
6692 BOOL* const pRuntimeLookup = nullptr;
6693 bool usingReadyToRunHelper = false;
6694 CorInfoHelpFunc helper = CORINFO_HELP_UNDEF;
6695 GenTree* opHandle = impTokenToHandle(pResolvedToken, pRuntimeLookup, mustRestoreHandle, useParent);
6697 #ifdef FEATURE_READYTORUN_COMPILER
6698 CORINFO_CONST_LOOKUP lookup = {};
6700 if (opts.IsReadyToRun())
6702 helper = CORINFO_HELP_READYTORUN_NEW;
6703 CORINFO_LOOKUP_KIND* const pGenericLookupKind = nullptr;
6704 usingReadyToRunHelper =
6705 info.compCompHnd->getReadyToRunHelper(pResolvedToken, pGenericLookupKind, helper, &lookup);
6709 if (!usingReadyToRunHelper)
6711 if (opHandle == nullptr)
6713 // We must be backing out of an inline.
6714 assert(compDonotInline());
6719 bool helperHasSideEffects;
6720 CorInfoHelpFunc helperTemp =
6721 info.compCompHnd->getNewHelper(pResolvedToken, info.compMethodHnd, &helperHasSideEffects);
6723 if (!usingReadyToRunHelper)
6725 helper = helperTemp;
6728 // TODO: ReadyToRun: When generic dictionary lookups are necessary, replace the lookup call
6729 // and the newfast call with a single call to a dynamic R2R cell that will:
6730 // 1) Load the context
6731 // 2) Perform the generic dictionary lookup and caching, and generate the appropriate stub
6732 // 3) Allocate and return the new object for boxing
6733 // Reason: performance (today, we'll always use the slow helper for the R2R generics case)
6735 GenTreeAllocObj* allocObj =
6736 gtNewAllocObjNode(helper, helperHasSideEffects, pResolvedToken->hClass, TYP_REF, opHandle);
6738 #ifdef FEATURE_READYTORUN_COMPILER
6739 if (usingReadyToRunHelper)
6741 allocObj->gtEntryPoint = lookup;
6748 /*****************************************************************************
6750 * Clones the given tree value and returns a copy of the given tree.
6751 * If 'complexOK' is false, the cloning is only done provided the tree
6752 * is not too complex (whatever that may mean);
6753 * If 'complexOK' is true, we try slightly harder to clone the tree.
6754 * In either case, NULL is returned if the tree cannot be cloned
6756 * Note that there is the function gtCloneExpr() which does a more
6757 * complete job if you can't handle this function failing.
6760 GenTree* Compiler::gtClone(GenTree* tree, bool complexOK)
6764 switch (tree->gtOper)
6768 #if defined(LATE_DISASM)
6769 if (tree->IsIconHandle())
6771 copy = gtNewIconHandleNode(tree->gtIntCon.gtIconVal, tree->gtFlags, tree->gtIntCon.gtFieldSeq);
6772 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6773 copy->gtType = tree->gtType;
6778 copy = new (this, GT_CNS_INT)
6779 GenTreeIntCon(tree->gtType, tree->gtIntCon.gtIconVal, tree->gtIntCon.gtFieldSeq);
6780 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6785 copy = gtNewLconNode(tree->gtLngCon.gtLconVal);
6789 // Remember that the LclVar node has been cloned. The flag will be set
6790 // on 'copy' as well.
6791 tree->gtFlags |= GTF_VAR_CLONED;
6792 copy = gtNewLclvNode(tree->gtLclVarCommon.gtLclNum, tree->gtType DEBUGARG(tree->gtLclVar.gtLclILoffs));
6796 case GT_LCL_FLD_ADDR:
6797 // Remember that the LclVar node has been cloned. The flag will be set
6798 // on 'copy' as well.
6799 tree->gtFlags |= GTF_VAR_CLONED;
6800 copy = new (this, tree->gtOper)
6801 GenTreeLclFld(tree->gtOper, tree->TypeGet(), tree->gtLclFld.gtLclNum, tree->gtLclFld.gtLclOffs);
6802 copy->gtLclFld.gtFieldSeq = tree->gtLclFld.gtFieldSeq;
6806 copy = new (this, GT_CLS_VAR)
6807 GenTreeClsVar(tree->gtType, tree->gtClsVar.gtClsVarHnd, tree->gtClsVar.gtFieldSeq);
6816 if (tree->gtOper == GT_FIELD)
6820 // copied from line 9850
6823 if (tree->gtField.gtFldObj)
6825 objp = gtClone(tree->gtField.gtFldObj, false);
6832 copy = gtNewFieldRef(tree->TypeGet(), tree->gtField.gtFldHnd, objp, tree->gtField.gtFldOffset);
6833 copy->gtField.gtFldMayOverlap = tree->gtField.gtFldMayOverlap;
6834 #ifdef FEATURE_READYTORUN_COMPILER
6835 copy->gtField.gtFieldLookup = tree->gtField.gtFieldLookup;
6838 else if (tree->OperIs(GT_ADD, GT_SUB))
6840 GenTree* op1 = tree->gtOp.gtOp1;
6841 GenTree* op2 = tree->gtOp.gtOp2;
6843 if (op1->OperIsLeaf() && op2->OperIsLeaf())
6856 copy = gtNewOperNode(tree->OperGet(), tree->TypeGet(), op1, op2);
6863 else if (tree->gtOper == GT_ADDR)
6865 GenTree* op1 = gtClone(tree->gtOp.gtOp1);
6870 copy = gtNewOperNode(GT_ADDR, tree->TypeGet(), op1);
6880 copy->gtFlags |= tree->gtFlags & ~GTF_NODE_MASK;
6882 copy->gtDebugFlags |= tree->gtDebugFlags & ~GTF_DEBUG_NODE_MASK;
6883 #endif // defined(DEBUG)
6888 //------------------------------------------------------------------------
6889 // gtCloneExpr: Create a copy of `tree`, adding flags `addFlags`, mapping
6890 // local `varNum` to int constant `varVal` if it appears at
6891 // the root, and mapping uses of local `deepVarNum` to constant
6892 // `deepVarVal` if they occur beyond the root.
6895 // tree - GenTree to create a copy of
6896 // addFlags - GTF_* flags to add to the copied tree nodes
6897 // varNum - lclNum to replace at the root, or ~0 for no root replacement
6898 // varVal - If replacing at root, replace local `varNum` with IntCns `varVal`
6899 // deepVarNum - lclNum to replace uses of beyond the root, or ~0 for no replacement
6900 // deepVarVal - If replacing beyond root, replace `deepVarNum` with IntCns `deepVarVal`
6903 // A copy of the given tree with the replacements and added flags specified.
6906 // Top-level callers should generally call the overload that doesn't have
6907 // the explicit `deepVarNum` and `deepVarVal` parameters; those are used in
6908 // recursive invocations to avoid replacing defs.
6910 GenTree* Compiler::gtCloneExpr(
6911 GenTree* tree, unsigned addFlags, unsigned varNum, int varVal, unsigned deepVarNum, int deepVarVal)
6913 if (tree == nullptr)
6918 /* Figure out what kind of a node we have */
6920 genTreeOps oper = tree->OperGet();
6921 unsigned kind = tree->OperKind();
6924 /* Is this a constant or leaf node? */
6926 if (kind & (GTK_CONST | GTK_LEAF))
6932 #if defined(LATE_DISASM)
6933 if (tree->IsIconHandle())
6935 copy = gtNewIconHandleNode(tree->gtIntCon.gtIconVal, tree->gtFlags, tree->gtIntCon.gtFieldSeq);
6936 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6937 copy->gtType = tree->gtType;
6942 copy = gtNewIconNode(tree->gtIntCon.gtIconVal, tree->gtType);
6943 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6944 copy->gtIntCon.gtFieldSeq = tree->gtIntCon.gtFieldSeq;
6949 copy = gtNewLconNode(tree->gtLngCon.gtLconVal);
6953 copy = gtNewDconNode(tree->gtDblCon.gtDconVal);
6954 copy->gtType = tree->gtType; // keep the same type
6958 copy = gtNewSconNode(tree->gtStrCon.gtSconCPX, tree->gtStrCon.gtScpHnd);
6963 if (tree->gtLclVarCommon.gtLclNum == varNum)
6965 copy = gtNewIconNode(varVal, tree->gtType);
6966 if (tree->gtFlags & GTF_VAR_ARR_INDEX)
6968 copy->LabelIndex(this);
6973 // Remember that the LclVar node has been cloned. The flag will
6974 // be set on 'copy' as well.
6975 tree->gtFlags |= GTF_VAR_CLONED;
6976 copy = gtNewLclvNode(tree->gtLclVar.gtLclNum, tree->gtType DEBUGARG(tree->gtLclVar.gtLclILoffs));
6977 copy->AsLclVarCommon()->SetSsaNum(tree->AsLclVarCommon()->GetSsaNum());
6979 copy->gtFlags = tree->gtFlags;
6983 if (tree->gtLclFld.gtLclNum == varNum)
6985 IMPL_LIMITATION("replacing GT_LCL_FLD with a constant");
6989 // Remember that the LclVar node has been cloned. The flag will
6990 // be set on 'copy' as well.
6991 tree->gtFlags |= GTF_VAR_CLONED;
6992 copy = new (this, GT_LCL_FLD)
6993 GenTreeLclFld(tree->TypeGet(), tree->gtLclFld.gtLclNum, tree->gtLclFld.gtLclOffs);
6994 copy->gtLclFld.gtFieldSeq = tree->gtLclFld.gtFieldSeq;
6995 copy->gtFlags = tree->gtFlags;
7000 copy = new (this, GT_CLS_VAR)
7001 GenTreeClsVar(tree->TypeGet(), tree->gtClsVar.gtClsVarHnd, tree->gtClsVar.gtFieldSeq);
7005 // GT_RET_EXPR is unique node, that contains a link to a gtInlineCandidate node,
7006 // that is part of another statement. We cannot clone both here and cannot
7007 // create another GT_RET_EXPR that points to the same gtInlineCandidate.
7008 NO_WAY("Cloning of GT_RET_EXPR node not supported");
7011 case GT_MEMORYBARRIER:
7012 copy = new (this, GT_MEMORYBARRIER) GenTree(GT_MEMORYBARRIER, TYP_VOID);
7016 copy = gtNewArgPlaceHolderNode(tree->gtType, tree->gtArgPlace.gtArgPlaceClsHnd);
7020 copy = new (this, oper) GenTreeFptrVal(tree->gtType, tree->gtFptrVal.gtFptrMethod);
7022 #ifdef FEATURE_READYTORUN_COMPILER
7023 copy->gtFptrVal.gtEntryPoint = tree->gtFptrVal.gtEntryPoint;
7030 copy = new (this, oper) GenTree(oper, tree->gtType);
7033 #if !FEATURE_EH_FUNCLETS
7035 #endif // !FEATURE_EH_FUNCLETS
7037 copy = new (this, oper) GenTreeVal(oper, tree->gtType, tree->gtVal.gtVal1);
7041 NO_WAY("Cloning of node not supported");
7046 /* Is it a 'simple' unary/binary operator? */
7048 if (kind & GTK_SMPOP)
7050 /* If necessary, make sure we allocate a "fat" tree node */
7051 CLANG_FORMAT_COMMENT_ANCHOR;
7055 /* These nodes sometimes get bashed to "fat" ones */
7064 // In the implementation of gtNewLargeOperNode you have
7065 // to give an oper that will create a small node,
7066 // otherwise it asserts.
7068 if (GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL)
7070 copy = gtNewLargeOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1,
7071 tree->OperIsBinary() ? tree->gtOp.gtOp2 : nullptr);
7073 else // Always a large tree
7075 if (tree->OperIsBinary())
7077 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2);
7081 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1);
7088 new (this, LargeOpOpcode()) GenTreeCast(tree->TypeGet(), tree->gtCast.CastOp(), tree->IsUnsigned(),
7089 tree->gtCast.gtCastType DEBUGARG(/*largeNode*/ TRUE));
7092 // The nodes below this are not bashed, so they can be allocated at their individual sizes.
7095 assert((tree->gtOp.gtOp2 == nullptr) || tree->gtOp.gtOp2->OperIsList());
7096 copy = new (this, GT_LIST) GenTreeArgList(tree->gtOp.gtOp1);
7097 copy->gtOp.gtOp2 = tree->gtOp.gtOp2;
7101 copy = new (this, GT_FIELD_LIST) GenTreeFieldList(tree->gtOp.gtOp1, tree->AsFieldList()->gtFieldOffset,
7102 tree->AsFieldList()->gtFieldType, nullptr);
7103 copy->gtOp.gtOp2 = tree->gtOp.gtOp2;
7104 copy->gtFlags = (copy->gtFlags & ~GTF_FIELD_LIST_HEAD) | (tree->gtFlags & GTF_FIELD_LIST_HEAD);
7109 GenTreeIndex* asInd = tree->AsIndex();
7110 copy = new (this, GT_INDEX)
7111 GenTreeIndex(asInd->TypeGet(), asInd->Arr(), asInd->Index(), asInd->gtIndElemSize);
7112 copy->AsIndex()->gtStructElemClass = asInd->gtStructElemClass;
7118 GenTreeIndexAddr* asIndAddr = tree->AsIndexAddr();
7120 copy = new (this, GT_INDEX_ADDR)
7121 GenTreeIndexAddr(asIndAddr->Arr(), asIndAddr->Index(), asIndAddr->gtElemType,
7122 asIndAddr->gtStructElemClass, asIndAddr->gtElemSize, asIndAddr->gtLenOffset,
7123 asIndAddr->gtElemOffset);
7124 copy->AsIndexAddr()->gtIndRngFailBB = asIndAddr->gtIndRngFailBB;
7130 GenTreeAllocObj* asAllocObj = tree->AsAllocObj();
7131 copy = new (this, GT_ALLOCOBJ)
7132 GenTreeAllocObj(tree->TypeGet(), asAllocObj->gtNewHelper, asAllocObj->gtHelperHasSideEffects,
7133 asAllocObj->gtAllocObjClsHnd, asAllocObj->gtOp1);
7137 case GT_RUNTIMELOOKUP:
7139 GenTreeRuntimeLookup* asRuntimeLookup = tree->AsRuntimeLookup();
7141 copy = new (this, GT_RUNTIMELOOKUP)
7142 GenTreeRuntimeLookup(asRuntimeLookup->gtHnd, asRuntimeLookup->gtHndType, asRuntimeLookup->gtOp1);
7147 copy = gtNewArrLen(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtArrLen.ArrLenOffset());
7151 copy = new (this, GT_ARR_INDEX)
7152 GenTreeArrIndex(tree->TypeGet(),
7153 gtCloneExpr(tree->gtArrIndex.ArrObj(), addFlags, deepVarNum, deepVarVal),
7154 gtCloneExpr(tree->gtArrIndex.IndexExpr(), addFlags, deepVarNum, deepVarVal),
7155 tree->gtArrIndex.gtCurrDim, tree->gtArrIndex.gtArrRank,
7156 tree->gtArrIndex.gtArrElemType);
7160 copy = new (this, GT_QMARK) GenTreeQmark(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2, this);
7164 copy = new (this, GT_OBJ)
7165 GenTreeObj(tree->TypeGet(), tree->gtOp.gtOp1, tree->AsObj()->gtClass, tree->gtBlk.gtBlkSize);
7166 copy->AsObj()->CopyGCInfo(tree->AsObj());
7167 copy->gtBlk.gtBlkOpGcUnsafe = tree->gtBlk.gtBlkOpGcUnsafe;
7171 copy = new (this, GT_BLK) GenTreeBlk(GT_BLK, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtBlk.gtBlkSize);
7172 copy->gtBlk.gtBlkOpGcUnsafe = tree->gtBlk.gtBlkOpGcUnsafe;
7176 copy = new (this, GT_DYN_BLK) GenTreeDynBlk(tree->gtOp.gtOp1, tree->gtDynBlk.gtDynamicSize);
7177 copy->gtBlk.gtBlkOpGcUnsafe = tree->gtBlk.gtBlkOpGcUnsafe;
7181 copy = new (this, GT_BOX)
7182 GenTreeBox(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtBox.gtAsgStmtWhenInlinedBoxValue,
7183 tree->gtBox.gtCopyStmtWhenInlinedBoxValue);
7187 copy = new (this, GT_INTRINSIC)
7188 GenTreeIntrinsic(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2,
7189 tree->gtIntrinsic.gtIntrinsicId, tree->gtIntrinsic.gtMethodHandle);
7190 #ifdef FEATURE_READYTORUN_COMPILER
7191 copy->gtIntrinsic.gtEntryPoint = tree->gtIntrinsic.gtEntryPoint;
7197 GenTreeAddrMode* addrModeOp = tree->AsAddrMode();
7198 copy = new (this, GT_LEA)
7199 GenTreeAddrMode(addrModeOp->TypeGet(), addrModeOp->Base(), addrModeOp->Index(), addrModeOp->gtScale,
7200 static_cast<unsigned>(addrModeOp->Offset()));
7207 copy = new (this, oper) GenTreeCopyOrReload(oper, tree->TypeGet(), tree->gtGetOp1());
7214 GenTreeSIMD* simdOp = tree->AsSIMD();
7215 copy = gtNewSIMDNode(simdOp->TypeGet(), simdOp->gtGetOp1(), simdOp->gtGetOp2IfPresent(),
7216 simdOp->gtSIMDIntrinsicID, simdOp->gtSIMDBaseType, simdOp->gtSIMDSize);
7221 #ifdef FEATURE_HW_INTRINSICS
7222 case GT_HWIntrinsic:
7224 GenTreeHWIntrinsic* hwintrinsicOp = tree->AsHWIntrinsic();
7225 copy = new (this, GT_HWIntrinsic)
7226 GenTreeHWIntrinsic(hwintrinsicOp->TypeGet(), hwintrinsicOp->gtGetOp1(),
7227 hwintrinsicOp->gtGetOp2IfPresent(), hwintrinsicOp->gtHWIntrinsicId,
7228 hwintrinsicOp->gtSIMDBaseType, hwintrinsicOp->gtSIMDSize);
7229 copy->AsHWIntrinsic()->gtIndexBaseType = hwintrinsicOp->gtIndexBaseType;
7235 assert(!GenTree::IsExOp(tree->OperKind()) && tree->OperIsSimple());
7236 // We're in the SimpleOp case, so it's always unary or binary.
7237 if (GenTree::OperIsUnary(tree->OperGet()))
7239 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, /*doSimplifications*/ false);
7243 assert(GenTree::OperIsBinary(tree->OperGet()));
7244 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2);
7249 // Some flags are conceptually part of the gtOper, and should be copied immediately.
7250 if (tree->gtOverflowEx())
7252 copy->gtFlags |= GTF_OVERFLOW;
7255 if (tree->gtOp.gtOp1)
7257 if (tree->gtOper == GT_ASG)
7259 // Don't replace varNum if it appears as the LHS of an assign.
7260 copy->gtOp.gtOp1 = gtCloneExpr(tree->gtOp.gtOp1, addFlags, -1, 0, deepVarNum, deepVarVal);
7264 copy->gtOp.gtOp1 = gtCloneExpr(tree->gtOp.gtOp1, addFlags, deepVarNum, deepVarVal);
7268 if (tree->gtGetOp2IfPresent())
7270 copy->gtOp.gtOp2 = gtCloneExpr(tree->gtOp.gtOp2, addFlags, deepVarNum, deepVarVal);
7274 addFlags |= tree->gtFlags;
7276 // Copy any node annotations, if necessary.
7277 switch (tree->gtOper)
7285 if (!tree->AsIndir()->gtOp1->OperIs(GT_INDEX_ADDR) && TryGetArrayInfo(tree->AsIndir(), &arrInfo))
7287 GetArrayInfoMap()->Set(copy, arrInfo);
7297 /* GTF_NODE_MASK should not be propagated from 'tree' to 'copy' */
7298 addFlags &= ~GTF_NODE_MASK;
7301 // Effects flags propagate upwards.
7302 if (copy->gtOp.gtOp1 != nullptr)
7304 copy->gtFlags |= (copy->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
7306 if (copy->gtGetOp2IfPresent() != nullptr)
7308 copy->gtFlags |= (copy->gtGetOp2()->gtFlags & GTF_ALL_EFFECT);
7314 /* See what kind of a special operator we have here */
7319 copy = gtCloneExpr(tree->gtStmt.gtStmtExpr, addFlags, deepVarNum, deepVarVal);
7320 copy = gtNewStmt(copy, tree->gtStmt.gtStmtILoffsx);
7325 // We can't safely clone calls that have GT_RET_EXPRs via gtCloneExpr.
7326 // You must use gtCloneCandidateCall for these calls (and then do appropriate other fixup)
7327 if (tree->gtCall.IsInlineCandidate() || tree->gtCall.IsGuardedDevirtualizationCandidate())
7329 NO_WAY("Cloning of calls with associated GT_RET_EXPR nodes is not supported");
7332 copy = gtCloneExprCallHelper(tree->AsCall(), addFlags, deepVarNum, deepVarVal);
7337 copy = gtNewFieldRef(tree->TypeGet(), tree->gtField.gtFldHnd, nullptr, tree->gtField.gtFldOffset);
7339 copy->gtField.gtFldObj = tree->gtField.gtFldObj
7340 ? gtCloneExpr(tree->gtField.gtFldObj, addFlags, deepVarNum, deepVarVal)
7342 copy->gtField.gtFldMayOverlap = tree->gtField.gtFldMayOverlap;
7343 #ifdef FEATURE_READYTORUN_COMPILER
7344 copy->gtField.gtFieldLookup = tree->gtField.gtFieldLookup;
7351 GenTree* inds[GT_ARR_MAX_RANK];
7352 for (unsigned dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
7354 inds[dim] = gtCloneExpr(tree->gtArrElem.gtArrInds[dim], addFlags, deepVarNum, deepVarVal);
7356 copy = new (this, GT_ARR_ELEM)
7357 GenTreeArrElem(tree->TypeGet(), gtCloneExpr(tree->gtArrElem.gtArrObj, addFlags, deepVarNum, deepVarVal),
7358 tree->gtArrElem.gtArrRank, tree->gtArrElem.gtArrElemSize, tree->gtArrElem.gtArrElemType,
7365 copy = new (this, GT_ARR_OFFSET)
7366 GenTreeArrOffs(tree->TypeGet(), gtCloneExpr(tree->gtArrOffs.gtOffset, addFlags, deepVarNum, deepVarVal),
7367 gtCloneExpr(tree->gtArrOffs.gtIndex, addFlags, deepVarNum, deepVarVal),
7368 gtCloneExpr(tree->gtArrOffs.gtArrObj, addFlags, deepVarNum, deepVarVal),
7369 tree->gtArrOffs.gtCurrDim, tree->gtArrOffs.gtArrRank, tree->gtArrOffs.gtArrElemType);
7374 copy = new (this, GT_CMPXCHG)
7375 GenTreeCmpXchg(tree->TypeGet(),
7376 gtCloneExpr(tree->gtCmpXchg.gtOpLocation, addFlags, deepVarNum, deepVarVal),
7377 gtCloneExpr(tree->gtCmpXchg.gtOpValue, addFlags, deepVarNum, deepVarVal),
7378 gtCloneExpr(tree->gtCmpXchg.gtOpComparand, addFlags, deepVarNum, deepVarVal));
7381 case GT_ARR_BOUNDS_CHECK:
7384 #endif // FEATURE_SIMD
7385 #ifdef FEATURE_HW_INTRINSICS
7386 case GT_HW_INTRINSIC_CHK:
7387 #endif // FEATURE_HW_INTRINSICS
7388 copy = new (this, oper)
7389 GenTreeBoundsChk(oper, tree->TypeGet(),
7390 gtCloneExpr(tree->gtBoundsChk.gtIndex, addFlags, deepVarNum, deepVarVal),
7391 gtCloneExpr(tree->gtBoundsChk.gtArrLen, addFlags, deepVarNum, deepVarVal),
7392 tree->gtBoundsChk.gtThrowKind);
7393 copy->gtBoundsChk.gtIndRngFailBB = tree->gtBoundsChk.gtIndRngFailBB;
7396 case GT_STORE_DYN_BLK:
7398 copy = new (this, oper)
7399 GenTreeDynBlk(gtCloneExpr(tree->gtDynBlk.Addr(), addFlags, deepVarNum, deepVarVal),
7400 gtCloneExpr(tree->gtDynBlk.gtDynamicSize, addFlags, deepVarNum, deepVarVal));
7407 NO_WAY("unexpected operator");
7412 // If it has a zero-offset field seq, copy annotation.
7413 if (tree->TypeGet() == TYP_BYREF)
7415 FieldSeqNode* fldSeq = nullptr;
7416 if (GetZeroOffsetFieldMap()->Lookup(tree, &fldSeq))
7418 GetZeroOffsetFieldMap()->Set(copy, fldSeq);
7422 copy->gtVNPair = tree->gtVNPair; // A cloned tree gets the orginal's Value number pair
7424 /* Compute the flags for the copied node. Note that we can do this only
7425 if we didnt gtFoldExpr(copy) */
7427 if (copy->gtOper == oper)
7429 addFlags |= tree->gtFlags;
7432 /* GTF_NODE_MASK should not be propagated from 'tree' to 'copy' */
7433 addFlags &= ~GTF_NODE_MASK;
7435 // Some other flags depend on the context of the expression, and should not be preserved.
7436 // For example, GTF_RELOP_QMARK:
7437 if (copy->OperKind() & GTK_RELOP)
7439 addFlags &= ~GTF_RELOP_QMARK;
7441 // On the other hand, if we're creating such a context, restore this flag.
7442 if (copy->OperGet() == GT_QMARK)
7444 copy->gtOp.gtOp1->gtFlags |= GTF_RELOP_QMARK;
7447 copy->gtFlags |= addFlags;
7449 // Update side effect flags since they may be different from the source side effect flags.
7450 // For example, we may have replaced some locals with constants and made indirections non-throwing.
7451 gtUpdateNodeSideEffects(copy);
7454 /* GTF_COLON_COND should be propagated from 'tree' to 'copy' */
7455 copy->gtFlags |= (tree->gtFlags & GTF_COLON_COND);
7458 // Non-node debug flags should be propagated from 'tree' to 'copy'
7459 copy->gtDebugFlags |= (tree->gtDebugFlags & ~GTF_DEBUG_NODE_MASK);
7462 /* Make sure to copy back fields that may have been initialized */
7464 copy->CopyRawCosts(tree);
7465 copy->gtRsvdRegs = tree->gtRsvdRegs;
7466 copy->CopyReg(tree);
7470 //------------------------------------------------------------------------
7471 // gtCloneExprCallHelper: clone a call tree
7474 // Do not invoke this method directly, instead call either gtCloneExpr
7475 // or gtCloneCandidateCall, as appropriate.
7478 // tree - the call to clone
7479 // addFlags - GTF_* flags to add to the copied tree nodes
7480 // deepVarNum - lclNum to replace uses of beyond the root, or BAD_VAR_NUM for no replacement
7481 // deepVarVal - If replacing beyond root, replace `deepVarNum` with IntCns `deepVarVal`
7484 // Cloned copy of call and all subtrees.
7486 GenTreeCall* Compiler::gtCloneExprCallHelper(GenTreeCall* tree, unsigned addFlags, unsigned deepVarNum, int deepVarVal)
7488 GenTreeCall* copy = new (this, GT_CALL) GenTreeCall(tree->TypeGet());
7490 copy->gtCallObjp = tree->gtCallObjp ? gtCloneExpr(tree->gtCallObjp, addFlags, deepVarNum, deepVarVal) : nullptr;
7492 tree->gtCallArgs ? gtCloneExpr(tree->gtCallArgs, addFlags, deepVarNum, deepVarVal)->AsArgList() : nullptr;
7493 copy->gtCallMoreFlags = tree->gtCallMoreFlags;
7494 copy->gtCallLateArgs = tree->gtCallLateArgs
7495 ? gtCloneExpr(tree->gtCallLateArgs, addFlags, deepVarNum, deepVarVal)->AsArgList()
7498 #if !FEATURE_FIXED_OUT_ARGS
7499 copy->regArgList = tree->regArgList;
7500 copy->regArgListCount = tree->regArgListCount;
7503 // The call sig comes from the EE and doesn't change throughout the compilation process, meaning
7504 // we only really need one physical copy of it. Therefore a shallow pointer copy will suffice.
7505 // (Note that this still holds even if the tree we are cloning was created by an inlinee compiler,
7506 // because the inlinee still uses the inliner's memory allocator anyway.)
7507 copy->callSig = tree->callSig;
7509 copy->gtCallType = tree->gtCallType;
7510 copy->gtReturnType = tree->gtReturnType;
7511 copy->gtControlExpr = tree->gtControlExpr;
7513 /* Copy the union */
7514 if (tree->gtCallType == CT_INDIRECT)
7516 copy->gtCallCookie =
7517 tree->gtCallCookie ? gtCloneExpr(tree->gtCallCookie, addFlags, deepVarNum, deepVarVal) : nullptr;
7518 copy->gtCallAddr = tree->gtCallAddr ? gtCloneExpr(tree->gtCallAddr, addFlags, deepVarNum, deepVarVal) : nullptr;
7520 else if (tree->IsVirtualStub())
7522 copy->gtCallMethHnd = tree->gtCallMethHnd;
7523 copy->gtStubCallStubAddr = tree->gtStubCallStubAddr;
7527 copy->gtCallMethHnd = tree->gtCallMethHnd;
7528 copy->gtInlineCandidateInfo = nullptr;
7531 if (tree->fgArgInfo)
7533 // Create and initialize the fgArgInfo for our copy of the call tree
7534 copy->fgArgInfo = new (this, CMK_Unknown) fgArgInfo(copy, tree);
7538 copy->fgArgInfo = nullptr;
7541 copy->gtRetClsHnd = tree->gtRetClsHnd;
7543 #if FEATURE_MULTIREG_RET
7544 copy->gtReturnTypeDesc = tree->gtReturnTypeDesc;
7547 #ifdef FEATURE_READYTORUN_COMPILER
7548 copy->setEntryPoint(tree->gtEntryPoint);
7551 #if defined(DEBUG) || defined(INLINE_DATA)
7552 copy->gtInlineObservation = tree->gtInlineObservation;
7553 copy->gtRawILOffset = tree->gtCall.gtRawILOffset;
7556 copy->CopyOtherRegFlags(tree);
7561 //------------------------------------------------------------------------
7562 // gtCloneCandidateCall: clone a call that is an inline or guarded
7563 // devirtualization candidate (~ any call that can have a GT_RET_EXPR)
7566 // If the call really is a candidate, the caller must take additional steps
7567 // after cloning to re-establish candidate info and the relationship between
7568 // the candidate and any associated GT_RET_EXPR.
7571 // call - the call to clone
7574 // Cloned copy of call and all subtrees.
7576 GenTreeCall* Compiler::gtCloneCandidateCall(GenTreeCall* call)
7578 assert(call->IsInlineCandidate() || call->IsGuardedDevirtualizationCandidate());
7580 GenTreeCall* result = gtCloneExprCallHelper(call);
7582 // There is some common post-processing in gtCloneExpr that we reproduce
7583 // here, for the fields that make sense for candidate calls.
7584 result->gtFlags |= call->gtFlags;
7587 result->gtDebugFlags |= (call->gtDebugFlags & ~GTF_DEBUG_NODE_MASK);
7590 result->CopyReg(call);
7595 //------------------------------------------------------------------------
7596 // gtReplaceTree: Replace a tree with a new tree.
7599 // stmt - The top-level root stmt of the tree being replaced.
7600 // Must not be null.
7601 // tree - The tree being replaced. Must not be null.
7602 // replacementTree - The replacement tree. Must not be null.
7605 // The tree node that replaces the old tree.
7608 // The sequencing of the stmt has been done.
7611 // The caller must ensure that the original statement has been sequenced,
7612 // and the side effect flags are updated on the statement nodes,
7613 // but this method will sequence 'replacementTree', and insert it into the
7614 // proper place in the statement sequence.
7616 GenTree* Compiler::gtReplaceTree(GenTreeStmt* stmt, GenTree* tree, GenTree* replacementTree)
7618 assert(fgStmtListThreaded);
7619 assert(tree != nullptr);
7620 assert(stmt != nullptr);
7621 assert(replacementTree != nullptr);
7623 GenTree** treePtr = nullptr;
7624 GenTree* treeParent = tree->gtGetParent(&treePtr);
7626 assert(treeParent != nullptr || tree == stmt->gtStmtExpr);
7628 if (treePtr == nullptr)
7630 // Replace the stmt expr and rebuild the linear order for "stmt".
7631 assert(treeParent == nullptr);
7632 assert(fgOrder != FGOrderLinear);
7633 stmt->gtStmtExpr = tree;
7638 assert(treeParent != nullptr);
7640 // Check to see if the node to be replaced is a call argument and if so,
7641 // set `treeParent` to the call node.
7642 GenTree* cursor = treeParent;
7643 while ((cursor != nullptr) && (cursor->OperGet() == GT_LIST))
7645 cursor = cursor->gtNext;
7648 if ((cursor != nullptr) && (cursor->OperGet() == GT_CALL))
7650 treeParent = cursor;
7655 assert(treeParent->TryGetUse(tree, &useEdge));
7656 assert(useEdge == treePtr);
7659 GenTree* treeFirstNode = fgGetFirstNode(tree);
7660 GenTree* treeLastNode = tree;
7661 GenTree* treePrevNode = treeFirstNode->gtPrev;
7662 GenTree* treeNextNode = treeLastNode->gtNext;
7664 treeParent->ReplaceOperand(treePtr, replacementTree);
7666 // Build the linear order for "replacementTree".
7667 fgSetTreeSeq(replacementTree, treePrevNode);
7669 // Restore linear-order Prev and Next for "replacementTree".
7670 if (treePrevNode != nullptr)
7672 treeFirstNode = fgGetFirstNode(replacementTree);
7673 treeFirstNode->gtPrev = treePrevNode;
7674 treePrevNode->gtNext = treeFirstNode;
7678 // Update the linear oder start of "stmt" if treeFirstNode
7679 // appears to have replaced the original first node.
7680 assert(treeFirstNode == stmt->gtStmtList);
7681 stmt->gtStmtList = fgGetFirstNode(replacementTree);
7684 if (treeNextNode != nullptr)
7686 treeLastNode = replacementTree;
7687 treeLastNode->gtNext = treeNextNode;
7688 treeNextNode->gtPrev = treeLastNode;
7692 return replacementTree;
7695 //------------------------------------------------------------------------
7696 // gtUpdateSideEffects: Update the side effects of a tree and its ancestors
7699 // stmt - The tree's statement
7700 // tree - Tree to update the side effects for
7702 // Note: If tree's order hasn't been established, the method updates side effect
7703 // flags on all statement's nodes.
7705 void Compiler::gtUpdateSideEffects(GenTreeStmt* stmt, GenTree* tree)
7707 if (fgStmtListThreaded)
7709 gtUpdateTreeAncestorsSideEffects(tree);
7713 gtUpdateStmtSideEffects(stmt);
7717 //------------------------------------------------------------------------
7718 // gtUpdateTreeAncestorsSideEffects: Update the side effects of a tree and its ancestors
7719 // when statement order has been established.
7722 // tree - Tree to update the side effects for
7724 void Compiler::gtUpdateTreeAncestorsSideEffects(GenTree* tree)
7726 assert(fgStmtListThreaded);
7727 while (tree != nullptr)
7729 gtUpdateNodeSideEffects(tree);
7730 tree = tree->gtGetParent(nullptr);
7734 //------------------------------------------------------------------------
7735 // gtUpdateStmtSideEffects: Update the side effects for statement tree nodes.
7738 // stmt - The statement to update side effects on
7740 void Compiler::gtUpdateStmtSideEffects(GenTreeStmt* stmt)
7742 fgWalkTree(&stmt->gtStmtExpr, fgUpdateSideEffectsPre, fgUpdateSideEffectsPost);
7745 //------------------------------------------------------------------------
7746 // gtUpdateNodeOperSideEffects: Update the side effects based on the node operation.
7749 // tree - Tree to update the side effects on
7752 // This method currently only updates GTF_EXCEPT, GTF_ASG, and GTF_CALL flags.
7753 // The other side effect flags may remain unnecessarily (conservatively) set.
7754 // The caller of this method is expected to update the flags based on the children's flags.
7756 void Compiler::gtUpdateNodeOperSideEffects(GenTree* tree)
7758 if (tree->OperMayThrow(this))
7760 tree->gtFlags |= GTF_EXCEPT;
7764 tree->gtFlags &= ~GTF_EXCEPT;
7765 if (tree->OperIsIndirOrArrLength())
7767 tree->gtFlags |= GTF_IND_NONFAULTING;
7771 if (tree->OperRequiresAsgFlag())
7773 tree->gtFlags |= GTF_ASG;
7777 tree->gtFlags &= ~GTF_ASG;
7780 if (tree->OperRequiresCallFlag(this))
7782 tree->gtFlags |= GTF_CALL;
7786 tree->gtFlags &= ~GTF_CALL;
7790 //------------------------------------------------------------------------
7791 // gtUpdateNodeSideEffects: Update the side effects based on the node operation and
7792 // children's side efects.
7795 // tree - Tree to update the side effects on
7798 // This method currently only updates GTF_EXCEPT and GTF_ASG flags. The other side effect
7799 // flags may remain unnecessarily (conservatively) set.
7801 void Compiler::gtUpdateNodeSideEffects(GenTree* tree)
7803 gtUpdateNodeOperSideEffects(tree);
7804 unsigned nChildren = tree->NumChildren();
7805 for (unsigned childNum = 0; childNum < nChildren; childNum++)
7807 GenTree* child = tree->GetChild(childNum);
7808 if (child != nullptr)
7810 tree->gtFlags |= (child->gtFlags & GTF_ALL_EFFECT);
7815 //------------------------------------------------------------------------
7816 // fgUpdateSideEffectsPre: Update the side effects based on the tree operation.
7819 // pTree - Pointer to the tree to update the side effects
7820 // fgWalkPre - Walk data
7823 // This method currently only updates GTF_EXCEPT and GTF_ASG flags. The other side effect
7824 // flags may remain unnecessarily (conservatively) set.
7826 Compiler::fgWalkResult Compiler::fgUpdateSideEffectsPre(GenTree** pTree, fgWalkData* fgWalkPre)
7828 fgWalkPre->compiler->gtUpdateNodeOperSideEffects(*pTree);
7830 return WALK_CONTINUE;
7833 //------------------------------------------------------------------------
7834 // fgUpdateSideEffectsPost: Update the side effects of the parent based on the tree's flags.
7837 // pTree - Pointer to the tree
7838 // fgWalkPost - Walk data
7841 // The routine is used for updating the stale side effect flags for ancestor
7842 // nodes starting from treeParent up to the top-level stmt expr.
7844 Compiler::fgWalkResult Compiler::fgUpdateSideEffectsPost(GenTree** pTree, fgWalkData* fgWalkPost)
7846 GenTree* tree = *pTree;
7847 GenTree* parent = fgWalkPost->parent;
7848 if (parent != nullptr)
7850 parent->gtFlags |= (tree->gtFlags & GTF_ALL_EFFECT);
7852 return WALK_CONTINUE;
7855 /*****************************************************************************
7857 * Compares two trees and returns true when both trees are the same.
7858 * Instead of fully comparing the two trees this method can just return false.
7859 * Thus callers should not assume that the trees are different when false is returned.
7860 * Only when true is returned can the caller perform code optimizations.
7861 * The current implementation only compares a limited set of LEAF/CONST node
7862 * and returns false for all othere trees.
7864 bool Compiler::gtCompareTree(GenTree* op1, GenTree* op2)
7866 /* Make sure that both trees are of the same GT node kind */
7867 if (op1->OperGet() != op2->OperGet())
7872 /* Make sure that both trees are returning the same type */
7873 if (op1->gtType != op2->gtType)
7878 /* Figure out what kind of a node we have */
7880 genTreeOps oper = op1->OperGet();
7881 unsigned kind = op1->OperKind();
7883 /* Is this a constant or leaf node? */
7885 if (kind & (GTK_CONST | GTK_LEAF))
7890 if ((op1->gtIntCon.gtIconVal == op2->gtIntCon.gtIconVal) && GenTree::SameIconHandleFlag(op1, op2))
7897 if (op1->gtLngCon.gtLconVal == op2->gtLngCon.gtLconVal)
7904 if (op1->gtStrCon.gtSconCPX == op2->gtStrCon.gtSconCPX)
7911 if (op1->gtLclVarCommon.gtLclNum == op2->gtLclVarCommon.gtLclNum)
7918 if (op1->gtClsVar.gtClsVarHnd == op2->gtClsVar.gtClsVarHnd)
7925 // we return false for these unhandled 'oper' kinds
7932 GenTree* Compiler::gtGetThisArg(GenTreeCall* call)
7934 if (call->gtCallObjp != nullptr)
7936 if (call->gtCallObjp->gtOper != GT_NOP && call->gtCallObjp->gtOper != GT_ASG)
7938 if (!(call->gtCallObjp->gtFlags & GTF_LATE_ARG))
7940 return call->gtCallObjp;
7944 if (call->gtCallLateArgs)
7946 unsigned argNum = 0;
7947 fgArgTabEntry* thisArgTabEntry = gtArgEntryByArgNum(call, argNum);
7948 GenTree* result = thisArgTabEntry->node;
7950 #if !FEATURE_FIXED_OUT_ARGS && defined(DEBUG)
7951 regNumber thisReg = REG_ARG_0;
7952 GenTree* lateArgs = call->gtCallLateArgs;
7953 regList list = call->regArgList;
7955 while (lateArgs != NULL)
7957 assert(lateArgs->gtOper == GT_LIST);
7958 assert(index < call->regArgListCount);
7959 regNumber curArgReg = list[index];
7960 if (curArgReg == thisReg)
7962 assert(result == lateArgs->gtOp.gtOp1);
7965 lateArgs = lateArgs->gtOp.gtOp2;
7968 #endif // !FEATURE_FIXED_OUT_ARGS && defined(DEBUG)
7975 bool GenTree::gtSetFlags() const
7978 // When FEATURE_SET_FLAGS (_TARGET_ARM_) is active the method returns true
7979 // when the gtFlags has the flag GTF_SET_FLAGS set
7980 // otherwise the architecture will be have instructions that typically set
7981 // the flags and this method will return true.
7983 // Exceptions: GT_IND (load/store) is not allowed to set the flags
7984 // and on XARCH the GT_MUL/GT_DIV and all overflow instructions
7985 // do not set the condition flags
7987 // Precondition we have a GTK_SMPOP
7989 if (!varTypeIsIntegralOrI(TypeGet()) && (TypeGet() != TYP_VOID))
7994 if (((gtFlags & GTF_SET_FLAGS) != 0) && (gtOper != GT_IND))
7996 // GTF_SET_FLAGS is not valid on GT_IND and is overlaid with GTF_NONFAULTING_IND
8005 bool GenTree::gtRequestSetFlags()
8007 bool result = false;
8009 #if FEATURE_SET_FLAGS
8010 // This method is a Nop unless FEATURE_SET_FLAGS is defined
8012 // In order to set GTF_SET_FLAGS
8013 // we must have a GTK_SMPOP
8014 // and we have a integer or machine size type (not floating point or TYP_LONG on 32-bit)
8016 if (!OperIsSimple())
8019 if (!varTypeIsIntegralOrI(TypeGet()))
8026 // These will turn into simple load from memory instructions
8027 // and we can't force the setting of the flags on load from memory
8032 // These instructions don't set the flags (on x86/x64)
8037 // Otherwise we can set the flags for this gtOper
8038 // and codegen must set the condition flags.
8040 gtFlags |= GTF_SET_FLAGS;
8044 #endif // FEATURE_SET_FLAGS
8046 // Codegen for this tree must set the condition flags if
8047 // this method returns true.
8052 unsigned GenTree::NumChildren()
8054 if (OperIsConst() || OperIsLeaf())
8058 else if (OperIsUnary())
8060 if (OperGet() == GT_NOP || OperGet() == GT_RETURN || OperGet() == GT_RETFILT)
8062 if (gtOp.gtOp1 == nullptr)
8076 else if (OperIsBinary())
8078 // All binary operators except LEA have at least one arg; the second arg may sometimes be null, however.
8079 if (OperGet() == GT_LEA)
8081 unsigned childCount = 0;
8082 if (gtOp.gtOp1 != nullptr)
8086 if (gtOp.gtOp2 != nullptr)
8092 #ifdef FEATURE_HW_INTRINSICS
8093 // GT_HWIntrinsic require special handling
8094 if (OperGet() == GT_HWIntrinsic)
8096 if (gtOp.gtOp1 == nullptr)
8102 assert(gtOp.gtOp1 != nullptr);
8103 if (gtOp.gtOp2 == nullptr)
8120 case GT_ARR_BOUNDS_CHECK:
8123 #endif // FEATURE_SIMD
8124 #ifdef FEATURE_HW_INTRINSICS
8125 case GT_HW_INTRINSIC_CHK:
8126 #endif // FEATURE_HW_INTRINSICS
8134 return 1 + AsArrElem()->gtArrRank;
8140 case GT_STORE_DYN_BLK:
8145 GenTreeCall* call = AsCall();
8146 unsigned res = 0; // arg list(s) (including late args).
8147 if (call->gtCallObjp != nullptr)
8151 if (call->gtCallArgs != nullptr)
8155 if (call->gtCallLateArgs != nullptr)
8157 res++; // Add late args?
8159 if (call->gtControlExpr != nullptr)
8164 if (call->gtCallType == CT_INDIRECT)
8166 if (call->gtCallCookie != nullptr)
8170 if (call->gtCallAddr != nullptr)
8185 GenTree* GenTree::GetChild(unsigned childNum)
8187 assert(childNum < NumChildren()); // Precondition.
8188 assert(NumChildren() <= MAX_CHILDREN);
8189 assert(!(OperIsConst() || OperIsLeaf()));
8192 return AsUnOp()->gtOp1;
8194 // Special case for assignment of dynamic block.
8195 // This code is here to duplicate the former case where the size may be evaluated prior to the
8196 // source and destination addresses. In order to do this, we treat the size as a child of the
8198 // TODO-1stClassStructs: Revisit the need to duplicate former behavior, so that we can remove
8199 // these special cases.
8200 if ((OperGet() == GT_ASG) && (gtOp.gtOp1->OperGet() == GT_DYN_BLK) && (childNum == 2))
8202 return gtOp.gtOp1->AsDynBlk()->gtDynamicSize;
8204 else if (OperIsBinary())
8206 if (OperIsAddrMode())
8208 // If this is the first (0th) child, only return op1 if it is non-null
8209 // Otherwise, we return gtOp2.
8210 if (childNum == 0 && AsOp()->gtOp1 != nullptr)
8212 return AsOp()->gtOp1;
8214 return AsOp()->gtOp2;
8216 // TODO-Cleanup: Consider handling ReverseOps here, and then we wouldn't have to handle it in
8217 // fgGetFirstNode(). However, it seems that it causes loop hoisting behavior to change.
8220 return AsOp()->gtOp1;
8224 return AsOp()->gtOp2;
8236 return AsCmpXchg()->gtOpLocation;
8238 return AsCmpXchg()->gtOpValue;
8240 return AsCmpXchg()->gtOpComparand;
8244 case GT_ARR_BOUNDS_CHECK:
8247 #endif // FEATURE_SIMD
8248 #ifdef FEATURE_HW_INTRINSICS
8249 case GT_HW_INTRINSIC_CHK:
8250 #endif // FEATURE_HW_INTRINSICS
8254 return AsBoundsChk()->gtIndex;
8256 return AsBoundsChk()->gtArrLen;
8261 case GT_STORE_DYN_BLK:
8265 return AsDynBlk()->Addr();
8267 return AsDynBlk()->Data();
8269 return AsDynBlk()->gtDynamicSize;
8277 return AsDynBlk()->gtEvalSizeFirst ? AsDynBlk()->gtDynamicSize : AsDynBlk()->Addr();
8279 return AsDynBlk()->gtEvalSizeFirst ? AsDynBlk()->Addr() : AsDynBlk()->gtDynamicSize;
8285 return AsField()->gtFldObj;
8288 return AsStmt()->gtStmtExpr;
8293 return AsArrElem()->gtArrObj;
8297 return AsArrElem()->gtArrInds[childNum - 1];
8304 return AsArrOffs()->gtOffset;
8306 return AsArrOffs()->gtIndex;
8308 return AsArrOffs()->gtArrObj;
8315 // The if chain below assumes that all possible children are non-null.
8316 // If some are null, "virtually skip them."
8317 // If there isn't "virtually skip it."
8318 GenTreeCall* call = AsCall();
8320 if (call->gtCallObjp == nullptr)
8324 if (childNum >= 1 && call->gtCallArgs == nullptr)
8328 if (childNum >= 2 && call->gtCallLateArgs == nullptr)
8332 if (childNum >= 3 && call->gtControlExpr == nullptr)
8336 if (call->gtCallType == CT_INDIRECT)
8338 if (childNum >= 4 && call->gtCallCookie == nullptr)
8346 return call->gtCallObjp;
8348 else if (childNum == 1)
8350 return call->gtCallArgs;
8352 else if (childNum == 2)
8354 return call->gtCallLateArgs;
8356 else if (childNum == 3)
8358 return call->gtControlExpr;
8362 assert(call->gtCallType == CT_INDIRECT);
8365 return call->gtCallCookie;
8369 assert(childNum == 5);
8370 return call->gtCallAddr;
8382 GenTreeUseEdgeIterator::GenTreeUseEdgeIterator()
8383 : m_advance(nullptr), m_node(nullptr), m_edge(nullptr), m_argList(nullptr), m_state(-1)
8387 GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node)
8388 : m_advance(nullptr), m_node(node), m_edge(nullptr), m_argList(nullptr), m_state(0)
8390 assert(m_node != nullptr);
8392 // NOTE: the switch statement below must be updated when introducing new nodes.
8394 switch (m_node->OperGet())
8399 case GT_LCL_VAR_ADDR:
8400 case GT_LCL_FLD_ADDR:
8409 case GT_MEMORYBARRIER:
8414 case GT_START_NONGC:
8415 case GT_START_PREEMPTGC:
8417 #if !FEATURE_EH_FUNCLETS
8419 #endif // !FEATURE_EH_FUNCLETS
8423 case GT_CLS_VAR_ADDR:
8427 case GT_PINVOKE_PROLOG:
8428 case GT_PINVOKE_EPILOG:
8433 // Standard unary operators
8434 case GT_STORE_LCL_VAR:
8435 case GT_STORE_LCL_FLD:
8451 case GT_RUNTIMELOOKUP:
8460 #if FEATURE_ARG_SPLIT
8461 case GT_PUTARG_SPLIT:
8462 #endif // FEATURE_ARG_SPLIT
8464 m_edge = &m_node->AsUnOp()->gtOp1;
8465 assert(*m_edge != nullptr);
8466 m_advance = &GenTreeUseEdgeIterator::Terminate;
8469 // Unary operators with an optional operand
8473 if (m_node->AsUnOp()->gtOp1 == nullptr)
8475 assert(m_node->NullOp1Legal());
8480 m_edge = &m_node->AsUnOp()->gtOp1;
8481 m_advance = &GenTreeUseEdgeIterator::Terminate;
8487 SetEntryStateForList(m_node->AsUnOp()->gtOp1);
8491 SetEntryStateForList(m_node);
8496 if (m_node->AsSIMD()->gtSIMDIntrinsicID == SIMDIntrinsicInitN)
8498 SetEntryStateForList(m_node->AsSIMD()->gtOp1);
8502 SetEntryStateForBinOp();
8505 #endif // FEATURE_SIMD
8507 #ifdef FEATURE_HW_INTRINSICS
8508 case GT_HWIntrinsic:
8509 if (m_node->AsHWIntrinsic()->gtOp1 == nullptr)
8511 assert(m_node->NullOp1Legal());
8514 else if (m_node->AsHWIntrinsic()->gtOp1->OperIsList())
8516 SetEntryStateForList(m_node->AsHWIntrinsic()->gtOp1);
8520 SetEntryStateForBinOp();
8523 #endif // FEATURE_HW_INTRINSICS
8525 // LEA, which may have no first operand
8527 if (m_node->AsAddrMode()->gtOp1 == nullptr)
8529 m_edge = &m_node->AsAddrMode()->gtOp2;
8530 m_advance = &GenTreeUseEdgeIterator::Terminate;
8534 SetEntryStateForBinOp();
8540 m_edge = &m_node->AsCmpXchg()->gtOpLocation;
8541 assert(*m_edge != nullptr);
8542 m_advance = &GenTreeUseEdgeIterator::AdvanceCmpXchg;
8545 case GT_ARR_BOUNDS_CHECK:
8548 #endif // FEATURE_SIMD
8549 #ifdef FEATURE_HW_INTRINSICS
8550 case GT_HW_INTRINSIC_CHK:
8551 #endif // FEATURE_HW_INTRINSICS
8552 m_edge = &m_node->AsBoundsChk()->gtIndex;
8553 assert(*m_edge != nullptr);
8554 m_advance = &GenTreeUseEdgeIterator::AdvanceBoundsChk;
8558 if (m_node->AsField()->gtFldObj == nullptr)
8564 m_edge = &m_node->AsField()->gtFldObj;
8565 m_advance = &GenTreeUseEdgeIterator::Terminate;
8570 if (m_node->AsStmt()->gtStmtExpr == nullptr)
8576 m_edge = &m_node->AsStmt()->gtStmtExpr;
8577 m_advance = &GenTreeUseEdgeIterator::Terminate;
8582 m_edge = &m_node->AsArrElem()->gtArrObj;
8583 assert(*m_edge != nullptr);
8584 m_advance = &GenTreeUseEdgeIterator::AdvanceArrElem;
8588 m_edge = &m_node->AsArrOffs()->gtOffset;
8589 assert(*m_edge != nullptr);
8590 m_advance = &GenTreeUseEdgeIterator::AdvanceArrOffset;
8595 GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
8596 m_edge = dynBlock->gtEvalSizeFirst ? &dynBlock->gtDynamicSize : &dynBlock->gtOp1;
8597 assert(*m_edge != nullptr);
8598 m_advance = &GenTreeUseEdgeIterator::AdvanceDynBlk;
8602 case GT_STORE_DYN_BLK:
8604 GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
8605 if (dynBlock->gtEvalSizeFirst)
8607 m_edge = &dynBlock->gtDynamicSize;
8611 m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp2 : &dynBlock->gtOp1;
8613 assert(*m_edge != nullptr);
8615 m_advance = &GenTreeUseEdgeIterator::AdvanceStoreDynBlk;
8620 AdvanceCall<CALL_INSTANCE>();
8625 assert(m_node->OperIsBinary());
8626 SetEntryStateForBinOp();
8631 //------------------------------------------------------------------------
8632 // GenTreeUseEdgeIterator::AdvanceCmpXchg: produces the next operand of a CmpXchg node and advances the state.
8634 void GenTreeUseEdgeIterator::AdvanceCmpXchg()
8639 m_edge = &m_node->AsCmpXchg()->gtOpValue;
8643 m_edge = &m_node->AsCmpXchg()->gtOpComparand;
8644 m_advance = &GenTreeUseEdgeIterator::Terminate;
8650 assert(*m_edge != nullptr);
8653 //------------------------------------------------------------------------
8654 // GenTreeUseEdgeIterator::AdvanceBoundsChk: produces the next operand of a BoundsChk node and advances the state.
8656 void GenTreeUseEdgeIterator::AdvanceBoundsChk()
8658 m_edge = &m_node->AsBoundsChk()->gtArrLen;
8659 assert(*m_edge != nullptr);
8660 m_advance = &GenTreeUseEdgeIterator::Terminate;
8663 //------------------------------------------------------------------------
8664 // GenTreeUseEdgeIterator::AdvanceArrElem: produces the next operand of a ArrElem node and advances the state.
8666 // Because these nodes are variadic, this function uses `m_state` to index into the list of array indices.
8668 void GenTreeUseEdgeIterator::AdvanceArrElem()
8670 if (m_state < m_node->AsArrElem()->gtArrRank)
8672 m_edge = &m_node->AsArrElem()->gtArrInds[m_state];
8673 assert(*m_edge != nullptr);
8682 //------------------------------------------------------------------------
8683 // GenTreeUseEdgeIterator::AdvanceArrOffset: produces the next operand of a ArrOffset node and advances the state.
8685 void GenTreeUseEdgeIterator::AdvanceArrOffset()
8690 m_edge = &m_node->AsArrOffs()->gtIndex;
8694 m_edge = &m_node->AsArrOffs()->gtArrObj;
8695 m_advance = &GenTreeUseEdgeIterator::Terminate;
8701 assert(*m_edge != nullptr);
8704 //------------------------------------------------------------------------
8705 // GenTreeUseEdgeIterator::AdvanceDynBlk: produces the next operand of a DynBlk node and advances the state.
8707 void GenTreeUseEdgeIterator::AdvanceDynBlk()
8709 GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
8711 m_edge = dynBlock->gtEvalSizeFirst ? &dynBlock->gtOp1 : &dynBlock->gtDynamicSize;
8712 assert(*m_edge != nullptr);
8713 m_advance = &GenTreeUseEdgeIterator::Terminate;
8716 //------------------------------------------------------------------------
8717 // GenTreeUseEdgeIterator::AdvanceStoreDynBlk: produces the next operand of a StoreDynBlk node and advances the state.
8719 // These nodes are moderately complicated but rare enough that templating this function is probably not
8720 // worth the extra complexity.
8722 void GenTreeUseEdgeIterator::AdvanceStoreDynBlk()
8724 GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
8725 if (dynBlock->gtEvalSizeFirst)
8730 m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp2 : &dynBlock->gtOp1;
8734 m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp1 : &dynBlock->gtOp2;
8735 m_advance = &GenTreeUseEdgeIterator::Terminate;
8746 m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp1 : &dynBlock->gtOp2;
8750 m_edge = &dynBlock->gtDynamicSize;
8751 m_advance = &GenTreeUseEdgeIterator::Terminate;
8758 assert(*m_edge != nullptr);
8761 //------------------------------------------------------------------------
8762 // GenTreeUseEdgeIterator::AdvanceBinOp: produces the next operand of a binary node and advances the state.
8764 // This function must be instantiated s.t. `ReverseOperands` is `true` iff the node is marked with the
8765 // `GTF_REVERSE_OPS` flag.
8767 template <bool ReverseOperands>
8768 void GenTreeUseEdgeIterator::AdvanceBinOp()
8770 assert(ReverseOperands == ((m_node->gtFlags & GTF_REVERSE_OPS) != 0));
8772 m_edge = !ReverseOperands ? &m_node->AsOp()->gtOp2 : &m_node->AsOp()->gtOp1;
8773 assert(*m_edge != nullptr);
8774 m_advance = &GenTreeUseEdgeIterator::Terminate;
8777 //------------------------------------------------------------------------
8778 // GenTreeUseEdgeIterator::SetEntryStateForBinOp: produces the first operand of a binary node and chooses
8779 // the appropriate advance function.
8781 void GenTreeUseEdgeIterator::SetEntryStateForBinOp()
8783 assert(m_node != nullptr);
8784 assert(m_node->OperIsBinary());
8786 GenTreeOp* const node = m_node->AsOp();
8788 if (node->gtOp2 == nullptr)
8790 assert(node->gtOp1 != nullptr);
8791 assert(node->NullOp2Legal());
8792 m_edge = &node->gtOp1;
8793 m_advance = &GenTreeUseEdgeIterator::Terminate;
8795 else if ((node->gtFlags & GTF_REVERSE_OPS) != 0)
8797 m_edge = &m_node->AsOp()->gtOp2;
8798 m_advance = &GenTreeUseEdgeIterator::AdvanceBinOp<true>;
8802 m_edge = &m_node->AsOp()->gtOp1;
8803 m_advance = &GenTreeUseEdgeIterator::AdvanceBinOp<false>;
8807 //------------------------------------------------------------------------
8808 // GenTreeUseEdgeIterator::AdvanceList: produces the next operand of a variadic node and advances the state.
8810 // This function does not use `m_state` for anything meaningful; it simply walks the `m_argList` until
8811 // there are no further entries.
8813 void GenTreeUseEdgeIterator::AdvanceList()
8815 assert(m_state == 0);
8817 if (m_argList == nullptr)
8823 GenTreeArgList* listNode = m_argList->AsArgList();
8824 m_edge = &listNode->gtOp1;
8825 m_argList = listNode->Rest();
8829 //------------------------------------------------------------------------
8830 // GenTreeUseEdgeIterator::SetEntryStateForList: produces the first operand of a list node.
8832 void GenTreeUseEdgeIterator::SetEntryStateForList(GenTree* list)
8835 m_advance = &GenTreeUseEdgeIterator::AdvanceList;
8839 //------------------------------------------------------------------------
8840 // GenTreeUseEdgeIterator::AdvanceCall: produces the next operand of a call node and advances the state.
8842 // This function is a bit tricky: in order to avoid doing unnecessary work, it is instantiated with the
8843 // state number the iterator will be in when it is called. For example, `AdvanceCall<CALL_INSTANCE>`
8844 // is the instantiation used when the iterator is at the `CALL_INSTANCE` state (i.e. the entry state).
8845 // This sort of templating allows each state to avoid processing earlier states without unnecessary
8846 // duplication of code.
8848 // Note that this method expands the argument lists (`gtCallArgs` and `gtCallLateArgs`) into their
8849 // component operands.
8851 template <int state>
8852 void GenTreeUseEdgeIterator::AdvanceCall()
8854 GenTreeCall* const call = m_node->AsCall();
8859 m_argList = call->gtCallArgs;
8860 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_ARGS>;
8861 if (call->gtCallObjp != nullptr)
8863 m_edge = &call->gtCallObjp;
8869 if (m_argList != nullptr)
8871 GenTreeArgList* argNode = m_argList->AsArgList();
8872 m_edge = &argNode->gtOp1;
8873 m_argList = argNode->Rest();
8876 m_argList = call->gtCallLateArgs;
8877 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_LATE_ARGS>;
8880 case CALL_LATE_ARGS:
8881 if (m_argList != nullptr)
8883 GenTreeArgList* argNode = m_argList->AsArgList();
8884 m_edge = &argNode->gtOp1;
8885 m_argList = argNode->Rest();
8888 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_CONTROL_EXPR>;
8891 case CALL_CONTROL_EXPR:
8892 if (call->gtControlExpr != nullptr)
8894 if (call->gtCallType == CT_INDIRECT)
8896 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_COOKIE>;
8900 m_advance = &GenTreeUseEdgeIterator::Terminate;
8902 m_edge = &call->gtControlExpr;
8905 else if (call->gtCallType != CT_INDIRECT)
8913 assert(call->gtCallType == CT_INDIRECT);
8915 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_ADDRESS>;
8916 if (call->gtCallCookie != nullptr)
8918 m_edge = &call->gtCallCookie;
8924 assert(call->gtCallType == CT_INDIRECT);
8926 m_advance = &GenTreeUseEdgeIterator::Terminate;
8927 if (call->gtCallAddr != nullptr)
8929 m_edge = &call->gtCallAddr;
8938 //------------------------------------------------------------------------
8939 // GenTreeUseEdgeIterator::Terminate: advances the iterator to the terminal state.
8941 void GenTreeUseEdgeIterator::Terminate()
8946 //------------------------------------------------------------------------
8947 // GenTreeUseEdgeIterator::operator++: advances the iterator to the next operand.
8949 GenTreeUseEdgeIterator& GenTreeUseEdgeIterator::operator++()
8951 // If we've reached the terminal state, do nothing.
8954 (this->*m_advance)();
8960 GenTreeUseEdgeIterator GenTree::UseEdgesBegin()
8962 return GenTreeUseEdgeIterator(this);
8965 GenTreeUseEdgeIterator GenTree::UseEdgesEnd()
8967 return GenTreeUseEdgeIterator();
8970 IteratorPair<GenTreeUseEdgeIterator> GenTree::UseEdges()
8972 return MakeIteratorPair(UseEdgesBegin(), UseEdgesEnd());
8975 GenTreeOperandIterator GenTree::OperandsBegin()
8977 return GenTreeOperandIterator(this);
8980 GenTreeOperandIterator GenTree::OperandsEnd()
8982 return GenTreeOperandIterator();
8985 IteratorPair<GenTreeOperandIterator> GenTree::Operands()
8987 return MakeIteratorPair(OperandsBegin(), OperandsEnd());
8990 bool GenTree::Precedes(GenTree* other)
8992 assert(other != nullptr);
8994 for (GenTree* node = gtNext; node != nullptr; node = node->gtNext)
9007 /* static */ int GenTree::gtDispFlags(unsigned flags, unsigned debugFlags)
9009 int charsDisplayed = 11; // 11 is the "baseline" number of flag characters displayed
9011 printf("%c", (flags & GTF_ASG) ? 'A' : (IsContained(flags) ? 'c' : '-'));
9012 printf("%c", (flags & GTF_CALL) ? 'C' : '-');
9013 printf("%c", (flags & GTF_EXCEPT) ? 'X' : '-');
9014 printf("%c", (flags & GTF_GLOB_REF) ? 'G' : '-');
9015 printf("%c", (debugFlags & GTF_DEBUG_NODE_MORPHED) ? '+' : // First print '+' if GTF_DEBUG_NODE_MORPHED is set
9016 (flags & GTF_ORDER_SIDEEFF) ? 'O' : '-'); // otherwise print 'O' or '-'
9017 printf("%c", (flags & GTF_COLON_COND) ? '?' : '-');
9018 printf("%c", (flags & GTF_DONT_CSE) ? 'N' : // N is for No cse
9019 (flags & GTF_MAKE_CSE) ? 'H' : '-'); // H is for Hoist this expr
9020 printf("%c", (flags & GTF_REVERSE_OPS) ? 'R' : '-');
9021 printf("%c", (flags & GTF_UNSIGNED) ? 'U' : (flags & GTF_BOOLEAN) ? 'B' : '-');
9022 #if FEATURE_SET_FLAGS
9023 printf("%c", (flags & GTF_SET_FLAGS) ? 'S' : '-');
9026 printf("%c", (flags & GTF_LATE_ARG) ? 'L' : '-');
9027 printf("%c", (flags & GTF_SPILLED) ? 'z' : (flags & GTF_SPILL) ? 'Z' : '-');
9029 return charsDisplayed;
9032 /*****************************************************************************/
9034 void Compiler::gtDispNodeName(GenTree* tree)
9036 /* print the node name */
9041 if (tree->gtOper < GT_COUNT)
9043 name = GenTree::OpName(tree->OperGet());
9050 char* bufp = &buf[0];
9052 if ((tree->gtOper == GT_CNS_INT) && tree->IsIconHandle())
9054 sprintf_s(bufp, sizeof(buf), " %s(h)%c", name, 0);
9056 else if (tree->gtOper == GT_PUTARG_STK)
9058 sprintf_s(bufp, sizeof(buf), " %s [+0x%02x]%c", name, tree->AsPutArgStk()->getArgOffset(), 0);
9060 else if (tree->gtOper == GT_CALL)
9062 const char* callType = "CALL";
9063 const char* gtfType = "";
9064 const char* ctType = "";
9065 char gtfTypeBuf[100];
9067 if (tree->gtCall.gtCallType == CT_USER_FUNC)
9069 if (tree->gtCall.IsVirtual())
9074 else if (tree->gtCall.gtCallType == CT_HELPER)
9078 else if (tree->gtCall.gtCallType == CT_INDIRECT)
9084 assert(!"Unknown gtCallType");
9087 if (tree->gtFlags & GTF_CALL_NULLCHECK)
9089 gtfType = " nullcheck";
9091 if (tree->gtCall.IsVirtualVtable())
9095 else if (tree->gtCall.IsVirtualStub())
9099 #ifdef FEATURE_READYTORUN_COMPILER
9100 else if (tree->gtCall.IsR2RRelativeIndir())
9102 gtfType = " r2r_ind";
9104 #endif // FEATURE_READYTORUN_COMPILER
9105 else if (tree->gtFlags & GTF_CALL_UNMANAGED)
9107 char* gtfTypeBufWalk = gtfTypeBuf;
9108 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " unman");
9109 if (tree->gtFlags & GTF_CALL_POP_ARGS)
9111 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " popargs");
9113 if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
9115 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " thiscall");
9117 gtfType = gtfTypeBuf;
9120 sprintf_s(bufp, sizeof(buf), " %s%s%s%c", callType, ctType, gtfType, 0);
9122 else if (tree->gtOper == GT_ARR_ELEM)
9124 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s[", name);
9125 for (unsigned rank = tree->gtArrElem.gtArrRank - 1; rank; rank--)
9127 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), ",");
9129 SimpleSprintf_s(bufp, buf, sizeof(buf), "]");
9131 else if (tree->gtOper == GT_ARR_OFFSET || tree->gtOper == GT_ARR_INDEX)
9133 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s[", name);
9134 unsigned char currDim;
9136 if (tree->gtOper == GT_ARR_OFFSET)
9138 currDim = tree->gtArrOffs.gtCurrDim;
9139 rank = tree->gtArrOffs.gtArrRank;
9143 currDim = tree->gtArrIndex.gtCurrDim;
9144 rank = tree->gtArrIndex.gtArrRank;
9147 for (unsigned char dim = 0; dim < rank; dim++)
9149 // Use a defacto standard i,j,k for the dimensions.
9150 // Note that we only support up to rank 3 arrays with these nodes, so we won't run out of characters.
9154 dimChar = 'i' + dim;
9156 else if (dim > currDim)
9161 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "%c", dimChar);
9162 if (dim != rank - 1)
9164 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), ",");
9167 SimpleSprintf_s(bufp, buf, sizeof(buf), "]");
9169 else if (tree->gtOper == GT_LEA)
9171 GenTreeAddrMode* lea = tree->AsAddrMode();
9172 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s(", name);
9173 if (lea->Base() != nullptr)
9175 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "b+");
9177 if (lea->Index() != nullptr)
9179 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "(i*%d)+", lea->gtScale);
9181 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "%d)", lea->Offset());
9183 else if (tree->gtOper == GT_ARR_BOUNDS_CHECK)
9185 switch (tree->gtBoundsChk.gtThrowKind)
9187 case SCK_RNGCHK_FAIL:
9188 sprintf_s(bufp, sizeof(buf), " %s_Rng", name);
9191 sprintf_s(bufp, sizeof(buf), " %s_Arg", name);
9193 case SCK_ARG_RNG_EXCPN:
9194 sprintf_s(bufp, sizeof(buf), " %s_ArgRng", name);
9200 else if (tree->gtOverflowEx())
9202 sprintf_s(bufp, sizeof(buf), " %s_ovfl%c", name, 0);
9204 else if (tree->OperIsBlk() && !tree->OperIsDynBlk())
9206 sprintf_s(bufp, sizeof(buf), " %s(%d)", name, tree->AsBlk()->gtBlkSize);
9210 sprintf_s(bufp, sizeof(buf), " %s%c", name, 0);
9213 if (strlen(buf) < 10)
9215 printf(" %-10s", buf);
9223 //------------------------------------------------------------------------
9224 // gtDispZeroFieldSeq: If this node has a zero fieldSeq annotation
9225 // then print this Field Sequence
9227 void Compiler::gtDispZeroFieldSeq(GenTree* tree)
9229 NodeToFieldSeqMap* map = GetZeroOffsetFieldMap();
9231 // THe most common case is having no entries in this map
9232 if (map->GetCount() > 0)
9234 FieldSeqNode* fldSeq = nullptr;
9235 if (map->Lookup(tree, &fldSeq))
9238 gtDispFieldSeq(fldSeq);
9243 //------------------------------------------------------------------------
9244 // gtDispVN: Utility function that prints a tree's ValueNumber: gtVNPair
9246 void Compiler::gtDispVN(GenTree* tree)
9248 if (tree->gtVNPair.GetLiberal() != ValueNumStore::NoVN)
9250 assert(tree->gtVNPair.GetConservative() != ValueNumStore::NoVN);
9252 vnpPrint(tree->gtVNPair, 0);
9256 //------------------------------------------------------------------------
9257 // gtDispCommonEndLine
9258 // Utility function that prints the following node information
9259 // 1: The associated zero field sequence (if any)
9260 // 2. The register assigned to this node (if any)
9261 // 2. The value number assigned (if any)
9262 // 3. A newline character
9264 void Compiler::gtDispCommonEndLine(GenTree* tree)
9266 gtDispZeroFieldSeq(tree);
9272 //------------------------------------------------------------------------
9273 // gtDispNode: Print a tree to jitstdout.
9276 // tree - the tree to be printed
9277 // indentStack - the specification for the current level of indentation & arcs
9278 // msg - a contextual method (i.e. from the parent) to print
9284 // 'indentStack' may be null, in which case no indentation or arcs are printed
9285 // 'msg' may be null
9287 void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, __in __in_z __in_opt const char* msg, bool isLIR)
9289 bool printPointer = true; // always true..
9290 bool printFlags = true; // always true..
9291 bool printCost = true; // always true..
9299 printf("N%03u ", tree->gtSeqNum);
9300 if (tree->gtCostsInitialized)
9302 printf("(%3u,%3u) ", tree->gtCostEx, tree->gtCostSz);
9308 ") "); // This probably indicates a bug: the node has a sequence number, but not costs.
9313 if (tree->gtOper == GT_STMT)
9315 prev = tree->gtStmt.gtStmtExpr;
9322 bool hasSeqNum = true;
9323 unsigned dotNum = 0;
9327 prev = prev->gtPrev;
9329 if ((prev == nullptr) || (prev == tree))
9336 } while (prev->gtSeqNum == 0);
9338 // If we have an indent stack, don't add additional characters,
9339 // as it will mess up the alignment.
9340 bool displayDotNum = tree->gtOper != GT_STMT && hasSeqNum && (indentStack == nullptr);
9343 printf("N%03u.%02u ", prev->gtSeqNum, dotNum);
9350 if (tree->gtCostsInitialized)
9352 printf("(%3u,%3u) ", tree->gtCostEx, tree->gtCostSz);
9358 // Do better alignment in this case
9368 if (optValnumCSE_phase)
9370 if (IS_CSE_INDEX(tree->gtCSEnum))
9372 printf("CSE #%02d (%s)", GET_CSE_INDEX(tree->gtCSEnum), (IS_CSE_USE(tree->gtCSEnum) ? "use" : "def"));
9380 /* Print the node ID */
9384 if (tree->gtOper >= GT_COUNT)
9386 printf(" **** ILLEGAL NODE ****");
9392 /* First print the flags associated with the node */
9393 switch (tree->gtOper)
9401 case GT_STORE_DYN_BLK:
9404 // We prefer printing V or U
9405 if ((tree->gtFlags & (GTF_IND_VOLATILE | GTF_IND_UNALIGNED)) == 0)
9407 if (tree->gtFlags & GTF_IND_TGTANYWHERE)
9413 if (tree->gtFlags & GTF_IND_TGT_NOT_HEAP)
9419 if (tree->gtFlags & GTF_IND_INVARIANT)
9425 if (tree->gtFlags & GTF_IND_ARR_INDEX)
9431 if (tree->gtFlags & GTF_IND_NONFAULTING)
9433 printf("n"); // print a n for non-faulting
9437 if (tree->gtFlags & GTF_IND_ASG_LHS)
9439 printf("D"); // print a D for definition
9449 if ((tree->gtFlags & (GTF_IND_VOLATILE | GTF_IND_UNALIGNED)) == 0) // We prefer printing V or U over R
9451 if (tree->gtFlags & GTF_INX_REFARR_LAYOUT)
9456 } // R means RefArray
9462 if (tree->gtFlags & GTF_IND_VOLATILE)
9468 if (tree->gtFlags & GTF_IND_UNALIGNED)
9477 if (tree->OperIsInitBlkOp())
9486 if (tree->gtCall.IsInlineCandidate())
9488 if (tree->gtCall.IsGuardedDevirtualizationCandidate())
9499 else if (tree->gtCall.IsGuardedDevirtualizationCandidate())
9505 if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_RETBUFFARG)
9511 if (tree->gtFlags & GTF_CALL_HOISTABLE)
9521 #if !defined(_TARGET_64BIT_)
9524 if (tree->gtFlags & GTF_MUL_64RSLT)
9534 case GT_LCL_VAR_ADDR:
9535 case GT_LCL_FLD_ADDR:
9536 case GT_STORE_LCL_FLD:
9537 case GT_STORE_LCL_VAR:
9538 if (tree->gtFlags & GTF_VAR_USEASG)
9544 if (tree->gtFlags & GTF_VAR_DEF)
9550 if (tree->gtFlags & GTF_VAR_CAST)
9556 if (tree->gtFlags & GTF_VAR_ARR_INDEX)
9572 if (tree->gtFlags & GTF_RELOP_NAN_UN)
9578 if (tree->gtFlags & GTF_RELOP_JMP_USED)
9584 if (tree->gtFlags & GTF_RELOP_QMARK)
9593 printf((tree->gtFlags & GTF_JCMP_TST) ? "T" : "C");
9594 printf((tree->gtFlags & GTF_JCMP_EQ) ? "EQ" : "NE");
9598 if (tree->gtFlags & GTF_FIELD_LIST_HEAD)
9613 /* Then print the general purpose flags */
9614 unsigned flags = tree->gtFlags;
9616 if (tree->OperIsBinary())
9618 genTreeOps oper = tree->OperGet();
9620 // Check for GTF_ADDRMODE_NO_CSE flag on add/mul/shl Binary Operators
9621 if ((oper == GT_ADD) || (oper == GT_MUL) || (oper == GT_LSH))
9623 if ((tree->gtFlags & GTF_ADDRMODE_NO_CSE) != 0)
9625 flags |= GTF_DONT_CSE; // Force the GTF_ADDRMODE_NO_CSE flag to print out like GTF_DONT_CSE
9629 else // !tree->OperIsBinary()
9631 // the GTF_REVERSE flag only applies to binary operations
9632 flags &= ~GTF_REVERSE_OPS; // we use this value for GTF_VAR_ARR_INDEX above
9635 msgLength -= GenTree::gtDispFlags(flags, tree->gtDebugFlags);
9637 printf("%c", (flags & GTF_ASG ) ? 'A' : '-');
9638 printf("%c", (flags & GTF_CALL ) ? 'C' : '-');
9639 printf("%c", (flags & GTF_EXCEPT ) ? 'X' : '-');
9640 printf("%c", (flags & GTF_GLOB_REF ) ? 'G' : '-');
9641 printf("%c", (flags & GTF_ORDER_SIDEEFF ) ? 'O' : '-');
9642 printf("%c", (flags & GTF_COLON_COND ) ? '?' : '-');
9643 printf("%c", (flags & GTF_DONT_CSE ) ? 'N' : // N is for No cse
9644 (flags & GTF_MAKE_CSE ) ? 'H' : '-'); // H is for Hoist this expr
9645 printf("%c", (flags & GTF_REVERSE_OPS ) ? 'R' : '-');
9646 printf("%c", (flags & GTF_UNSIGNED ) ? 'U' :
9647 (flags & GTF_BOOLEAN ) ? 'B' : '-');
9648 printf("%c", (flags & GTF_SET_FLAGS ) ? 'S' : '-');
9649 printf("%c", (flags & GTF_SPILLED ) ? 'z' : '-');
9650 printf("%c", (flags & GTF_SPILL ) ? 'Z' : '-');
9654 // If we're printing a node for LIR, we use the space normally associated with the message
9655 // to display the node's temp name (if any)
9656 const bool hasOperands = tree->OperandsBegin() != tree->OperandsEnd();
9659 assert(msg == nullptr);
9661 // If the tree does not have any operands, we do not display the indent stack. This gives us
9662 // two additional characters for alignment.
9668 if (tree->IsValue())
9670 const size_t bufLength = msgLength - 1;
9671 msg = reinterpret_cast<char*>(alloca(bufLength * sizeof(char)));
9672 sprintf_s(const_cast<char*>(msg), bufLength, "t%d = %s", tree->gtTreeID, hasOperands ? "" : " ");
9676 /* print the msg associated with the node */
9687 printf(isLIR ? " %+*s" : " %-*s", msgLength, msg);
9689 /* Indent the node accordingly */
9690 if (!isLIR || hasOperands)
9692 printIndent(indentStack);
9695 gtDispNodeName(tree);
9697 assert(tree == nullptr || tree->gtOper < GT_COUNT);
9701 /* print the type of the node */
9702 if (tree->gtOper != GT_CAST)
9704 printf(" %-6s", varTypeName(tree->TypeGet()));
9705 if (tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_STORE_LCL_VAR)
9707 LclVarDsc* varDsc = &lvaTable[tree->gtLclVarCommon.gtLclNum];
9708 if (varDsc->lvAddrExposed)
9710 printf("(AX)"); // Variable has address exposed.
9713 if (varDsc->lvUnusedStruct)
9715 assert(varDsc->lvPromoted);
9716 printf("(U)"); // Unused struct
9718 else if (varDsc->lvPromoted)
9720 if (varTypeIsPromotable(varDsc))
9722 printf("(P)"); // Promoted struct
9726 // Promoted implicit by-refs can have this state during
9727 // global morph while they are being rewritten
9728 assert(fgGlobalMorph);
9729 printf("(P?!)"); // Promoted struct
9734 if (tree->gtOper == GT_STMT)
9736 if (opts.compDbgInfo)
9738 GenTreeStmt* stmt = tree->AsStmt();
9739 IL_OFFSET endIL = stmt->gtStmtLastILoffs;
9742 if (stmt->gtStmtILoffsx == BAD_IL_OFFSET)
9748 printf("0x%03X", jitGetILoffs(stmt->gtStmtILoffsx));
9751 if (endIL == BAD_IL_OFFSET)
9757 printf("0x%03X", endIL);
9763 if (tree->IsArgPlaceHolderNode() && (tree->gtArgPlace.gtArgPlaceClsHnd != nullptr))
9765 printf(" => [clsHnd=%08X]", dspPtr(tree->gtArgPlace.gtArgPlaceClsHnd));
9768 if (tree->gtOper == GT_RUNTIMELOOKUP)
9770 #ifdef _TARGET_64BIT_
9771 printf(" 0x%llx", dspPtr(tree->gtRuntimeLookup.gtHnd));
9773 printf(" 0x%x", dspPtr(tree->gtRuntimeLookup.gtHnd));
9776 switch (tree->gtRuntimeLookup.gtHndType)
9778 case CORINFO_HANDLETYPE_CLASS:
9781 case CORINFO_HANDLETYPE_METHOD:
9784 case CORINFO_HANDLETYPE_FIELD:
9794 // for tracking down problems in reguse prediction or liveness tracking
9799 dspRegMask(tree->gtRsvdRegs);
9805 void Compiler::gtDispRegVal(GenTree* tree)
9807 switch (tree->GetRegTag())
9809 // Don't display NOREG; the absence of this tag will imply this state
9810 // case GenTree::GT_REGTAG_NONE: printf(" NOREG"); break;
9812 case GenTree::GT_REGTAG_REG:
9813 printf(" REG %s", compRegVarName(tree->gtRegNum));
9820 if (tree->IsMultiRegCall())
9822 // 0th reg is gtRegNum, which is already printed above.
9823 // Print the remaining regs of a multi-reg call node.
9824 GenTreeCall* call = tree->AsCall();
9825 unsigned regCount = call->GetReturnTypeDesc()->TryGetReturnRegCount();
9826 for (unsigned i = 1; i < regCount; ++i)
9828 printf(",%s", compRegVarName(call->GetRegNumByIdx(i)));
9831 else if (tree->IsCopyOrReloadOfMultiRegCall())
9833 GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
9834 GenTreeCall* call = tree->gtGetOp1()->AsCall();
9835 unsigned regCount = call->GetReturnTypeDesc()->TryGetReturnRegCount();
9836 for (unsigned i = 1; i < regCount; ++i)
9838 printf(",%s", compRegVarName(copyOrReload->GetRegNumByIdx(i)));
9842 #if FEATURE_MULTIREG_RET
9843 if (tree->IsCopyOrReload())
9845 for (int i = 1; i < MAX_RET_REG_COUNT; i++)
9847 regNumber reg = (regNumber)tree->AsCopyOrReload()->GetRegNumByIdx(i);
9852 printf(",%s", compRegVarName(reg));
9857 #if defined(_TARGET_ARM_)
9858 if (tree->OperIsMultiRegOp() && (tree->AsMultiRegOp()->gtOtherReg != REG_NA))
9860 printf(",%s", compRegVarName(tree->AsMultiRegOp()->gtOtherReg));
9865 // We usually/commonly don't expect to print anything longer than this string,
9866 #define LONGEST_COMMON_LCL_VAR_DISPLAY "V99 PInvokeFrame"
9867 #define LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH (sizeof(LONGEST_COMMON_LCL_VAR_DISPLAY))
9868 #define BUF_SIZE (LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH * 2)
9870 void Compiler::gtGetLclVarNameInfo(unsigned lclNum, const char** ilKindOut, const char** ilNameOut, unsigned* ilNumOut)
9872 const char* ilKind = nullptr;
9873 const char* ilName = nullptr;
9875 unsigned ilNum = compMap2ILvarNum(lclNum);
9877 if (ilNum == (unsigned)ICorDebugInfo::RETBUF_ILNUM)
9881 else if (ilNum == (unsigned)ICorDebugInfo::VARARGS_HND_ILNUM)
9883 ilName = "VarArgHandle";
9885 else if (ilNum == (unsigned)ICorDebugInfo::TYPECTXT_ILNUM)
9889 else if (ilNum == (unsigned)ICorDebugInfo::UNKNOWN_ILNUM)
9892 if (lclNumIsTrueCSE(lclNum))
9895 ilNum = lclNum - optCSEstart;
9897 else if (lclNum >= optCSEstart)
9899 // Currently any new LclVar's introduced after the CSE phase
9900 // are believed to be created by the "rationalizer" that is what is meant by the "rat" prefix.
9902 ilNum = lclNum - (optCSEstart + optCSEcount);
9905 #endif // FEATURE_ANYCSE
9907 if (lclNum == info.compLvFrameListRoot)
9909 ilName = "FramesRoot";
9911 else if (lclNum == lvaInlinedPInvokeFrameVar)
9913 ilName = "PInvokeFrame";
9915 else if (lclNum == lvaGSSecurityCookie)
9917 ilName = "GsCookie";
9919 #if FEATURE_FIXED_OUT_ARGS
9920 else if (lclNum == lvaPInvokeFrameRegSaveVar)
9922 ilName = "PInvokeFrameRegSave";
9924 else if (lclNum == lvaOutgoingArgSpaceVar)
9928 #endif // FEATURE_FIXED_OUT_ARGS
9930 else if (lclNum == lvaPromotedStructAssemblyScratchVar)
9932 ilName = "PromotedStructScratch";
9934 #endif // _TARGET_ARM_
9935 #if !FEATURE_EH_FUNCLETS
9936 else if (lclNum == lvaShadowSPslotsVar)
9940 #endif // !FEATURE_EH_FUNCLETS
9941 #ifdef JIT32_GCENCODER
9942 else if (lclNum == lvaLocAllocSPvar)
9944 ilName = "LocAllocSP";
9946 #endif // JIT32_GCENCODER
9947 #if FEATURE_EH_FUNCLETS
9948 else if (lclNum == lvaPSPSym)
9952 #endif // FEATURE_EH_FUNCLETS
9956 if (compIsForInlining())
9958 ilNum = lclNum - impInlineInfo->InlinerCompiler->info.compLocalsCount;
9962 ilNum = lclNum - info.compLocalsCount;
9967 else if (lclNum < (compIsForInlining() ? impInlineInfo->InlinerCompiler->info.compArgsCount : info.compArgsCount))
9969 if (ilNum == 0 && !info.compIsStatic)
9980 if (!lvaTable[lclNum].lvIsStructField)
9984 if (compIsForInlining())
9986 ilNum -= impInlineInfo->InlinerCompiler->info.compILargsCount;
9990 ilNum -= info.compILargsCount;
9994 *ilKindOut = ilKind;
9995 *ilNameOut = ilName;
9999 /*****************************************************************************/
10000 int Compiler::gtGetLclVarName(unsigned lclNum, char* buf, unsigned buf_remaining)
10002 char* bufp_next = buf;
10003 unsigned charsPrinted = 0;
10004 int sprintf_result;
10006 sprintf_result = sprintf_s(bufp_next, buf_remaining, "V%02u", lclNum);
10008 if (sprintf_result < 0)
10010 return sprintf_result;
10013 charsPrinted += sprintf_result;
10014 bufp_next += sprintf_result;
10015 buf_remaining -= sprintf_result;
10017 const char* ilKind = nullptr;
10018 const char* ilName = nullptr;
10019 unsigned ilNum = 0;
10021 gtGetLclVarNameInfo(lclNum, &ilKind, &ilName, &ilNum);
10023 if (ilName != nullptr)
10025 sprintf_result = sprintf_s(bufp_next, buf_remaining, " %s", ilName);
10026 if (sprintf_result < 0)
10028 return sprintf_result;
10030 charsPrinted += sprintf_result;
10031 bufp_next += sprintf_result;
10032 buf_remaining -= sprintf_result;
10034 else if (ilKind != nullptr)
10036 sprintf_result = sprintf_s(bufp_next, buf_remaining, " %s%d", ilKind, ilNum);
10037 if (sprintf_result < 0)
10039 return sprintf_result;
10041 charsPrinted += sprintf_result;
10042 bufp_next += sprintf_result;
10043 buf_remaining -= sprintf_result;
10046 assert(charsPrinted > 0);
10047 assert(buf_remaining > 0);
10049 return (int)charsPrinted;
10052 /*****************************************************************************
10053 * Get the local var name, and create a copy of the string that can be used in debug output.
10055 char* Compiler::gtGetLclVarName(unsigned lclNum)
10057 char buf[BUF_SIZE];
10058 int charsPrinted = gtGetLclVarName(lclNum, buf, _countof(buf));
10059 if (charsPrinted < 0)
10064 char* retBuf = new (this, CMK_DebugOnly) char[charsPrinted + 1];
10065 strcpy_s(retBuf, charsPrinted + 1, buf);
10069 /*****************************************************************************/
10070 void Compiler::gtDispLclVar(unsigned lclNum, bool padForBiggestDisp)
10072 char buf[BUF_SIZE];
10073 int charsPrinted = gtGetLclVarName(lclNum, buf, _countof(buf));
10075 if (charsPrinted < 0)
10082 if (padForBiggestDisp && (charsPrinted < LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH))
10084 printf("%*c", LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH - charsPrinted, ' ');
10088 /*****************************************************************************/
10089 void Compiler::gtDispConst(GenTree* tree)
10091 assert(tree->OperKind() & GTK_CONST);
10093 switch (tree->gtOper)
10096 if (tree->IsIconHandle(GTF_ICON_STR_HDL))
10098 const wchar_t* str = eeGetCPString(tree->gtIntCon.gtIconVal);
10099 if (str != nullptr)
10101 printf(" 0x%X \"%S\"", dspPtr(tree->gtIntCon.gtIconVal), str);
10105 // Note that eGetCPString isn't currently implemented on Linux/ARM
10106 // and instead always returns nullptr
10107 printf(" 0x%X [ICON_STR_HDL]", dspPtr(tree->gtIntCon.gtIconVal));
10112 ssize_t dspIconVal = tree->IsIconHandle() ? dspPtr(tree->gtIntCon.gtIconVal) : tree->gtIntCon.gtIconVal;
10114 if (tree->TypeGet() == TYP_REF)
10116 assert(tree->gtIntCon.gtIconVal == 0);
10119 else if ((tree->gtIntCon.gtIconVal > -1000) && (tree->gtIntCon.gtIconVal < 1000))
10121 printf(" %ld", dspIconVal);
10122 #ifdef _TARGET_64BIT_
10124 else if ((tree->gtIntCon.gtIconVal & 0xFFFFFFFF00000000LL) != 0)
10126 printf(" 0x%llx", dspIconVal);
10131 printf(" 0x%X", dspIconVal);
10134 if (tree->IsIconHandle())
10136 switch (tree->GetIconHandleFlag())
10138 case GTF_ICON_SCOPE_HDL:
10141 case GTF_ICON_CLASS_HDL:
10144 case GTF_ICON_METHOD_HDL:
10147 case GTF_ICON_FIELD_HDL:
10150 case GTF_ICON_STATIC_HDL:
10153 case GTF_ICON_STR_HDL:
10154 unreached(); // This case is handled above
10156 case GTF_ICON_PSTR_HDL:
10159 case GTF_ICON_PTR_HDL:
10162 case GTF_ICON_VARG_HDL:
10165 case GTF_ICON_PINVKI_HDL:
10166 printf(" pinvoke");
10168 case GTF_ICON_TOKEN_HDL:
10171 case GTF_ICON_TLS_HDL:
10174 case GTF_ICON_FTN_ADDR:
10177 case GTF_ICON_CIDMID_HDL:
10178 printf(" cid/mid");
10180 case GTF_ICON_BBC_PTR:
10184 printf(" UNKNOWN");
10189 if ((tree->gtFlags & GTF_ICON_FIELD_OFF) != 0)
10191 printf(" field offset");
10194 #ifdef FEATURE_SIMD
10195 if ((tree->gtFlags & GTF_ICON_SIMD_COUNT) != 0)
10197 printf(" Vector<T>.Count");
10201 if ((tree->IsReuseRegVal()) != 0)
10203 printf(" reuse reg val");
10207 gtDispFieldSeq(tree->gtIntCon.gtFieldSeq);
10212 printf(" 0x%016I64x", tree->gtLngCon.gtLconVal);
10216 if (*((__int64*)&tree->gtDblCon.gtDconVal) == (__int64)I64(0x8000000000000000))
10218 printf(" -0.00000");
10222 printf(" %#.17g", tree->gtDblCon.gtDconVal);
10226 printf("<string constant>");
10229 assert(!"unexpected constant node");
10233 void Compiler::gtDispFieldSeq(FieldSeqNode* pfsn)
10235 if (pfsn == FieldSeqStore::NotAField() || (pfsn == nullptr))
10242 while (pfsn != nullptr)
10244 assert(pfsn != FieldSeqStore::NotAField()); // Can't exist in a field sequence list except alone
10245 CORINFO_FIELD_HANDLE fldHnd = pfsn->m_fieldHnd;
10246 // First check the "pseudo" field handles...
10247 if (fldHnd == FieldSeqStore::FirstElemPseudoField)
10249 printf("#FirstElem");
10251 else if (fldHnd == FieldSeqStore::ConstantIndexPseudoField)
10253 printf("#ConstantIndex");
10257 printf("%s", eeGetFieldName(fldHnd));
10259 pfsn = pfsn->m_next;
10260 if (pfsn != nullptr)
10268 //------------------------------------------------------------------------
10269 // gtDispLeaf: Print a single leaf node to jitstdout.
10272 // tree - the tree to be printed
10273 // indentStack - the specification for the current level of indentation & arcs
10279 // 'indentStack' may be null, in which case no indentation or arcs are printed
10281 void Compiler::gtDispLeaf(GenTree* tree, IndentStack* indentStack)
10283 if (tree->OperKind() & GTK_CONST)
10289 bool isLclFld = false;
10291 switch (tree->gtOper)
10297 case GT_LCL_FLD_ADDR:
10298 case GT_STORE_LCL_FLD:
10304 case GT_LCL_VAR_ADDR:
10305 case GT_STORE_LCL_VAR:
10307 varNum = tree->gtLclVarCommon.gtLclNum;
10308 varDsc = &lvaTable[varNum];
10309 gtDispLclVar(varNum);
10310 if (tree->gtLclVarCommon.HasSsaName())
10312 if (tree->gtFlags & GTF_VAR_USEASG)
10314 assert(tree->gtFlags & GTF_VAR_DEF);
10315 printf("ud:%d->%d", tree->gtLclVarCommon.gtSsaNum, GetSsaNumForLocalVarDef(tree));
10319 printf("%s:%d", (tree->gtFlags & GTF_VAR_DEF) ? "d" : "u", tree->gtLclVarCommon.gtSsaNum);
10325 printf("[+%u]", tree->gtLclFld.gtLclOffs);
10326 gtDispFieldSeq(tree->gtLclFld.gtFieldSeq);
10329 if (varDsc->lvRegister)
10332 varDsc->PrintVarReg();
10334 else if (tree->InReg())
10336 printf(" %s", compRegVarName(tree->gtRegNum));
10339 if (varDsc->lvPromoted)
10341 if (!varTypeIsPromotable(varDsc) && !varDsc->lvUnusedStruct)
10343 // Promoted implicit byrefs can get in this state while they are being rewritten
10344 // in global morph.
10345 assert(fgGlobalMorph);
10349 CORINFO_CLASS_HANDLE typeHnd = varDsc->lvVerTypeInfo.GetClassHandle();
10350 CORINFO_FIELD_HANDLE fldHnd;
10352 for (unsigned i = varDsc->lvFieldLclStart; i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++i)
10354 LclVarDsc* fieldVarDsc = &lvaTable[i];
10355 const char* fieldName;
10356 #if !defined(_TARGET_64BIT_)
10357 if (varTypeIsLong(varDsc))
10359 fieldName = (i == 0) ? "lo" : "hi";
10362 #endif // !defined(_TARGET_64BIT_)
10364 fldHnd = info.compCompHnd->getFieldInClass(typeHnd, fieldVarDsc->lvFldOrdinal);
10365 fieldName = eeGetFieldName(fldHnd);
10370 printIndent(indentStack);
10371 printf(" %-6s V%02u.%s (offs=0x%02x) -> ", varTypeName(fieldVarDsc->TypeGet()),
10372 tree->gtLclVarCommon.gtLclNum, fieldName, fieldVarDsc->lvFldOffset);
10375 if (fieldVarDsc->lvRegister)
10378 fieldVarDsc->PrintVarReg();
10381 if (fieldVarDsc->lvTracked && fgLocalVarLivenessDone && // Includes local variable liveness
10382 ((tree->gtFlags & GTF_VAR_DEATH) != 0))
10384 printf(" (last use)");
10389 else // a normal not-promoted lclvar
10391 if (varDsc->lvTracked && fgLocalVarLivenessDone && ((tree->gtFlags & GTF_VAR_DEATH) != 0))
10393 printf(" (last use)");
10400 const char* methodName;
10401 const char* className;
10403 methodName = eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtVal.gtVal1, &className);
10404 printf(" %s.%s\n", className, methodName);
10409 printf(" Hnd=%#x", dspPtr(tree->gtClsVar.gtClsVarHnd));
10410 gtDispFieldSeq(tree->gtClsVar.gtFieldSeq);
10413 case GT_CLS_VAR_ADDR:
10414 printf(" Hnd=%#x", dspPtr(tree->gtClsVar.gtClsVarHnd));
10422 const char* methodName;
10423 const char* className;
10425 methodName = eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtFptrVal.gtFptrMethod, &className);
10426 printf(" %s.%s\n", className, methodName);
10430 #if !FEATURE_EH_FUNCLETS
10432 printf(" endNstLvl=%d", tree->gtVal.gtVal1);
10434 #endif // !FEATURE_EH_FUNCLETS
10436 // Vanilla leaves. No qualifying information available. So do nothing
10439 case GT_START_NONGC:
10440 case GT_START_PREEMPTGC:
10443 case GT_MEMORYBARRIER:
10445 case GT_PINVOKE_PROLOG:
10450 printf("(inl return from call ");
10451 printTreeID(tree->gtRetExpr.gtInlineCandidate);
10456 printf(" %s", getRegName(tree->gtPhysReg.gtSrcReg, varTypeIsFloating(tree)));
10460 printf(" IL offset: ");
10461 if (tree->gtStmt.gtStmtILoffsx == BAD_IL_OFFSET)
10467 printf("0x%x", jitGetILoffs(tree->gtStmt.gtStmtILoffsx));
10473 printf(" cond=%s", tree->AsCC()->gtCondition.Name());
10476 printf(" cond=%s%s", (tree->gtFlags & GTF_JCMP_TST) ? "TEST_" : "",
10477 (tree->gtFlags & GTF_JCMP_EQ) ? "EQ" : "NE");
10480 assert(!"don't know how to display tree leaf node");
10484 //------------------------------------------------------------------------
10485 // gtDispLeaf: Print a child node to jitstdout.
10488 // tree - the tree to be printed
10489 // indentStack - the specification for the current level of indentation & arcs
10490 // arcType - the type of arc to use for this child
10491 // msg - a contextual method (i.e. from the parent) to print
10492 // topOnly - a boolean indicating whether to print the children, or just the top node
10498 // 'indentStack' may be null, in which case no indentation or arcs are printed
10499 // 'msg' has a default value of null
10500 // 'topOnly' is an optional argument that defaults to false
10502 void Compiler::gtDispChild(GenTree* child,
10503 IndentStack* indentStack,
10504 IndentInfo arcType,
10505 __in_opt const char* msg, /* = nullptr */
10506 bool topOnly) /* = false */
10508 indentStack->Push(arcType);
10509 gtDispTree(child, indentStack, msg, topOnly);
10510 indentStack->Pop();
10513 #ifdef FEATURE_SIMD
10514 // Intrinsic Id to name map
10515 extern const char* const simdIntrinsicNames[] = {
10516 #define SIMD_INTRINSIC(mname, inst, id, name, r, ac, arg1, arg2, arg3, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) name,
10517 #include "simdintrinsiclist.h"
10519 #endif // FEATURE_SIMD
10521 /*****************************************************************************/
10523 void Compiler::gtDispTree(GenTree* tree,
10524 IndentStack* indentStack, /* = nullptr */
10525 __in __in_z __in_opt const char* msg, /* = nullptr */
10526 bool topOnly, /* = false */
10527 bool isLIR) /* = false */
10529 if (tree == nullptr)
10531 printf(" [%08X] <NULL>\n", tree);
10532 printf(""); // null string means flush
10536 if (indentStack == nullptr)
10538 indentStack = new (this, CMK_DebugOnly) IndentStack(this);
10541 if (IsUninitialized(tree))
10543 /* Value used to initalize nodes */
10544 printf("Uninitialized tree node!\n");
10548 if (tree->gtOper >= GT_COUNT)
10550 gtDispNode(tree, indentStack, msg, isLIR);
10551 printf("Bogus operator!\n");
10555 /* Is tree a leaf node? */
10557 if (tree->OperIsLeaf() || tree->OperIsLocalStore()) // local stores used to be leaves
10559 gtDispNode(tree, indentStack, msg, isLIR);
10560 gtDispLeaf(tree, indentStack);
10561 gtDispCommonEndLine(tree);
10563 if (tree->OperIsLocalStore() && !topOnly)
10565 gtDispChild(tree->gtOp.gtOp1, indentStack, IINone);
10570 // Determine what kind of arc to propagate.
10571 IndentInfo myArc = IINone;
10572 IndentInfo lowerArc = IINone;
10573 if (indentStack->Depth() > 0)
10575 myArc = indentStack->Pop();
10579 indentStack->Push(IIArc);
10583 indentStack->Push(IIArc);
10587 indentStack->Push(IINone);
10591 indentStack->Push(IIEmbedded);
10592 lowerArc = IIEmbedded;
10595 indentStack->Push(IINone);
10604 // Special case formatting for PHI nodes -- arg lists like calls.
10606 if (tree->OperGet() == GT_PHI)
10608 gtDispNode(tree, indentStack, msg, isLIR);
10609 gtDispCommonEndLine(tree);
10613 if (tree->gtOp.gtOp1 != nullptr)
10615 IndentInfo arcType = IIArcTop;
10616 for (GenTreeArgList* args = tree->gtOp.gtOp1->AsArgList(); args != nullptr; args = args->Rest())
10618 if (args->Rest() == nullptr)
10620 arcType = IIArcBottom;
10622 gtDispChild(args->Current(), indentStack, arcType);
10630 /* Is it a 'simple' unary/binary operator? */
10632 const char* childMsg = nullptr;
10634 if (tree->OperIsSimple())
10638 if (tree->gtGetOp2IfPresent())
10640 // Label the childMsgs of the GT_COLON operator
10641 // op2 is the then part
10643 if (tree->gtOper == GT_COLON)
10647 gtDispChild(tree->gtOp.gtOp2, indentStack, IIArcTop, childMsg, topOnly);
10651 // Now, get the right type of arc for this node
10652 if (myArc != IINone)
10654 indentStack->Pop();
10655 indentStack->Push(myArc);
10658 gtDispNode(tree, indentStack, msg, isLIR);
10660 // Propagate lowerArc to the lower children.
10661 if (indentStack->Depth() > 0)
10663 (void)indentStack->Pop();
10664 indentStack->Push(lowerArc);
10667 if (tree->gtOper == GT_CAST)
10669 /* Format a message that explains the effect of this GT_CAST */
10671 var_types fromType = genActualType(tree->gtCast.CastOp()->TypeGet());
10672 var_types toType = tree->CastToType();
10673 var_types finalType = tree->TypeGet();
10675 /* if GTF_UNSIGNED is set then force fromType to an unsigned type */
10676 if (tree->gtFlags & GTF_UNSIGNED)
10678 fromType = genUnsignedType(fromType);
10681 if (finalType != toType)
10683 printf(" %s <-", varTypeName(finalType));
10686 printf(" %s <- %s", varTypeName(toType), varTypeName(fromType));
10689 if (tree->gtOper == GT_OBJ && (tree->gtFlags & GTF_VAR_DEATH))
10691 printf(" (last use)");
10693 if (tree->OperIsBlkOp())
10695 if (tree->OperIsCopyBlkOp())
10699 else if (tree->OperIsInitBlkOp())
10703 if (tree->OperIsStoreBlk() && (tree->AsBlk()->gtBlkOpKind != GenTreeBlk::BlkOpKindInvalid))
10705 switch (tree->AsBlk()->gtBlkOpKind)
10707 case GenTreeBlk::BlkOpKindRepInstr:
10708 printf(" (RepInstr)");
10710 case GenTreeBlk::BlkOpKindUnroll:
10711 printf(" (Unroll)");
10713 case GenTreeBlk::BlkOpKindHelper:
10714 printf(" (Helper)");
10721 else if (tree->OperIsFieldList())
10723 printf(" %s at offset %d", varTypeName(tree->AsFieldList()->gtFieldType),
10724 tree->AsFieldList()->gtFieldOffset);
10726 #if FEATURE_PUT_STRUCT_ARG_STK
10727 else if (tree->OperGet() == GT_PUTARG_STK)
10729 printf(" (%d slots)", tree->AsPutArgStk()->gtNumSlots);
10730 if (tree->AsPutArgStk()->gtPutArgStkKind != GenTreePutArgStk::Kind::Invalid)
10732 switch (tree->AsPutArgStk()->gtPutArgStkKind)
10734 case GenTreePutArgStk::Kind::RepInstr:
10735 printf(" (RepInstr)");
10737 case GenTreePutArgStk::Kind::Unroll:
10738 printf(" (Unroll)");
10740 case GenTreePutArgStk::Kind::Push:
10743 case GenTreePutArgStk::Kind::PushAllSlots:
10744 printf(" (PushAllSlots)");
10751 #endif // FEATURE_PUT_STRUCT_ARG_STK
10753 if (tree->gtOper == GT_INTRINSIC)
10755 switch (tree->gtIntrinsic.gtIntrinsicId)
10757 case CORINFO_INTRINSIC_Sin:
10760 case CORINFO_INTRINSIC_Cos:
10763 case CORINFO_INTRINSIC_Cbrt:
10766 case CORINFO_INTRINSIC_Sqrt:
10769 case CORINFO_INTRINSIC_Abs:
10772 case CORINFO_INTRINSIC_Round:
10775 case CORINFO_INTRINSIC_Cosh:
10778 case CORINFO_INTRINSIC_Sinh:
10781 case CORINFO_INTRINSIC_Tan:
10784 case CORINFO_INTRINSIC_Tanh:
10787 case CORINFO_INTRINSIC_Asin:
10790 case CORINFO_INTRINSIC_Asinh:
10793 case CORINFO_INTRINSIC_Acos:
10796 case CORINFO_INTRINSIC_Acosh:
10799 case CORINFO_INTRINSIC_Atan:
10802 case CORINFO_INTRINSIC_Atan2:
10805 case CORINFO_INTRINSIC_Atanh:
10808 case CORINFO_INTRINSIC_Log10:
10811 case CORINFO_INTRINSIC_Pow:
10814 case CORINFO_INTRINSIC_Exp:
10817 case CORINFO_INTRINSIC_Ceiling:
10818 printf(" ceiling");
10820 case CORINFO_INTRINSIC_Floor:
10823 case CORINFO_INTRINSIC_Object_GetType:
10824 printf(" objGetType");
10832 #ifdef FEATURE_SIMD
10833 if (tree->gtOper == GT_SIMD)
10835 printf(" %s %s", varTypeName(tree->gtSIMD.gtSIMDBaseType),
10836 simdIntrinsicNames[tree->gtSIMD.gtSIMDIntrinsicID]);
10838 #endif // FEATURE_SIMD
10840 #ifdef FEATURE_HW_INTRINSICS
10841 if (tree->gtOper == GT_HWIntrinsic)
10844 tree->gtHWIntrinsic.gtSIMDBaseType == TYP_UNKNOWN ? ""
10845 : varTypeName(tree->gtHWIntrinsic.gtSIMDBaseType),
10846 HWIntrinsicInfo::lookupName(tree->gtHWIntrinsic.gtHWIntrinsicId));
10848 #endif // FEATURE_HW_INTRINSICS
10850 gtDispCommonEndLine(tree);
10852 if (!topOnly && tree->gtOp.gtOp1)
10855 // Label the child of the GT_COLON operator
10856 // op1 is the else part
10858 if (tree->gtOper == GT_COLON)
10862 else if (tree->gtOper == GT_QMARK)
10866 gtDispChild(tree->gtOp.gtOp1, indentStack, IIArcBottom, childMsg, topOnly);
10872 // Now, get the right type of arc for this node
10873 if (myArc != IINone)
10875 indentStack->Pop();
10876 indentStack->Push(myArc);
10878 gtDispNode(tree, indentStack, msg, isLIR);
10880 // Propagate lowerArc to the lower children.
10881 if (indentStack->Depth() > 0)
10883 (void)indentStack->Pop();
10884 indentStack->Push(lowerArc);
10887 // See what kind of a special operator we have here, and handle its special children.
10889 switch (tree->gtOper)
10892 if (FieldSeqStore::IsPseudoField(tree->gtField.gtFldHnd))
10894 printf(" #PseudoField:0x%x", tree->gtField.gtFldOffset);
10898 printf(" %s", eeGetFieldName(tree->gtField.gtFldHnd), 0);
10901 gtDispCommonEndLine(tree);
10903 if (tree->gtField.gtFldObj && !topOnly)
10905 gtDispChild(tree->gtField.gtFldObj, indentStack, IIArcBottom);
10912 GenTreeCall* call = tree->AsCall();
10913 assert(call->gtFlags & GTF_CALL);
10914 unsigned numChildren = call->NumChildren();
10915 GenTree* lastChild = nullptr;
10916 if (numChildren != 0)
10918 lastChild = call->GetChild(numChildren - 1);
10921 if (call->gtCallType != CT_INDIRECT)
10923 const char* methodName;
10924 const char* className;
10926 methodName = eeGetMethodName(call->gtCallMethHnd, &className);
10928 printf(" %s.%s", className, methodName);
10931 if ((call->gtFlags & GTF_CALL_UNMANAGED) && (call->gtCallMoreFlags & GTF_CALL_M_FRAME_VAR_DEATH))
10933 printf(" (FramesRoot last use)");
10936 if (((call->gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0) && (call->gtInlineCandidateInfo != nullptr) &&
10937 (call->gtInlineCandidateInfo->exactContextHnd != nullptr))
10939 printf(" (exactContextHnd=0x%p)", dspPtr(call->gtInlineCandidateInfo->exactContextHnd));
10942 gtDispCommonEndLine(tree);
10951 if ((call->gtCallObjp != nullptr) && (call->gtCallObjp->gtOper != GT_NOP) &&
10952 (!call->gtCallObjp->IsArgPlaceHolderNode()))
10954 if (call->gtCallObjp->gtOper == GT_ASG)
10956 sprintf_s(bufp, sizeof(buf), "this SETUP%c", 0);
10960 sprintf_s(bufp, sizeof(buf), "this in %s%c", compRegVarName(REG_ARG_0), 0);
10962 gtDispChild(call->gtCallObjp, indentStack, (call->gtCallObjp == lastChild) ? IIArcBottom : IIArc,
10966 if (call->gtCallArgs)
10968 gtDispArgList(call, indentStack);
10971 if (call->gtCallType == CT_INDIRECT)
10973 gtDispChild(call->gtCallAddr, indentStack, (call->gtCallAddr == lastChild) ? IIArcBottom : IIArc,
10974 "calli tgt", topOnly);
10977 if (call->gtControlExpr != nullptr)
10979 gtDispChild(call->gtControlExpr, indentStack,
10980 (call->gtControlExpr == lastChild) ? IIArcBottom : IIArc, "control expr", topOnly);
10983 #if !FEATURE_FIXED_OUT_ARGS
10984 regList list = call->regArgList;
10986 /* process the late argument list */
10987 int lateArgIndex = 0;
10988 for (GenTreeArgList* lateArgs = call->gtCallLateArgs; lateArgs;
10989 (lateArgIndex++, lateArgs = lateArgs->Rest()))
10993 argx = lateArgs->Current();
10995 IndentInfo arcType = (lateArgs->Rest() == nullptr) ? IIArcBottom : IIArc;
10996 gtGetLateArgMsg(call, argx, lateArgIndex, -1, bufp, sizeof(buf));
10997 gtDispChild(argx, indentStack, arcType, bufp, topOnly);
11008 gtDispChild(tree->gtStmt.gtStmtExpr, indentStack, IIArcBottom);
11013 gtDispCommonEndLine(tree);
11017 gtDispChild(tree->gtArrElem.gtArrObj, indentStack, IIArc, nullptr, topOnly);
11020 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
11022 IndentInfo arcType = ((dim + 1) == tree->gtArrElem.gtArrRank) ? IIArcBottom : IIArc;
11023 gtDispChild(tree->gtArrElem.gtArrInds[dim], indentStack, arcType, nullptr, topOnly);
11028 case GT_ARR_OFFSET:
11029 gtDispCommonEndLine(tree);
11033 gtDispChild(tree->gtArrOffs.gtOffset, indentStack, IIArc, nullptr, topOnly);
11034 gtDispChild(tree->gtArrOffs.gtIndex, indentStack, IIArc, nullptr, topOnly);
11035 gtDispChild(tree->gtArrOffs.gtArrObj, indentStack, IIArcBottom, nullptr, topOnly);
11040 gtDispCommonEndLine(tree);
11044 gtDispChild(tree->gtCmpXchg.gtOpLocation, indentStack, IIArc, nullptr, topOnly);
11045 gtDispChild(tree->gtCmpXchg.gtOpValue, indentStack, IIArc, nullptr, topOnly);
11046 gtDispChild(tree->gtCmpXchg.gtOpComparand, indentStack, IIArcBottom, nullptr, topOnly);
11050 case GT_ARR_BOUNDS_CHECK:
11051 #ifdef FEATURE_SIMD
11053 #endif // FEATURE_SIMD
11054 #ifdef FEATURE_HW_INTRINSICS
11055 case GT_HW_INTRINSIC_CHK:
11056 #endif // FEATURE_HW_INTRINSICS
11057 gtDispCommonEndLine(tree);
11061 gtDispChild(tree->gtBoundsChk.gtIndex, indentStack, IIArc, nullptr, topOnly);
11062 gtDispChild(tree->gtBoundsChk.gtArrLen, indentStack, IIArcBottom, nullptr, topOnly);
11066 case GT_STORE_DYN_BLK:
11068 if (tree->OperIsCopyBlkOp())
11072 else if (tree->OperIsInitBlkOp())
11076 gtDispCommonEndLine(tree);
11080 if (tree->gtDynBlk.Data() != nullptr)
11082 gtDispChild(tree->gtDynBlk.Data(), indentStack, IIArc, nullptr, topOnly);
11084 gtDispChild(tree->gtDynBlk.Addr(), indentStack, IIArc, nullptr, topOnly);
11085 gtDispChild(tree->gtDynBlk.gtDynamicSize, indentStack, IIArcBottom, nullptr, topOnly);
11090 printf("<DON'T KNOW HOW TO DISPLAY THIS NODE> :");
11091 printf(""); // null string means flush
11096 //------------------------------------------------------------------------
11097 // gtGetArgMsg: Construct a message about the given argument
11100 // call - The call for which 'arg' is an argument
11101 // arg - The argument for which a message should be constructed
11102 // argNum - The ordinal number of the arg in the argument list
11103 // listCount - When printing in LIR form this is the count for a GT_FIELD_LIST
11104 // or -1 if we are not printing in LIR form
11105 // bufp - A pointer to the buffer into which the message is written
11106 // bufLength - The length of the buffer pointed to by bufp
11109 // No return value, but bufp is written.
11112 // 'call' must be a call node
11113 // 'arg' must be an argument to 'call' (else gtArgEntryByNode will assert)
11115 void Compiler::gtGetArgMsg(
11116 GenTreeCall* call, GenTree* arg, unsigned argNum, int listCount, char* bufp, unsigned bufLength)
11118 if (call->gtCallLateArgs != nullptr)
11120 fgArgTabEntry* curArgTabEntry = gtArgEntryByArgNum(call, argNum);
11121 assert(curArgTabEntry);
11123 if (arg->gtFlags & GTF_LATE_ARG)
11125 sprintf_s(bufp, bufLength, "arg%d SETUP%c", argNum, 0);
11129 #ifdef _TARGET_ARM_
11130 if (curArgTabEntry->isSplit)
11132 regNumber firstReg = curArgTabEntry->regNum;
11133 if (listCount == -1)
11135 if (curArgTabEntry->numRegs == 1)
11137 sprintf_s(bufp, bufLength, "arg%d %s out+%02x%c", argNum, compRegVarName(firstReg),
11138 (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE, 0);
11142 regNumber lastReg = REG_STK;
11143 char separator = (curArgTabEntry->numRegs == 2) ? ',' : '-';
11144 if (curArgTabEntry->isHfaRegArg)
11146 unsigned lastRegNum = genMapFloatRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
11147 lastReg = genMapFloatRegArgNumToRegNum(lastRegNum);
11151 unsigned lastRegNum = genMapIntRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
11152 lastReg = genMapIntRegArgNumToRegNum(lastRegNum);
11154 sprintf_s(bufp, bufLength, "arg%d %s%c%s out+%02x%c", argNum, compRegVarName(firstReg),
11155 separator, compRegVarName(lastReg), (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE,
11161 unsigned curArgNum = BAD_VAR_NUM;
11162 bool isFloat = curArgTabEntry->isHfaRegArg;
11165 curArgNum = genMapFloatRegNumToRegArgNum(firstReg) + listCount;
11169 curArgNum = genMapIntRegNumToRegArgNum(firstReg) + listCount;
11172 if (!isFloat && curArgNum < MAX_REG_ARG)
11174 regNumber curReg = genMapIntRegArgNumToRegNum(curArgNum);
11175 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
11177 else if (isFloat && curArgNum < MAX_FLOAT_REG_ARG)
11179 regNumber curReg = genMapFloatRegArgNumToRegNum(curArgNum);
11180 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
11184 unsigned stackSlot = listCount - curArgTabEntry->numRegs;
11185 sprintf_s(bufp, bufLength, "arg%d m%d out+%02x%c", argNum, listCount,
11186 stackSlot * TARGET_POINTER_SIZE, 0);
11191 #endif // _TARGET_ARM_
11192 #if FEATURE_FIXED_OUT_ARGS
11193 if (listCount == -1)
11195 sprintf_s(bufp, bufLength, "arg%d out+%02x%c", argNum, curArgTabEntry->slotNum * TARGET_POINTER_SIZE,
11198 else // listCount is 0,1,2 or 3
11200 assert(listCount <= MAX_ARG_REG_COUNT);
11201 sprintf_s(bufp, bufLength, "arg%d out+%02x%c", argNum,
11202 (curArgTabEntry->slotNum + listCount) * TARGET_POINTER_SIZE, 0);
11205 sprintf_s(bufp, bufLength, "arg%d on STK%c", argNum, 0);
11211 sprintf_s(bufp, bufLength, "arg%d%c", argNum, 0);
11215 //------------------------------------------------------------------------
11216 // gtGetLateArgMsg: Construct a message about the given argument
11219 // call - The call for which 'arg' is an argument
11220 // argx - The argument for which a message should be constructed
11221 // lateArgIndex - The ordinal number of the arg in the lastArg list
11222 // listCount - When printing in LIR form this is the count for a multireg GT_FIELD_LIST
11223 // or -1 if we are not printing in LIR form
11224 // bufp - A pointer to the buffer into which the message is written
11225 // bufLength - The length of the buffer pointed to by bufp
11228 // No return value, but bufp is written.
11231 // 'call' must be a call node
11232 // 'arg' must be an argument to 'call' (else gtArgEntryByNode will assert)
11234 void Compiler::gtGetLateArgMsg(
11235 GenTreeCall* call, GenTree* argx, int lateArgIndex, int listCount, char* bufp, unsigned bufLength)
11237 assert(!argx->IsArgPlaceHolderNode()); // No place holders nodes are in gtCallLateArgs;
11239 fgArgTabEntry* curArgTabEntry = gtArgEntryByLateArgIndex(call, lateArgIndex);
11240 assert(curArgTabEntry);
11241 regNumber argReg = curArgTabEntry->regNum;
11243 #if !FEATURE_FIXED_OUT_ARGS
11244 assert(lateArgIndex < call->regArgListCount);
11245 assert(argReg == call->regArgList[lateArgIndex]);
11247 if (argReg == REG_STK)
11249 sprintf_s(bufp, bufLength, "arg%d in out+%02x%c", curArgTabEntry->argNum,
11250 curArgTabEntry->slotNum * TARGET_POINTER_SIZE, 0);
11255 if (gtArgIsThisPtr(curArgTabEntry))
11257 sprintf_s(bufp, bufLength, "this in %s%c", compRegVarName(argReg), 0);
11259 #ifdef _TARGET_ARM_
11260 else if (curArgTabEntry->isSplit)
11262 regNumber firstReg = curArgTabEntry->regNum;
11263 unsigned argNum = curArgTabEntry->argNum;
11264 if (listCount == -1)
11266 if (curArgTabEntry->numRegs == 1)
11268 sprintf_s(bufp, bufLength, "arg%d %s out+%02x%c", argNum, compRegVarName(firstReg),
11269 (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE, 0);
11273 regNumber lastReg = REG_STK;
11274 char separator = (curArgTabEntry->numRegs == 2) ? ',' : '-';
11275 if (curArgTabEntry->isHfaRegArg)
11277 unsigned lastRegNum = genMapFloatRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
11278 lastReg = genMapFloatRegArgNumToRegNum(lastRegNum);
11282 unsigned lastRegNum = genMapIntRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
11283 lastReg = genMapIntRegArgNumToRegNum(lastRegNum);
11285 sprintf_s(bufp, bufLength, "arg%d %s%c%s out+%02x%c", argNum, compRegVarName(firstReg), separator,
11286 compRegVarName(lastReg), (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE, 0);
11291 unsigned curArgNum = BAD_VAR_NUM;
11292 bool isFloat = curArgTabEntry->isHfaRegArg;
11295 curArgNum = genMapFloatRegNumToRegArgNum(firstReg) + listCount;
11299 curArgNum = genMapIntRegNumToRegArgNum(firstReg) + listCount;
11302 if (!isFloat && curArgNum < MAX_REG_ARG)
11304 regNumber curReg = genMapIntRegArgNumToRegNum(curArgNum);
11305 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
11307 else if (isFloat && curArgNum < MAX_FLOAT_REG_ARG)
11309 regNumber curReg = genMapFloatRegArgNumToRegNum(curArgNum);
11310 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
11314 unsigned stackSlot = listCount - curArgTabEntry->numRegs;
11315 sprintf_s(bufp, bufLength, "arg%d m%d out+%02x%c", argNum, listCount,
11316 stackSlot * TARGET_POINTER_SIZE, 0);
11321 #endif // _TARGET_ARM_
11324 #if FEATURE_MULTIREG_ARGS
11325 if (curArgTabEntry->numRegs >= 2)
11327 // listCount could be -1 but it is signed, so this comparison is OK.
11328 assert(listCount <= MAX_ARG_REG_COUNT);
11329 char separator = (curArgTabEntry->numRegs == 2) ? ',' : '-';
11330 sprintf_s(bufp, bufLength, "arg%d %s%c%s%c", curArgTabEntry->argNum, compRegVarName(argReg), separator,
11331 compRegVarName(curArgTabEntry->getRegNum(curArgTabEntry->numRegs - 1)), 0);
11336 sprintf_s(bufp, bufLength, "arg%d in %s%c", curArgTabEntry->argNum, compRegVarName(argReg), 0);
11342 //------------------------------------------------------------------------
11343 // gtDispArgList: Dump the tree for a call arg list
11346 // call - The call to dump arguments for
11347 // indentStack - the specification for the current level of indentation & arcs
11352 void Compiler::gtDispArgList(GenTreeCall* call, IndentStack* indentStack)
11354 GenTree* args = call->gtCallArgs;
11355 unsigned argnum = 0;
11356 const int BufLength = 256;
11357 char buf[BufLength];
11358 char* bufp = &buf[0];
11359 unsigned numChildren = call->NumChildren();
11360 assert(numChildren != 0);
11361 bool argListIsLastChild = (args == call->GetChild(numChildren - 1));
11363 IndentInfo arcType = IIArc;
11364 if (call->gtCallObjp != nullptr)
11369 while (args != nullptr)
11371 assert(args->gtOper == GT_LIST);
11372 GenTree* arg = args->gtOp.gtOp1;
11373 if (!arg->IsNothingNode() && !arg->IsArgPlaceHolderNode())
11375 gtGetArgMsg(call, arg, argnum, -1, bufp, BufLength);
11376 if (argListIsLastChild && (args->gtOp.gtOp2 == nullptr))
11378 arcType = IIArcBottom;
11380 gtDispChild(arg, indentStack, arcType, bufp, false);
11382 args = args->gtOp.gtOp2;
11387 //------------------------------------------------------------------------
11388 // gtDispArgList: Dump the tree for a call arg list
11391 // tree - The call for which 'arg' is an argument
11392 // indentStack - the specification for the current level of indentation & arcs
11398 // 'tree' must be a GT_LIST node
11400 void Compiler::gtDispTreeList(GenTree* tree, IndentStack* indentStack /* = nullptr */)
11402 for (/*--*/; tree != nullptr; tree = tree->gtNext)
11404 gtDispTree(tree, indentStack);
11409 //------------------------------------------------------------------------
11410 // Compiler::gtDispRange: dumps a range of LIR.
11413 // range - the range of LIR to display.
11415 void Compiler::gtDispRange(LIR::ReadOnlyRange const& range)
11417 for (GenTree* node : range)
11419 gtDispLIRNode(node);
11423 //------------------------------------------------------------------------
11424 // Compiler::gtDispTreeRange: dumps the LIR range that contains all of the
11425 // nodes in the dataflow tree rooted at a given
11429 // containingRange - the LIR range that contains the root node.
11430 // tree - the root of the dataflow tree.
11432 void Compiler::gtDispTreeRange(LIR::Range& containingRange, GenTree* tree)
11435 gtDispRange(containingRange.GetTreeRange(tree, &unused));
11438 //------------------------------------------------------------------------
11439 // Compiler::gtDispLIRNode: dumps a single LIR node.
11442 // node - the LIR node to dump.
11443 // prefixMsg - an optional prefix for each line of output.
11445 void Compiler::gtDispLIRNode(GenTree* node, const char* prefixMsg /* = nullptr */)
11447 auto displayOperand = [](GenTree* operand, const char* message, IndentInfo operandArc, IndentStack& indentStack,
11448 size_t prefixIndent) {
11449 assert(operand != nullptr);
11450 assert(message != nullptr);
11452 if (prefixIndent != 0)
11454 printf("%*s", (int)prefixIndent, "");
11457 // 49 spaces for alignment
11458 printf("%-49s", "");
11459 #if FEATURE_SET_FLAGS
11460 // additional flag enlarges the flag field by one character
11464 indentStack.Push(operandArc);
11465 indentStack.print();
11467 operandArc = IIArc;
11469 printf(" t%-5d %-6s %s\n", operand->gtTreeID, varTypeName(operand->TypeGet()), message);
11472 IndentStack indentStack(this);
11474 size_t prefixIndent = 0;
11475 if (prefixMsg != nullptr)
11477 prefixIndent = strlen(prefixMsg);
11480 const int bufLength = 256;
11481 char buf[bufLength];
11483 const bool nodeIsCall = node->IsCall();
11486 IndentInfo operandArc = IIArcTop;
11487 for (GenTree* operand : node->Operands())
11489 if (operand->IsArgPlaceHolderNode() || !operand->IsValue())
11491 // Either of these situations may happen with calls.
11497 GenTreeCall* call = node->AsCall();
11498 if (operand == call->gtCallObjp)
11500 sprintf_s(buf, sizeof(buf), "this in %s", compRegVarName(REG_ARG_0));
11501 displayOperand(operand, buf, operandArc, indentStack, prefixIndent);
11503 else if (operand == call->gtCallAddr)
11505 displayOperand(operand, "calli tgt", operandArc, indentStack, prefixIndent);
11507 else if (operand == call->gtControlExpr)
11509 displayOperand(operand, "control expr", operandArc, indentStack, prefixIndent);
11511 else if (operand == call->gtCallCookie)
11513 displayOperand(operand, "cookie", operandArc, indentStack, prefixIndent);
11517 fgArgTabEntry* curArgTabEntry = gtArgEntryByNode(call, operand);
11518 assert(curArgTabEntry);
11520 if (operand->OperGet() == GT_LIST)
11523 for (GenTreeArgList* element = operand->AsArgList(); element != nullptr; element = element->Rest())
11525 operand = element->Current();
11526 if (curArgTabEntry->lateArgInx == (unsigned)-1)
11528 gtGetArgMsg(call, operand, curArgTabEntry->argNum, listIndex, buf, sizeof(buf));
11532 gtGetLateArgMsg(call, operand, curArgTabEntry->lateArgInx, listIndex, buf, sizeof(buf));
11535 displayOperand(operand, buf, operandArc, indentStack, prefixIndent);
11536 operandArc = IIArc;
11541 if (!curArgTabEntry->isLateArg())
11543 gtGetArgMsg(call, operand, curArgTabEntry->argNum, -1, buf, sizeof(buf));
11547 gtGetLateArgMsg(call, operand, curArgTabEntry->lateArgInx, -1, buf, sizeof(buf));
11550 displayOperand(operand, buf, operandArc, indentStack, prefixIndent);
11554 else if (node->OperIsDynBlkOp())
11556 if (operand == node->AsBlk()->Addr())
11558 displayOperand(operand, "lhs", operandArc, indentStack, prefixIndent);
11560 else if (operand == node->AsBlk()->Data())
11562 displayOperand(operand, "rhs", operandArc, indentStack, prefixIndent);
11566 assert(operand == node->AsDynBlk()->gtDynamicSize);
11567 displayOperand(operand, "size", operandArc, indentStack, prefixIndent);
11570 else if (node->OperGet() == GT_DYN_BLK)
11572 if (operand == node->AsBlk()->Addr())
11574 displayOperand(operand, "lhs", operandArc, indentStack, prefixIndent);
11578 assert(operand == node->AsDynBlk()->gtDynamicSize);
11579 displayOperand(operand, "size", operandArc, indentStack, prefixIndent);
11582 else if (node->OperIs(GT_ASG))
11584 if (operand == node->gtGetOp1())
11586 displayOperand(operand, "lhs", operandArc, indentStack, prefixIndent);
11590 displayOperand(operand, "rhs", operandArc, indentStack, prefixIndent);
11595 displayOperand(operand, "", operandArc, indentStack, prefixIndent);
11598 operandArc = IIArc;
11601 // Visit the operator
11603 if (prefixMsg != nullptr)
11605 printf("%s", prefixMsg);
11608 const bool topOnly = true;
11609 const bool isLIR = true;
11610 gtDispTree(node, &indentStack, nullptr, topOnly, isLIR);
11613 /*****************************************************************************/
11616 /*****************************************************************************
11618 * Check if the given node can be folded,
11619 * and call the methods to perform the folding
11622 GenTree* Compiler::gtFoldExpr(GenTree* tree)
11624 unsigned kind = tree->OperKind();
11626 /* We must have a simple operation to fold */
11628 // If we're in CSE, it's not safe to perform tree
11629 // folding given that it can will potentially
11630 // change considered CSE candidates.
11631 if (optValnumCSE_phase)
11636 if (!(kind & GTK_SMPOP))
11641 GenTree* op1 = tree->gtOp.gtOp1;
11643 /* Filter out non-foldable trees that can have constant children */
11645 assert(kind & (GTK_UNOP | GTK_BINOP));
11646 switch (tree->gtOper)
11656 /* try to fold the current node */
11658 if ((kind & GTK_UNOP) && op1)
11660 if (op1->OperKind() & GTK_CONST)
11662 return gtFoldExprConst(tree);
11665 else if ((kind & GTK_BINOP) && op1 && tree->gtOp.gtOp2 &&
11666 // Don't take out conditionals for debugging
11667 (opts.OptimizationEnabled() || !tree->OperIsCompare()))
11669 GenTree* op2 = tree->gtOp.gtOp2;
11671 // The atomic operations are exempted here because they are never computable statically;
11672 // one of their arguments is an address.
11673 if (((op1->OperKind() & op2->OperKind()) & GTK_CONST) && !tree->OperIsAtomicOp())
11675 /* both nodes are constants - fold the expression */
11676 return gtFoldExprConst(tree);
11678 else if ((op1->OperKind() | op2->OperKind()) & GTK_CONST)
11680 /* at least one is a constant - see if we have a
11681 * special operator that can use only one constant
11682 * to fold - e.g. booleans */
11684 return gtFoldExprSpecial(tree);
11686 else if (tree->OperIsCompare())
11688 /* comparisons of two local variables can sometimes be folded */
11690 return gtFoldExprCompare(tree);
11692 else if (op2->OperGet() == GT_COLON)
11694 assert(tree->OperGet() == GT_QMARK);
11696 GenTree* colon_op1 = op2->gtOp.gtOp1;
11697 GenTree* colon_op2 = op2->gtOp.gtOp2;
11699 if (gtCompareTree(colon_op1, colon_op2))
11701 // Both sides of the GT_COLON are the same tree
11703 GenTree* sideEffList = nullptr;
11704 gtExtractSideEffList(op1, &sideEffList);
11706 // Clear colon flags only if the qmark itself is not conditionaly executed
11707 if ((tree->gtFlags & GTF_COLON_COND) == 0)
11709 fgWalkTreePre(&colon_op2, gtClearColonCond);
11712 if (sideEffList == nullptr)
11714 // No side-effects, just return colon_op2
11722 printf("\nIdentical GT_COLON trees with side effects! Extracting side effects...\n");
11723 gtDispTree(sideEffList);
11727 // Change the GT_COLON into a GT_COMMA node with the side-effects
11728 op2->ChangeOper(GT_COMMA);
11729 op2->gtFlags |= (sideEffList->gtFlags & GTF_ALL_EFFECT);
11730 op2->gtOp.gtOp1 = sideEffList;
11737 /* Return the original node (folded/bashed or not) */
11742 //------------------------------------------------------------------------
11743 // gtFoldExprCall: see if a call is foldable
11746 // call - call to examine
11749 // The original call if no folding happened.
11750 // An alternative tree if folding happens.
11753 // Checks for calls to Type.op_Equality, Type.op_Inequality, and
11754 // Enum.HasFlag, and if the call is to one of these,
11755 // attempts to optimize.
11757 GenTree* Compiler::gtFoldExprCall(GenTreeCall* call)
11759 // Can only fold calls to special intrinsics.
11760 if ((call->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) == 0)
11765 // Defer folding if not optimizing.
11766 if (opts.OptimizationDisabled())
11771 // Fetch id of the intrinsic.
11772 const CorInfoIntrinsics methodID = info.compCompHnd->getIntrinsicID(call->gtCallMethHnd);
11776 case CORINFO_INTRINSIC_TypeEQ:
11777 case CORINFO_INTRINSIC_TypeNEQ:
11779 noway_assert(call->TypeGet() == TYP_INT);
11780 GenTree* op1 = call->gtCallArgs->gtOp.gtOp1;
11781 GenTree* op2 = call->gtCallArgs->gtOp.gtOp2->gtOp.gtOp1;
11783 // If either operand is known to be a RuntimeType, this can be folded
11784 GenTree* result = gtFoldTypeEqualityCall(methodID, op1, op2);
11785 if (result != nullptr)
11796 // Check for a new-style jit intrinsic.
11797 const NamedIntrinsic ni = lookupNamedIntrinsic(call->gtCallMethHnd);
11799 if (ni == NI_System_Enum_HasFlag)
11801 GenTree* thisOp = call->gtCallObjp;
11802 GenTree* flagOp = call->gtCallArgs->gtOp.gtOp1;
11803 GenTree* result = gtOptimizeEnumHasFlag(thisOp, flagOp);
11805 if (result != nullptr)
11814 //------------------------------------------------------------------------
11815 // gtFoldTypeEqualityCall: see if a (potential) type equality call is foldable
11818 // methodID -- type equality intrinsic ID
11819 // op1 -- first argument to call
11820 // op2 -- second argument to call
11823 // nulltpr if no folding happened.
11824 // An alternative tree if folding happens.
11827 // If either operand is known to be a a RuntimeType, then the type
11828 // equality methods will simply check object identity and so we can
11829 // fold the call into a simple compare of the call's operands.
11831 GenTree* Compiler::gtFoldTypeEqualityCall(CorInfoIntrinsics methodID, GenTree* op1, GenTree* op2)
11833 // The method must be be a type equality intrinsic
11834 assert(methodID == CORINFO_INTRINSIC_TypeEQ || methodID == CORINFO_INTRINSIC_TypeNEQ);
11836 if ((gtGetTypeProducerKind(op1) == TPK_Unknown) && (gtGetTypeProducerKind(op2) == TPK_Unknown))
11841 const genTreeOps simpleOp = (methodID == CORINFO_INTRINSIC_TypeEQ) ? GT_EQ : GT_NE;
11843 JITDUMP("\nFolding call to Type:op_%s to a simple compare via %s\n",
11844 methodID == CORINFO_INTRINSIC_TypeEQ ? "Equality" : "Inequality", GenTree::OpName(simpleOp));
11846 GenTree* compare = gtNewOperNode(simpleOp, TYP_INT, op1, op2);
11851 /*****************************************************************************
11853 * Some comparisons can be folded:
11856 * classVarA == classVarA
11857 * locA + locB == locB + locA
11861 GenTree* Compiler::gtFoldExprCompare(GenTree* tree)
11863 GenTree* op1 = tree->gtOp.gtOp1;
11864 GenTree* op2 = tree->gtOp.gtOp2;
11866 assert(tree->OperIsCompare());
11868 /* Filter out cases that cannot be folded here */
11870 /* Do not fold floats or doubles (e.g. NaN != Nan) */
11872 if (varTypeIsFloating(op1->TypeGet()))
11877 /* Currently we can only fold when the two subtrees exactly match */
11879 if ((tree->gtFlags & GTF_SIDE_EFFECT) || GenTree::Compare(op1, op2, true) == false)
11881 return tree; /* return unfolded tree */
11886 switch (tree->gtOper)
11891 cons = gtNewIconNode(true); /* Folds to GT_CNS_INT(true) */
11897 cons = gtNewIconNode(false); /* Folds to GT_CNS_INT(false) */
11901 assert(!"Unexpected relOp");
11905 /* The node has beeen folded into 'cons' */
11909 fgMorphTreeDone(cons);
11913 cons->gtNext = tree->gtNext;
11914 cons->gtPrev = tree->gtPrev;
11920 //------------------------------------------------------------------------
11921 // gtCreateHandleCompare: generate a type handle comparison
11924 // oper -- comparison operation (equal/not equal)
11925 // op1 -- first operand
11926 // op2 -- second operand
11927 // typeCheckInliningResult -- indicates how the comparison should happen
11930 // Type comparison tree
11933 GenTree* Compiler::gtCreateHandleCompare(genTreeOps oper,
11936 CorInfoInlineTypeCheck typeCheckInliningResult)
11938 // If we can compare pointers directly, just emit the binary operation
11939 if (typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_PASS)
11941 return gtNewOperNode(oper, TYP_INT, op1, op2);
11944 assert(typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_USE_HELPER);
11946 // Emit a call to a runtime helper
11947 GenTreeArgList* helperArgs = gtNewArgList(op1, op2);
11948 GenTree* ret = gtNewHelperCallNode(CORINFO_HELP_ARE_TYPES_EQUIVALENT, TYP_INT, helperArgs);
11951 ret = gtNewOperNode(GT_NE, TYP_INT, ret, gtNewIconNode(0, TYP_INT));
11955 assert(oper == GT_NE);
11956 ret = gtNewOperNode(GT_EQ, TYP_INT, ret, gtNewIconNode(0, TYP_INT));
11962 //------------------------------------------------------------------------
11963 // gtFoldTypeCompare: see if a type comparison can be further simplified
11966 // tree -- tree possibly comparing types
11969 // An alternative tree if folding happens.
11970 // Original tree otherwise.
11974 // typeof(...) == obj.GetType()
11975 // typeof(...) == typeof(...)
11977 // And potentially optimizes away the need to obtain actual
11978 // RuntimeType objects to do the comparison.
11980 GenTree* Compiler::gtFoldTypeCompare(GenTree* tree)
11982 // Only handle EQ and NE
11983 // (maybe relop vs null someday)
11984 const genTreeOps oper = tree->OperGet();
11985 if ((oper != GT_EQ) && (oper != GT_NE))
11990 // Screen for the right kinds of operands
11991 GenTree* const op1 = tree->gtOp.gtOp1;
11992 const TypeProducerKind op1Kind = gtGetTypeProducerKind(op1);
11993 if (op1Kind == TPK_Unknown)
11998 GenTree* const op2 = tree->gtOp.gtOp2;
11999 const TypeProducerKind op2Kind = gtGetTypeProducerKind(op2);
12000 if (op2Kind == TPK_Unknown)
12005 // We must have a handle on one side or the other here to optimize,
12006 // otherwise we can't be sure that optimizing is sound.
12007 const bool op1IsFromHandle = (op1Kind == TPK_Handle);
12008 const bool op2IsFromHandle = (op2Kind == TPK_Handle);
12010 if (!(op1IsFromHandle || op2IsFromHandle))
12015 // If both types are created via handles, we can simply compare
12016 // handles (or the indirection cells for handles) instead of the
12017 // types that they'd create.
12018 if (op1IsFromHandle && op2IsFromHandle)
12020 JITDUMP("Optimizing compare of types-from-handles to instead compare handles\n");
12021 GenTree* op1ClassFromHandle = tree->gtOp.gtOp1->gtCall.gtCallArgs->gtOp.gtOp1;
12022 GenTree* op2ClassFromHandle = tree->gtOp.gtOp2->gtCall.gtCallArgs->gtOp.gtOp1;
12023 GenTree* op1TunneledHandle = nullptr;
12024 GenTree* op2TunneledHandle = nullptr;
12025 CORINFO_CLASS_HANDLE cls1Hnd = NO_CLASS_HANDLE;
12026 CORINFO_CLASS_HANDLE cls2Hnd = NO_CLASS_HANDLE;
12027 unsigned runtimeLookupCount = 0;
12029 // Try and find class handles from op1 and op2
12030 cls1Hnd = gtGetHelperArgClassHandle(op1ClassFromHandle, &runtimeLookupCount, &op1TunneledHandle);
12031 cls2Hnd = gtGetHelperArgClassHandle(op2ClassFromHandle, &runtimeLookupCount, &op2TunneledHandle);
12033 // If we have both class handles, try and resolve the type equality test completely.
12034 bool resolveFailed = false;
12036 if ((cls1Hnd != NO_CLASS_HANDLE) && (cls2Hnd != NO_CLASS_HANDLE))
12038 JITDUMP("Asking runtime to compare %p (%s) and %p (%s) for equality\n", dspPtr(cls1Hnd),
12039 info.compCompHnd->getClassName(cls1Hnd), dspPtr(cls2Hnd), info.compCompHnd->getClassName(cls2Hnd));
12040 TypeCompareState s = info.compCompHnd->compareTypesForEquality(cls1Hnd, cls2Hnd);
12042 if (s != TypeCompareState::May)
12044 // Type comparison result is known.
12045 const bool typesAreEqual = (s == TypeCompareState::Must);
12046 const bool operatorIsEQ = (oper == GT_EQ);
12047 const int compareResult = operatorIsEQ ^ typesAreEqual ? 0 : 1;
12048 JITDUMP("Runtime reports comparison is known at jit time: %u\n", compareResult);
12049 GenTree* result = gtNewIconNode(compareResult);
12051 // Any runtime lookups that fed into this compare are
12052 // now dead code, so they no longer require the runtime context.
12053 assert(lvaGenericsContextUseCount >= runtimeLookupCount);
12054 lvaGenericsContextUseCount -= runtimeLookupCount;
12059 resolveFailed = true;
12065 JITDUMP("Runtime reports comparison is NOT known at jit time\n");
12069 JITDUMP("Could not find handle for %s%s\n", (cls1Hnd == NO_CLASS_HANDLE) ? " cls1" : "",
12070 (cls2Hnd == NO_CLASS_HANDLE) ? " cls2" : "");
12073 // We can't answer the equality comparison definitively at jit
12074 // time, but can still simplfy the comparison.
12076 // Find out how we can compare the two handles.
12077 // NOTE: We're potentially passing NO_CLASS_HANDLE, but the runtime knows what to do with it here.
12078 CorInfoInlineTypeCheck inliningKind =
12079 info.compCompHnd->canInlineTypeCheck(cls1Hnd, CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN);
12081 // If the first type needs helper, check the other type: it might be okay with a simple compare.
12082 if (inliningKind == CORINFO_INLINE_TYPECHECK_USE_HELPER)
12084 inliningKind = info.compCompHnd->canInlineTypeCheck(cls2Hnd, CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN);
12087 assert(inliningKind == CORINFO_INLINE_TYPECHECK_PASS || inliningKind == CORINFO_INLINE_TYPECHECK_USE_HELPER);
12089 // If we successfully tunneled through both operands, compare
12090 // the tunneled values, otherwise compare the original values.
12092 if ((op1TunneledHandle != nullptr) && (op2TunneledHandle != nullptr))
12094 compare = gtCreateHandleCompare(oper, op1TunneledHandle, op2TunneledHandle, inliningKind);
12098 compare = gtCreateHandleCompare(oper, op1ClassFromHandle, op2ClassFromHandle, inliningKind);
12101 // Drop any now-irrelvant flags
12102 compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
12107 // Just one operand creates a type from a handle.
12109 // If the other operand is fetching the type from an object,
12110 // we can sometimes optimize the type compare into a simpler
12111 // method table comparison.
12113 // TODO: if other operand is null...
12114 if ((op1Kind != TPK_GetType) && (op2Kind != TPK_GetType))
12119 GenTree* const opHandle = op1IsFromHandle ? op1 : op2;
12120 GenTree* const opOther = op1IsFromHandle ? op2 : op1;
12122 // Tunnel through the handle operand to get at the class handle involved.
12123 GenTree* const opHandleArgument = opHandle->gtCall.gtCallArgs->gtOp.gtOp1;
12124 CORINFO_CLASS_HANDLE clsHnd = gtGetHelperArgClassHandle(opHandleArgument);
12126 // If we couldn't find the class handle, give up.
12127 if (clsHnd == NO_CLASS_HANDLE)
12132 // Ask the VM if this type can be equality tested by a simple method
12133 // table comparison.
12134 CorInfoInlineTypeCheck typeCheckInliningResult =
12135 info.compCompHnd->canInlineTypeCheck(clsHnd, CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE);
12136 if (typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_NONE)
12141 // We're good to go.
12142 JITDUMP("Optimizing compare of obj.GetType()"
12143 " and type-from-handle to compare method table pointer\n");
12145 // opHandleArgument is the method table we're looking for.
12146 GenTree* const knownMT = opHandleArgument;
12148 // Fetch object method table from the object itself.
12149 GenTree* objOp = nullptr;
12151 // Note we may see intrinsified or regular calls to GetType
12152 if (opOther->OperGet() == GT_INTRINSIC)
12154 objOp = opOther->gtUnOp.gtOp1;
12158 assert(opOther->OperGet() == GT_CALL);
12159 objOp = opOther->gtCall.gtCallObjp;
12162 GenTree* const objMT = gtNewOperNode(GT_IND, TYP_I_IMPL, objOp);
12164 // Update various flags
12165 objMT->gtFlags |= GTF_EXCEPT;
12166 compCurBB->bbFlags |= BBF_HAS_VTABREF;
12167 optMethodFlags |= OMF_HAS_VTABLEREF;
12169 // Compare the two method tables
12170 GenTree* const compare = gtCreateHandleCompare(oper, objMT, knownMT, typeCheckInliningResult);
12172 // Drop any now irrelevant flags
12173 compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
12179 //------------------------------------------------------------------------
12180 // gtGetHelperArgClassHandle: find the compile time class handle from
12181 // a helper call argument tree
12184 // tree - tree that passes the handle to the helper
12185 // runtimeLookupCount [optional, in/out] - incremented if tree was a runtime lookup
12186 // handleTree [optional, out] - set to the literal operand tree for indirect handles
12189 // The compile time class handle if known.
12191 CORINFO_CLASS_HANDLE Compiler::gtGetHelperArgClassHandle(GenTree* tree,
12192 unsigned* runtimeLookupCount,
12193 GenTree** handleTree)
12195 CORINFO_CLASS_HANDLE result = NO_CLASS_HANDLE;
12197 // Walk through any wrapping nop.
12198 if ((tree->gtOper == GT_NOP) && (tree->gtType == TYP_I_IMPL))
12200 tree = tree->gtOp.gtOp1;
12203 // The handle could be a literal constant
12204 if ((tree->OperGet() == GT_CNS_INT) && (tree->TypeGet() == TYP_I_IMPL))
12206 assert(tree->IsIconHandle(GTF_ICON_CLASS_HDL));
12207 result = (CORINFO_CLASS_HANDLE)tree->gtIntCon.gtCompileTimeHandle;
12209 // Or the result of a runtime lookup
12210 else if (tree->OperGet() == GT_RUNTIMELOOKUP)
12212 result = tree->AsRuntimeLookup()->GetClassHandle();
12214 if (runtimeLookupCount != nullptr)
12216 *runtimeLookupCount = *runtimeLookupCount + 1;
12219 // Or something reached indirectly
12220 else if (tree->gtOper == GT_IND)
12222 // The handle indirs we are looking for will be marked as non-faulting.
12223 // Certain others (eg from refanytype) may not be.
12224 if (tree->gtFlags & GTF_IND_NONFAULTING)
12226 GenTree* handleTreeInternal = tree->gtOp.gtOp1;
12228 if ((handleTreeInternal->OperGet() == GT_CNS_INT) && (handleTreeInternal->TypeGet() == TYP_I_IMPL))
12230 // These handle constants should be class handles.
12231 assert(handleTreeInternal->IsIconHandle(GTF_ICON_CLASS_HDL));
12232 result = (CORINFO_CLASS_HANDLE)handleTreeInternal->gtIntCon.gtCompileTimeHandle;
12234 if (handleTree != nullptr)
12236 *handleTree = handleTreeInternal;
12245 /*****************************************************************************
12247 * Some binary operators can be folded even if they have only one
12248 * operand constant - e.g. boolean operators, add with 0
12249 * multiply with 1, etc
12252 GenTree* Compiler::gtFoldExprSpecial(GenTree* tree)
12254 GenTree* op1 = tree->gtOp.gtOp1;
12255 GenTree* op2 = tree->gtOp.gtOp2;
12256 genTreeOps oper = tree->OperGet();
12262 assert(tree->OperKind() & GTK_BINOP);
12264 /* Filter out operators that cannot be folded here */
12265 if (oper == GT_CAST)
12270 /* We only consider TYP_INT for folding
12271 * Do not fold pointer arithmetic (e.g. addressing modes!) */
12273 if (oper != GT_QMARK && !varTypeIsIntOrI(tree->gtType))
12278 /* Find out which is the constant node */
12280 if (op1->IsCnsIntOrI())
12285 else if (op2->IsCnsIntOrI())
12295 /* Get the constant value */
12297 val = cons->gtIntConCommon.IconValue();
12299 /* Here op is the non-constant operand, val is the constant,
12300 first is true if the constant is op1 */
12308 // Optimize boxed value classes; these are always false. This IL is
12309 // generated when a generic value is tested against null:
12310 // <T> ... foo(T x) { ... if ((object)x == null) ...
12311 if (val == 0 && op->IsBoxedValue())
12313 JITDUMP("\nAttempting to optimize BOX(valueType) %s null [%06u]\n", GenTree::OpName(oper),
12316 // We don't expect GT_GT with signed compares, and we
12317 // can't predict the result if we do see it, since the
12318 // boxed object addr could have its high bit set.
12319 if ((oper == GT_GT) && !tree->IsUnsigned())
12321 JITDUMP(" bailing; unexpected signed compare via GT_GT\n");
12325 // The tree under the box must be side effect free
12326 // since we will drop it if we optimize.
12327 assert(!gtTreeHasSideEffects(op->gtBox.gtOp.gtOp1, GTF_SIDE_EFFECT));
12329 // See if we can optimize away the box and related statements.
12330 GenTree* boxSourceTree = gtTryRemoveBoxUpstreamEffects(op);
12331 bool didOptimize = (boxSourceTree != nullptr);
12333 // If optimization succeeded, remove the box.
12336 // Set up the result of the compare.
12337 int compareResult = 0;
12340 // GT_GT(null, box) == false
12341 // GT_GT(box, null) == true
12342 compareResult = (op1 == op);
12344 else if (oper == GT_EQ)
12346 // GT_EQ(box, null) == false
12347 // GT_EQ(null, box) == false
12352 assert(oper == GT_NE);
12353 // GT_NE(box, null) == true
12354 // GT_NE(null, box) == true
12358 JITDUMP("\nSuccess: replacing BOX(valueType) %s null with %d\n", GenTree::OpName(oper),
12361 op = gtNewIconNode(compareResult);
12365 fgMorphTreeDone(op);
12369 op->gtNext = tree->gtNext;
12370 op->gtPrev = tree->gtPrev;
12394 /* Multiply by zero - return the 'zero' node, but not if side effects */
12395 if (!(op->gtFlags & GTF_SIDE_EFFECT))
12405 if ((op2 == cons) && (val == 1) && !(op1->OperKind() & GTK_CONST))
12412 if ((op2 == cons) && (val == 0) && !(op1->OperKind() & GTK_CONST))
12421 /* AND with zero - return the 'zero' node, but not if side effects */
12423 if (!(op->gtFlags & GTF_SIDE_EFFECT))
12431 /* The GTF_BOOLEAN flag is set for nodes that are part
12432 * of a boolean expression, thus all their children
12433 * are known to evaluate to only 0 or 1 */
12435 if (tree->gtFlags & GTF_BOOLEAN)
12438 /* The constant value must be 1
12439 * AND with 1 stays the same */
12451 else if (tree->gtFlags & GTF_BOOLEAN)
12453 /* The constant value must be 1 - OR with 1 is 1 */
12457 /* OR with one - return the 'one' node, but not if side effects */
12459 if (!(op->gtFlags & GTF_SIDE_EFFECT))
12478 else if (!(op->gtFlags & GTF_SIDE_EFFECT))
12488 assert(op1 == cons && op2 == op && op2->gtOper == GT_COLON);
12489 assert(op2->gtOp.gtOp1 && op2->gtOp.gtOp2);
12491 assert(val == 0 || val == 1);
12493 GenTree* opToDelete;
12496 op = op2->AsColon()->ThenNode();
12497 opToDelete = op2->AsColon()->ElseNode();
12501 op = op2->AsColon()->ElseNode();
12502 opToDelete = op2->AsColon()->ThenNode();
12505 // Clear colon flags only if the qmark itself is not conditionaly executed
12506 if ((tree->gtFlags & GTF_COLON_COND) == 0)
12508 fgWalkTreePre(&op, gtClearColonCond);
12518 /* The node is not foldable */
12524 /* The node has beeen folded into 'op' */
12526 // If there was an assigment update, we just morphed it into
12527 // a use, update the flags appropriately
12528 if (op->gtOper == GT_LCL_VAR)
12530 assert(tree->OperIs(GT_ASG) || (op->gtFlags & (GTF_VAR_USEASG | GTF_VAR_DEF)) == 0);
12532 op->gtFlags &= ~(GTF_VAR_USEASG | GTF_VAR_DEF);
12535 op->gtNext = tree->gtNext;
12536 op->gtPrev = tree->gtPrev;
12541 //------------------------------------------------------------------------
12542 // gtTryRemoveBoxUpstreamEffects: given an unused value type box,
12543 // try and remove the upstream allocation and unnecessary parts of
12547 // op - the box node to optimize
12548 // options - controls whether and how trees are modified
12552 // A tree representing the original value to box, if removal
12553 // is successful/possible (but see note). nullptr if removal fails.
12556 // Value typed box gets special treatment because it has associated
12557 // side effects that can be removed if the box result is not used.
12559 // By default (options == BR_REMOVE_AND_NARROW) this method will
12560 // try and remove unnecessary trees and will try and reduce remaning
12561 // operations to the minimal set, possibly narrowing the width of
12562 // loads from the box source if it is a struct.
12564 // To perform a trial removal, pass BR_DONT_REMOVE. This can be
12565 // useful to determine if this optimization should only be
12566 // performed if some other conditions hold true.
12568 // To remove but not alter the access to the box source, pass
12569 // BR_REMOVE_BUT_NOT_NARROW.
12571 // To remove and return the tree for the type handle used for
12572 // the boxed newobj, pass BR_REMOVE_BUT_NOT_NARROW_WANT_TYPE_HANDLE.
12573 // This can be useful when the only part of the box that is "live"
12576 // If removal fails, is is possible that a subsequent pass may be
12577 // able to optimize. Blocking side effects may now be minimized
12578 // (null or bounds checks might have been removed) or might be
12579 // better known (inline return placeholder updated with the actual
12580 // return expression). So the box is perhaps best left as is to
12581 // help trigger this re-examination.
12583 GenTree* Compiler::gtTryRemoveBoxUpstreamEffects(GenTree* op, BoxRemovalOptions options)
12585 assert(op->IsBoxedValue());
12587 // grab related parts for the optimization
12588 GenTreeBox* box = op->AsBox();
12589 GenTreeStmt* asgStmt = box->gtAsgStmtWhenInlinedBoxValue;
12590 GenTreeStmt* copyStmt = box->gtCopyStmtWhenInlinedBoxValue;
12592 JITDUMP("gtTryRemoveBoxUpstreamEffects: %s to %s of BOX (valuetype)"
12593 " [%06u] (assign/newobj [%06u] copy [%06u])\n",
12594 (options == BR_DONT_REMOVE) ? "checking if it is possible" : "attempting",
12595 (options == BR_MAKE_LOCAL_COPY) ? "make local unboxed version" : "remove side effects", dspTreeID(op),
12596 dspTreeID(asgStmt), dspTreeID(copyStmt));
12598 // If we don't recognize the form of the assign, bail.
12599 GenTree* asg = asgStmt->gtStmtExpr;
12600 if (asg->gtOper != GT_ASG)
12602 JITDUMP(" bailing; unexpected assignment op %s\n", GenTree::OpName(asg->gtOper));
12606 // If we're eventually going to return the type handle, remember it now.
12607 GenTree* boxTypeHandle = nullptr;
12608 if ((options == BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE) || (options == BR_DONT_REMOVE_WANT_TYPE_HANDLE))
12610 GenTree* asgSrc = asg->gtOp.gtOp2;
12611 genTreeOps asgSrcOper = asgSrc->OperGet();
12613 // Allocation may be via AllocObj or via helper call, depending
12614 // on when this is invoked and whether the jit is using AllocObj
12615 // for R2R allocations.
12616 if (asgSrcOper == GT_ALLOCOBJ)
12618 GenTreeAllocObj* allocObj = asgSrc->AsAllocObj();
12619 boxTypeHandle = allocObj->gtOp.gtOp1;
12621 else if (asgSrcOper == GT_CALL)
12623 GenTreeCall* newobjCall = asgSrc->AsCall();
12624 GenTree* newobjArgs = newobjCall->gtCallArgs;
12626 // In R2R expansions the handle may not be an explicit operand to the helper,
12627 // so we can't remove the box.
12628 if (newobjArgs == nullptr)
12630 assert(newobjCall->IsHelperCall(this, CORINFO_HELP_READYTORUN_NEW));
12631 JITDUMP(" bailing; newobj via R2R helper\n");
12635 boxTypeHandle = newobjArgs->AsArgList()->Current();
12642 assert(boxTypeHandle != nullptr);
12645 // If we don't recognize the form of the copy, bail.
12646 GenTree* copy = copyStmt->gtStmtExpr;
12647 if (copy->gtOper != GT_ASG)
12649 // GT_RET_EXPR is a tolerable temporary failure.
12650 // The jit will revisit this optimization after
12651 // inlining is done.
12652 if (copy->gtOper == GT_RET_EXPR)
12654 JITDUMP(" bailing; must wait for replacement of copy %s\n", GenTree::OpName(copy->gtOper));
12658 // Anything else is a missed case we should
12659 // figure out how to handle. One known case
12660 // is GT_COMMAs enclosing the GT_ASG we are
12662 JITDUMP(" bailing; unexpected copy op %s\n", GenTree::OpName(copy->gtOper));
12667 // Handle case where we are optimizing the box into a local copy
12668 if (options == BR_MAKE_LOCAL_COPY)
12670 // Drill into the box to get at the box temp local and the box type
12671 GenTree* boxTemp = box->BoxOp();
12672 assert(boxTemp->IsLocal());
12673 const unsigned boxTempLcl = boxTemp->AsLclVar()->GetLclNum();
12674 assert(lvaTable[boxTempLcl].lvType == TYP_REF);
12675 CORINFO_CLASS_HANDLE boxClass = lvaTable[boxTempLcl].lvClassHnd;
12676 assert(boxClass != nullptr);
12678 // Verify that the copyDst has the expected shape
12679 // (blk|obj|ind (add (boxTempLcl, ptr-size)))
12681 // The shape here is constrained to the patterns we produce
12682 // over in impImportAndPushBox for the inlined box case.
12683 GenTree* copyDst = copy->gtOp.gtOp1;
12685 if (!copyDst->OperIs(GT_BLK, GT_IND, GT_OBJ))
12687 JITDUMP("Unexpected copy dest operator %s\n", GenTree::OpName(copyDst->gtOper));
12691 GenTree* copyDstAddr = copyDst->gtOp.gtOp1;
12692 if (copyDstAddr->OperGet() != GT_ADD)
12694 JITDUMP("Unexpected copy dest address tree\n");
12698 GenTree* copyDstAddrOp1 = copyDstAddr->gtOp.gtOp1;
12699 if ((copyDstAddrOp1->OperGet() != GT_LCL_VAR) || (copyDstAddrOp1->gtLclVarCommon.gtLclNum != boxTempLcl))
12701 JITDUMP("Unexpected copy dest address 1st addend\n");
12705 GenTree* copyDstAddrOp2 = copyDstAddr->gtOp.gtOp2;
12706 if (!copyDstAddrOp2->IsIntegralConst(TARGET_POINTER_SIZE))
12708 JITDUMP("Unexpected copy dest address 2nd addend\n");
12712 // Screening checks have all passed. Do the transformation.
12714 // Retype the box temp to be a struct
12715 JITDUMP("Retyping box temp V%02u to struct %s\n", boxTempLcl, eeGetClassName(boxClass));
12716 lvaTable[boxTempLcl].lvType = TYP_UNDEF;
12717 const bool isUnsafeValueClass = false;
12718 lvaSetStruct(boxTempLcl, boxClass, isUnsafeValueClass);
12719 var_types boxTempType = lvaTable[boxTempLcl].lvType;
12721 // Remove the newobj and assigment to box temp
12722 JITDUMP("Bashing NEWOBJ [%06u] to NOP\n", dspTreeID(asg));
12723 asg->gtBashToNOP();
12725 // Update the copy from the value to be boxed to the box temp
12726 GenTree* newDst = gtNewOperNode(GT_ADDR, TYP_BYREF, gtNewLclvNode(boxTempLcl, boxTempType));
12727 copyDst->gtOp.gtOp1 = newDst;
12729 // Return the address of the now-struct typed box temp
12730 GenTree* retValue = gtNewOperNode(GT_ADDR, TYP_BYREF, gtNewLclvNode(boxTempLcl, boxTempType));
12735 // If the copy is a struct copy, make sure we know how to isolate
12736 // any source side effects.
12737 GenTree* copySrc = copy->gtOp.gtOp2;
12739 // If the copy source is from a pending inline, wait for it to resolve.
12740 if (copySrc->gtOper == GT_RET_EXPR)
12742 JITDUMP(" bailing; must wait for replacement of copy source %s\n", GenTree::OpName(copySrc->gtOper));
12746 bool hasSrcSideEffect = false;
12747 bool isStructCopy = false;
12749 if (gtTreeHasSideEffects(copySrc, GTF_SIDE_EFFECT))
12751 hasSrcSideEffect = true;
12753 if (varTypeIsStruct(copySrc->gtType))
12755 isStructCopy = true;
12757 if ((copySrc->gtOper != GT_OBJ) && (copySrc->gtOper != GT_IND) && (copySrc->gtOper != GT_FIELD))
12759 // We don't know how to handle other cases, yet.
12760 JITDUMP(" bailing; unexpected copy source struct op with side effect %s\n",
12761 GenTree::OpName(copySrc->gtOper));
12767 // If this was a trial removal, we're done.
12768 if (options == BR_DONT_REMOVE)
12773 if (options == BR_DONT_REMOVE_WANT_TYPE_HANDLE)
12775 return boxTypeHandle;
12778 // Otherwise, proceed with the optimization.
12780 // Change the assignment expression to a NOP.
12781 JITDUMP("\nBashing NEWOBJ [%06u] to NOP\n", dspTreeID(asg));
12782 asg->gtBashToNOP();
12784 // Change the copy expression so it preserves key
12785 // source side effects.
12786 JITDUMP("\nBashing COPY [%06u]", dspTreeID(copy));
12788 if (!hasSrcSideEffect)
12790 // If there were no copy source side effects just bash
12791 // the copy to a NOP.
12792 copy->gtBashToNOP();
12793 JITDUMP(" to NOP; no source side effects.\n");
12795 else if (!isStructCopy)
12797 // For scalar types, go ahead and produce the
12798 // value as the copy is fairly cheap and likely
12799 // the optimizer can trim things down to just the
12800 // minimal side effect parts.
12801 copyStmt->gtStmtExpr = copySrc;
12802 JITDUMP(" to scalar read via [%06u]\n", dspTreeID(copySrc));
12806 // For struct types read the first byte of the
12807 // source struct; there's no need to read the
12808 // entire thing, and no place to put it.
12809 assert(copySrc->gtOper == GT_OBJ || copySrc->gtOper == GT_IND || copySrc->gtOper == GT_FIELD);
12810 copyStmt->gtStmtExpr = copySrc;
12812 if (options == BR_REMOVE_AND_NARROW || options == BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE)
12814 JITDUMP(" to read first byte of struct via modified [%06u]\n", dspTreeID(copySrc));
12815 copySrc->ChangeOper(GT_IND);
12816 copySrc->gtType = TYP_BYTE;
12820 JITDUMP(" to read entire struct via modified [%06u]\n", dspTreeID(copySrc));
12824 if (fgStmtListThreaded)
12826 fgSetStmtSeq(asgStmt);
12827 fgSetStmtSeq(copyStmt);
12830 // Box effects were successfully optimized.
12832 if (options == BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE)
12834 return boxTypeHandle;
12842 //------------------------------------------------------------------------
12843 // gtOptimizeEnumHasFlag: given the operands for a call to Enum.HasFlag,
12844 // try and optimize the call to a simple and/compare tree.
12847 // thisOp - first argument to the call
12848 // flagOp - second argument to the call
12851 // A new cmp/amd tree if successful. nullptr on failure.
12854 // If successful, may allocate new temps and modify connected
12857 GenTree* Compiler::gtOptimizeEnumHasFlag(GenTree* thisOp, GenTree* flagOp)
12859 JITDUMP("Considering optimizing call to Enum.HasFlag....\n");
12861 // Operands must be boxes
12862 if (!thisOp->IsBoxedValue() || !flagOp->IsBoxedValue())
12864 JITDUMP("bailing, need both inputs to be BOXes\n");
12868 // Operands must have same type
12869 bool isExactThis = false;
12870 bool isNonNullThis = false;
12871 CORINFO_CLASS_HANDLE thisHnd = gtGetClassHandle(thisOp, &isExactThis, &isNonNullThis);
12873 if (thisHnd == nullptr)
12875 JITDUMP("bailing, can't find type for 'this' operand\n");
12879 // A boxed thisOp should have exact type and non-null instance
12880 assert(isExactThis);
12881 assert(isNonNullThis);
12883 bool isExactFlag = false;
12884 bool isNonNullFlag = false;
12885 CORINFO_CLASS_HANDLE flagHnd = gtGetClassHandle(flagOp, &isExactFlag, &isNonNullFlag);
12887 if (flagHnd == nullptr)
12889 JITDUMP("bailing, can't find type for 'flag' operand\n");
12893 // A boxed flagOp should have exact type and non-null instance
12894 assert(isExactFlag);
12895 assert(isNonNullFlag);
12897 if (flagHnd != thisHnd)
12899 JITDUMP("bailing, operand types differ\n");
12903 // If we have a shared type instance we can't safely check type
12904 // equality, so bail.
12905 DWORD classAttribs = info.compCompHnd->getClassAttribs(thisHnd);
12906 if (classAttribs & CORINFO_FLG_SHAREDINST)
12908 JITDUMP("bailing, have shared instance type\n");
12912 // Simulate removing the box for thisOP. We need to know that it can
12913 // be safely removed before we can optimize.
12914 GenTree* thisVal = gtTryRemoveBoxUpstreamEffects(thisOp, BR_DONT_REMOVE);
12915 if (thisVal == nullptr)
12917 // Note we may fail here if the this operand comes from
12918 // a call. We should be able to retry this post-inlining.
12919 JITDUMP("bailing, can't undo box of 'this' operand\n");
12923 GenTree* flagVal = gtTryRemoveBoxUpstreamEffects(flagOp, BR_REMOVE_BUT_NOT_NARROW);
12924 if (flagVal == nullptr)
12926 // Note we may fail here if the flag operand comes from
12927 // a call. We should be able to retry this post-inlining.
12928 JITDUMP("bailing, can't undo box of 'flag' operand\n");
12932 // Yes, both boxes can be cleaned up. Optimize.
12933 JITDUMP("Optimizing call to Enum.HasFlag\n");
12935 // Undo the boxing of thisOp and prepare to operate directly
12936 // on the original enum values.
12937 thisVal = gtTryRemoveBoxUpstreamEffects(thisOp, BR_REMOVE_BUT_NOT_NARROW);
12939 // Our trial removal above should guarantee successful removal here.
12940 assert(thisVal != nullptr);
12942 // We should have a consistent view of the type
12943 var_types type = thisVal->TypeGet();
12944 assert(type == flagVal->TypeGet());
12946 // The thisVal and flagVal trees come from earlier statements.
12948 // Unless they are invariant values, we need to evaluate them both
12949 // to temps at those points to safely transmit the values here.
12951 // Also we need to use the flag twice, so we need two trees for it.
12952 GenTree* thisValOpt = nullptr;
12953 GenTree* flagValOpt = nullptr;
12954 GenTree* flagValOptCopy = nullptr;
12956 if (thisVal->IsIntegralConst())
12958 thisValOpt = gtClone(thisVal);
12959 assert(thisValOpt != nullptr);
12963 const unsigned thisTmp = lvaGrabTemp(true DEBUGARG("Enum:HasFlag this temp"));
12964 GenTree* thisAsg = gtNewTempAssign(thisTmp, thisVal);
12965 GenTreeStmt* thisAsgStmt = thisOp->AsBox()->gtCopyStmtWhenInlinedBoxValue;
12966 thisAsgStmt->gtStmtExpr = thisAsg;
12967 thisValOpt = gtNewLclvNode(thisTmp, type);
12970 if (flagVal->IsIntegralConst())
12972 flagValOpt = gtClone(flagVal);
12973 assert(flagValOpt != nullptr);
12974 flagValOptCopy = gtClone(flagVal);
12975 assert(flagValOptCopy != nullptr);
12979 const unsigned flagTmp = lvaGrabTemp(true DEBUGARG("Enum:HasFlag flag temp"));
12980 GenTree* flagAsg = gtNewTempAssign(flagTmp, flagVal);
12981 GenTreeStmt* flagAsgStmt = flagOp->AsBox()->gtCopyStmtWhenInlinedBoxValue;
12982 flagAsgStmt->gtStmtExpr = flagAsg;
12983 flagValOpt = gtNewLclvNode(flagTmp, type);
12984 flagValOptCopy = gtNewLclvNode(flagTmp, type);
12987 // Turn the call into (thisValTmp & flagTmp) == flagTmp.
12988 GenTree* andTree = gtNewOperNode(GT_AND, type, thisValOpt, flagValOpt);
12989 GenTree* cmpTree = gtNewOperNode(GT_EQ, TYP_INT, andTree, flagValOptCopy);
12991 JITDUMP("Optimized call to Enum.HasFlag\n");
12996 /*****************************************************************************
12998 * Fold the given constant tree.
13002 #pragma warning(push)
13003 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
13005 GenTree* Compiler::gtFoldExprConst(GenTree* tree)
13007 unsigned kind = tree->OperKind();
13009 SSIZE_T i1, i2, itemp;
13010 INT64 lval1, lval2, ltemp;
13013 var_types switchType;
13014 FieldSeqNode* fieldSeq = FieldSeqStore::NotAField(); // default unless we override it when folding
13016 assert(kind & (GTK_UNOP | GTK_BINOP));
13018 GenTree* op1 = tree->gtOp.gtOp1;
13019 GenTree* op2 = tree->gtGetOp2IfPresent();
13021 if (!opts.OptEnabled(CLFLG_CONSTANTFOLD))
13026 if (tree->OperGet() == GT_NOP)
13031 #ifdef FEATURE_SIMD
13032 if (tree->OperGet() == GT_SIMD)
13036 #endif // FEATURE_SIMD
13038 if (tree->gtOper == GT_ALLOCOBJ)
13043 if (tree->gtOper == GT_RUNTIMELOOKUP)
13048 if (kind & GTK_UNOP)
13050 assert(op1->OperKind() & GTK_CONST);
13052 switch (op1->gtType)
13056 /* Fold constant INT unary operator */
13058 if (!op1->gtIntCon.ImmedValCanBeFolded(this, tree->OperGet()))
13063 i1 = (int)op1->gtIntCon.gtIconVal;
13065 // If we fold a unary oper, then the folded constant
13066 // is considered a ConstantIndexField if op1 was one
13069 if ((op1->gtIntCon.gtFieldSeq != nullptr) && op1->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
13071 fieldSeq = op1->gtIntCon.gtFieldSeq;
13074 switch (tree->gtOper)
13085 i1 = ((i1 >> 24) & 0xFF) | ((i1 >> 8) & 0xFF00) | ((i1 << 8) & 0xFF0000) |
13086 ((i1 << 24) & 0xFF000000);
13090 i1 = ((i1 >> 8) & 0xFF) | ((i1 << 8) & 0xFF00);
13094 // assert (genActualType(tree->CastToType()) == tree->gtType);
13095 switch (tree->CastToType())
13098 itemp = INT32(INT8(i1));
13102 itemp = INT32(INT16(i1));
13104 if (tree->gtOverflow() && ((itemp != i1) || ((tree->gtFlags & GTF_UNSIGNED) && i1 < 0)))
13112 itemp = INT32(UINT16(i1));
13113 if (tree->gtOverflow())
13125 itemp = INT32(UINT8(i1));
13126 if (tree->gtOverflow())
13137 if (!(tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && i1 < 0)
13144 if ((tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && i1 < 0)
13151 if (tree->IsUnsigned())
13153 lval1 = UINT64(UINT32(i1));
13157 if (tree->gtOverflow() && (i1 < 0))
13161 lval1 = UINT64(INT32(i1));
13166 if (tree->IsUnsigned())
13168 lval1 = INT64(UINT32(i1));
13172 lval1 = INT64(INT32(i1));
13177 if (tree->gtFlags & GTF_UNSIGNED)
13179 f1 = forceCastToFloat(UINT32(i1));
13183 f1 = forceCastToFloat(INT32(i1));
13189 if (tree->gtFlags & GTF_UNSIGNED)
13191 d1 = (double)UINT32(i1);
13195 d1 = (double)INT32(i1);
13200 assert(!"BAD_TYP");
13213 /* Fold constant LONG unary operator */
13215 if (!op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13220 lval1 = op1->gtIntConCommon.LngValue();
13222 switch (tree->gtOper)
13233 lval1 = ((lval1 >> 56) & 0xFF) | ((lval1 >> 40) & 0xFF00) | ((lval1 >> 24) & 0xFF0000) |
13234 ((lval1 >> 8) & 0xFF000000) | ((lval1 << 8) & 0xFF00000000) |
13235 ((lval1 << 24) & 0xFF0000000000) | ((lval1 << 40) & 0xFF000000000000) |
13236 ((lval1 << 56) & 0xFF00000000000000);
13240 assert(genActualType(tree->CastToType()) == tree->gtType);
13241 switch (tree->CastToType())
13244 i1 = INT32(INT8(lval1));
13245 goto CHECK_INT_OVERFLOW;
13248 i1 = INT32(INT16(lval1));
13249 goto CHECK_INT_OVERFLOW;
13252 i1 = INT32(UINT16(lval1));
13253 goto CHECK_UINT_OVERFLOW;
13256 i1 = INT32(UINT8(lval1));
13257 goto CHECK_UINT_OVERFLOW;
13262 CHECK_INT_OVERFLOW:
13263 if (tree->gtOverflow())
13269 if ((tree->gtFlags & GTF_UNSIGNED) && i1 < 0)
13277 i1 = UINT32(lval1);
13279 CHECK_UINT_OVERFLOW:
13280 if (tree->gtOverflow() && UINT32(i1) != lval1)
13287 if (!(tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && lval1 < 0)
13294 if ((tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && lval1 < 0)
13302 if ((tree->gtFlags & GTF_UNSIGNED) && lval1 < 0)
13304 d1 = FloatingPointUtils::convertUInt64ToDouble((unsigned __int64)lval1);
13308 d1 = (double)lval1;
13311 if (tree->CastToType() == TYP_FLOAT)
13313 f1 = forceCastToFloat(d1); // truncate precision
13318 assert(!"BAD_TYP");
13331 assert(op1->gtOper == GT_CNS_DBL);
13333 /* Fold constant DOUBLE unary operator */
13335 d1 = op1->gtDblCon.gtDconVal;
13337 switch (tree->gtOper)
13345 if (tree->gtOverflowEx())
13350 assert(genActualType(tree->CastToType()) == tree->gtType);
13352 if ((op1->gtType == TYP_FLOAT && !_finite(forceCastToFloat(d1))) ||
13353 (op1->gtType == TYP_DOUBLE && !_finite(d1)))
13355 // The floating point constant is not finite. The ECMA spec says, in
13356 // III 3.27, that "...if overflow occurs converting a floating point type
13357 // to an integer, ..., the value returned is unspecified." However, it would
13358 // at least be desirable to have the same value returned for casting an overflowing
13359 // constant to an int as would obtained by passing that constant as a parameter
13360 // then casting that parameter to an int type. We will assume that the C compiler's
13361 // cast logic will yield the desired result (and trust testing to tell otherwise).
13362 // Cross-compilation is an issue here; if that becomes an important scenario, we should
13363 // capture the target-specific values of overflow casts to the various integral types as
13364 // constants in a target-specific function.
13365 CLANG_FORMAT_COMMENT_ANCHOR;
13367 // Don't fold conversions of +inf/-inf to integral value on all platforms
13368 // as the value returned by JIT helper doesn't match with the C compiler's cast result.
13369 // We want the behavior to be same with or without folding.
13373 if (d1 <= -1.0 && varTypeIsUnsigned(tree->CastToType()))
13375 // Don't fold conversions of these cases becasue the result is unspecified per ECMA spec
13376 // and the native math doing the fold doesn't match the run-time computation on all
13378 // We want the behavior to be same with or without folding.
13382 switch (tree->CastToType())
13385 i1 = INT32(INT8(d1));
13389 i1 = INT32(INT16(d1));
13393 i1 = INT32(UINT16(d1));
13397 i1 = INT32(UINT8(d1));
13405 i1 = forceCastToUInt32(d1);
13413 lval1 = FloatingPointUtils::convertDoubleToUInt64(d1);
13417 d1 = forceCastToFloat(d1);
13421 if (op1->gtType == TYP_FLOAT)
13423 d1 = forceCastToFloat(d1); // truncate precision
13425 goto CNS_DOUBLE; // redundant cast
13428 assert(!"BAD_TYP");
13439 /* not a foldable typ - e.g. RET const */
13444 /* We have a binary operator */
13446 assert(kind & GTK_BINOP);
13448 assert(op1->OperKind() & GTK_CONST);
13449 assert(op2->OperKind() & GTK_CONST);
13451 if (tree->gtOper == GT_COMMA)
13456 if (tree->OperIsAnyList())
13461 switchType = op1->gtType;
13463 // Normally we will just switch on op1 types, but for the case where
13464 // only op2 is a GC type and op1 is not a GC type, we use the op2 type.
13465 // This makes us handle this as a case of folding for GC type.
13467 if (varTypeIsGC(op2->gtType) && !varTypeIsGC(op1->gtType))
13469 switchType = op2->gtType;
13472 switch (switchType)
13475 /*-------------------------------------------------------------------------
13476 * Fold constant REF of BYREF binary operator
13477 * These can only be comparisons or null pointers
13482 /* String nodes are an RVA at this point */
13484 if (op1->gtOper == GT_CNS_STR || op2->gtOper == GT_CNS_STR)
13493 i1 = op1->gtIntConCommon.IconValue();
13494 i2 = op2->gtIntConCommon.IconValue();
13496 switch (tree->gtOper)
13507 noway_assert(tree->gtType != TYP_REF);
13508 // We only fold a GT_ADD that involves a null reference.
13509 if (((op1->TypeGet() == TYP_REF) && (i1 == 0)) || ((op2->TypeGet() == TYP_REF) && (i2 == 0)))
13514 printf("\nFolding operator with constant nodes into a constant:\n");
13518 // Fold into GT_IND of null byref
13519 tree->ChangeOperConst(GT_CNS_INT);
13520 tree->gtType = TYP_BYREF;
13521 tree->gtIntCon.gtIconVal = 0;
13522 tree->gtIntCon.gtFieldSeq = FieldSeqStore::NotAField();
13523 if (vnStore != nullptr)
13525 fgValueNumberTreeConst(tree);
13530 printf("\nFolded to null byref:\n");
13543 /*-------------------------------------------------------------------------
13544 * Fold constant INT binary operator
13549 if (tree->OperIsCompare() && (tree->gtType == TYP_BYTE))
13551 tree->gtType = TYP_INT;
13554 assert(tree->gtType == TYP_INT || varTypeIsGC(tree->TypeGet()) || tree->gtOper == GT_MKREFANY);
13556 // No GC pointer types should be folded here...
13558 assert(!varTypeIsGC(op1->gtType) && !varTypeIsGC(op2->gtType));
13560 if (!op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13565 if (!op2->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13570 i1 = op1->gtIntConCommon.IconValue();
13571 i2 = op2->gtIntConCommon.IconValue();
13573 switch (tree->gtOper)
13576 i1 = (INT32(i1) == INT32(i2));
13579 i1 = (INT32(i1) != INT32(i2));
13583 if (tree->gtFlags & GTF_UNSIGNED)
13585 i1 = (UINT32(i1) < UINT32(i2));
13589 i1 = (INT32(i1) < INT32(i2));
13594 if (tree->gtFlags & GTF_UNSIGNED)
13596 i1 = (UINT32(i1) <= UINT32(i2));
13600 i1 = (INT32(i1) <= INT32(i2));
13605 if (tree->gtFlags & GTF_UNSIGNED)
13607 i1 = (UINT32(i1) >= UINT32(i2));
13611 i1 = (INT32(i1) >= INT32(i2));
13616 if (tree->gtFlags & GTF_UNSIGNED)
13618 i1 = (UINT32(i1) > UINT32(i2));
13622 i1 = (INT32(i1) > INT32(i2));
13628 if (tree->gtOverflow())
13630 if (tree->gtFlags & GTF_UNSIGNED)
13632 if (INT64(UINT32(itemp)) != INT64(UINT32(i1)) + INT64(UINT32(i2)))
13639 if (INT64(INT32(itemp)) != INT64(INT32(i1)) + INT64(INT32(i2)))
13646 fieldSeq = GetFieldSeqStore()->Append(op1->gtIntCon.gtFieldSeq, op2->gtIntCon.gtFieldSeq);
13650 if (tree->gtOverflow())
13652 if (tree->gtFlags & GTF_UNSIGNED)
13654 if (INT64(UINT32(itemp)) != ((INT64)((UINT32)i1) - (INT64)((UINT32)i2)))
13661 if (INT64(INT32(itemp)) != INT64(INT32(i1)) - INT64(INT32(i2)))
13671 if (tree->gtOverflow())
13673 if (tree->gtFlags & GTF_UNSIGNED)
13675 if (INT64(UINT32(itemp)) != ((INT64)((UINT32)i1) * (INT64)((UINT32)i2)))
13682 if (INT64(INT32(itemp)) != INT64(INT32(i1)) * INT64(INT32(i2)))
13688 // For the very particular case of the "constant array index" pseudo-field, we
13689 // assume that multiplication is by the field width, and preserves that field.
13690 // This could obviously be made more robust by a more complicated set of annotations...
13691 if ((op1->gtIntCon.gtFieldSeq != nullptr) && op1->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
13693 assert(op2->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField());
13694 fieldSeq = op1->gtIntCon.gtFieldSeq;
13696 else if ((op2->gtIntCon.gtFieldSeq != nullptr) &&
13697 op2->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
13699 assert(op1->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField());
13700 fieldSeq = op2->gtIntCon.gtFieldSeq;
13716 i1 <<= (i2 & 0x1f);
13719 i1 >>= (i2 & 0x1f);
13722 /* logical shift -> make it unsigned to not propagate the sign bit */
13723 i1 = UINT32(i1) >> (i2 & 0x1f);
13726 i1 = (i1 << (i2 & 0x1f)) | (UINT32(i1) >> ((32 - i2) & 0x1f));
13729 i1 = (i1 << ((32 - i2) & 0x1f)) | (UINT32(i1) >> (i2 & 0x1f));
13732 /* DIV and MOD can generate an INT 0 - if division by 0
13733 * or overflow - when dividing MIN by -1 */
13739 if (INT32(i2) == 0)
13741 // Division by zero:
13742 // We have to evaluate this expression and throw an exception
13745 else if ((INT32(i2) == -1) && (UINT32(i1) == 0x80000000))
13747 // Overflow Division:
13748 // We have to evaluate this expression and throw an exception
13752 if (tree->gtOper == GT_DIV)
13754 i1 = INT32(i1) / INT32(i2);
13756 else if (tree->gtOper == GT_MOD)
13758 i1 = INT32(i1) % INT32(i2);
13760 else if (tree->gtOper == GT_UDIV)
13762 i1 = UINT32(i1) / UINT32(i2);
13766 assert(tree->gtOper == GT_UMOD);
13767 i1 = UINT32(i1) % UINT32(i2);
13775 /* We get here after folding to a GT_CNS_INT type
13776 * change the node to the new type / value and make sure the node sizes are OK */
13783 printf("\nFolding operator with constant nodes into a constant:\n");
13788 #ifdef _TARGET_64BIT_
13789 // Some operations are performed as 64 bit instead of 32 bit so the upper 32 bits
13790 // need to be discarded. Since constant values are stored as ssize_t and the node
13791 // has TYP_INT the result needs to be sign extended rather than zero extended.
13793 #endif // _TARGET_64BIT_
13795 /* Also all conditional folding jumps here since the node hanging from
13796 * GT_JTRUE has to be a GT_CNS_INT - value 0 or 1 */
13798 tree->ChangeOperConst(GT_CNS_INT);
13799 tree->gtType = TYP_INT;
13800 tree->gtIntCon.gtIconVal = i1;
13801 tree->gtIntCon.gtFieldSeq = fieldSeq;
13802 if (vnStore != nullptr)
13804 fgValueNumberTreeConst(tree);
13809 printf("Bashed to int constant:\n");
13815 /* This operation is going to cause an overflow exception. Morph into
13816 an overflow helper. Put a dummy constant value for code generation.
13818 We could remove all subsequent trees in the current basic block,
13819 unless this node is a child of GT_COLON
13821 NOTE: Since the folded value is not constant we should not change the
13822 "tree" node - otherwise we confuse the logic that checks if the folding
13823 was successful - instead use one of the operands, e.g. op1
13827 // Don't fold overflow operations if not global morph phase.
13828 // The reason for this is that this optimization is replacing a gentree node
13829 // with another new gentree node. Say a GT_CALL(arglist) has one 'arg'
13830 // involving overflow arithmetic. During assertion prop, it is possible
13831 // that the 'arg' could be constant folded and the result could lead to an
13832 // overflow. In such a case 'arg' will get replaced with GT_COMMA node
13833 // but fgMorphArgs() - see the logic around "if(lateArgsComputed)" - doesn't
13834 // update args table. For this reason this optimization is enabled only
13835 // for global morphing phase.
13837 // TODO-CQ: Once fgMorphArgs() is fixed this restriction could be removed.
13838 CLANG_FORMAT_COMMENT_ANCHOR;
13840 if (!fgGlobalMorph)
13842 assert(tree->gtOverflow());
13846 op1 = gtNewLconNode(0);
13847 if (vnStore != nullptr)
13849 op1->gtVNPair.SetBoth(vnStore->VNZeroForType(TYP_LONG));
13854 // Don't fold overflow operations if not global morph phase.
13855 // The reason for this is that this optimization is replacing a gentree node
13856 // with another new gentree node. Say a GT_CALL(arglist) has one 'arg'
13857 // involving overflow arithmetic. During assertion prop, it is possible
13858 // that the 'arg' could be constant folded and the result could lead to an
13859 // overflow. In such a case 'arg' will get replaced with GT_COMMA node
13860 // but fgMorphArgs() - see the logic around "if(lateArgsComputed)" - doesn't
13861 // update args table. For this reason this optimization is enabled only
13862 // for global morphing phase.
13864 // TODO-CQ: Once fgMorphArgs() is fixed this restriction could be removed.
13866 if (!fgGlobalMorph)
13868 assert(tree->gtOverflow());
13872 op1 = gtNewIconNode(0);
13873 if (vnStore != nullptr)
13875 op1->gtVNPair.SetBoth(vnStore->VNZeroForType(TYP_INT));
13883 printf("\nFolding binary operator with constant nodes into a comma throw:\n");
13887 /* We will change the cast to a GT_COMMA and attach the exception helper as gtOp.gtOp1.
13888 * The constant expression zero becomes op2. */
13890 assert(tree->gtOverflow());
13891 assert(tree->gtOper == GT_ADD || tree->gtOper == GT_SUB || tree->gtOper == GT_CAST ||
13892 tree->gtOper == GT_MUL);
13896 op1 = gtNewHelperCallNode(CORINFO_HELP_OVERFLOW, TYP_VOID,
13897 gtNewArgList(gtNewIconNode(compCurBB->bbTryIndex)));
13899 // op1 is a call to the JIT helper that throws an Overflow exception
13900 // attach the ExcSet for VNF_OverflowExc(Void) to this call
13902 if (vnStore != nullptr)
13905 vnStore->VNPWithExc(ValueNumPair(ValueNumStore::VNForVoid(), ValueNumStore::VNForVoid()),
13906 vnStore->VNPExcSetSingleton(
13907 vnStore->VNPairForFunc(TYP_REF, VNF_OverflowExc, vnStore->VNPForVoid())));
13910 tree = gtNewOperNode(GT_COMMA, tree->gtType, op1, op2);
13914 /*-------------------------------------------------------------------------
13915 * Fold constant LONG binary operator
13920 // No GC pointer types should be folded here...
13922 assert(!varTypeIsGC(op1->gtType) && !varTypeIsGC(op2->gtType));
13924 // op1 is known to be a TYP_LONG, op2 is normally a TYP_LONG, unless we have a shift operator in which case
13927 assert((op2->gtType == TYP_LONG) || (op2->gtType == TYP_INT));
13929 if (!op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13934 if (!op2->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13939 lval1 = op1->gtIntConCommon.LngValue();
13941 // For the shift operators we can have a op2 that is a TYP_INT and thus will be GT_CNS_INT
13942 if (op2->OperGet() == GT_CNS_INT)
13944 lval2 = op2->gtIntConCommon.IconValue();
13948 lval2 = op2->gtIntConCommon.LngValue();
13951 switch (tree->gtOper)
13954 i1 = (lval1 == lval2);
13957 i1 = (lval1 != lval2);
13961 if (tree->gtFlags & GTF_UNSIGNED)
13963 i1 = (UINT64(lval1) < UINT64(lval2));
13967 i1 = (lval1 < lval2);
13972 if (tree->gtFlags & GTF_UNSIGNED)
13974 i1 = (UINT64(lval1) <= UINT64(lval2));
13978 i1 = (lval1 <= lval2);
13983 if (tree->gtFlags & GTF_UNSIGNED)
13985 i1 = (UINT64(lval1) >= UINT64(lval2));
13989 i1 = (lval1 >= lval2);
13994 if (tree->gtFlags & GTF_UNSIGNED)
13996 i1 = (UINT64(lval1) > UINT64(lval2));
14000 i1 = (lval1 > lval2);
14005 ltemp = lval1 + lval2;
14008 /* For the SIGNED case - If there is one positive and one negative operand, there can be no overflow
14009 * If both are positive, the result has to be positive, and similary for negatives.
14011 * For the UNSIGNED case - If a UINT32 operand is bigger than the result then OVF */
14013 if (tree->gtOverflow())
14015 if (tree->gtFlags & GTF_UNSIGNED)
14017 if ((UINT64(lval1) > UINT64(ltemp)) || (UINT64(lval2) > UINT64(ltemp)))
14022 else if (((lval1 < 0) == (lval2 < 0)) && ((lval1 < 0) != (ltemp < 0)))
14031 ltemp = lval1 - lval2;
14032 if (tree->gtOverflow())
14034 if (tree->gtFlags & GTF_UNSIGNED)
14036 if (UINT64(lval2) > UINT64(lval1))
14043 /* If both operands are +ve or both are -ve, there can be no
14044 overflow. Else use the logic for : lval1 + (-lval2) */
14046 if ((lval1 < 0) != (lval2 < 0))
14048 if (lval2 == INT64_MIN)
14053 goto LNG_ADD_CHKOVF;
14061 ltemp = lval1 * lval2;
14063 if (tree->gtOverflow() && lval2 != 0)
14066 if (tree->gtFlags & GTF_UNSIGNED)
14068 UINT64 ultemp = ltemp;
14069 UINT64 ulval1 = lval1;
14070 UINT64 ulval2 = lval2;
14071 if ((ultemp / ulval2) != ulval1)
14078 // This does a multiply and then reverses it. This test works great except for MIN_INT *
14079 //-1. In that case we mess up the sign on ltmp. Make sure to double check the sign.
14080 // if either is 0, then no overflow
14081 if (lval1 != 0) // lval2 checked above.
14083 if (((lval1 < 0) == (lval2 < 0)) && (ltemp < 0))
14087 if (((lval1 < 0) != (lval2 < 0)) && (ltemp > 0))
14092 // TODO-Amd64-Unix: Remove the code that disables optimizations for this method when the
14094 // optimizer is fixed and/or the method implementation is refactored in a simpler code.
14095 // There is a bug in the clang-3.5 optimizer. The issue is that in release build the
14096 // optimizer is mistyping (or just wrongly decides to use 32 bit operation for a corner
14097 // case of MIN_LONG) the args of the (ltemp / lval2) to int (it does a 32 bit div
14098 // operation instead of 64 bit.). For the case of lval1 and lval2 equal to MIN_LONG
14099 // (0x8000000000000000) this results in raising a SIGFPE.
14100 // Optimizations disabled for now. See compiler.h.
14101 if ((ltemp / lval2) != lval1)
14123 lval1 <<= (lval2 & 0x3f);
14126 lval1 >>= (lval2 & 0x3f);
14129 /* logical shift -> make it unsigned to not propagate the sign bit */
14130 lval1 = UINT64(lval1) >> (lval2 & 0x3f);
14133 lval1 = (lval1 << (lval2 & 0x3f)) | (UINT64(lval1) >> ((64 - lval2) & 0x3f));
14136 lval1 = (lval1 << ((64 - lval2) & 0x3f)) | (UINT64(lval1) >> (lval2 & 0x3f));
14139 // Both DIV and IDIV on x86 raise an exception for min_int (and min_long) / -1. So we preserve
14140 // that behavior here.
14147 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
14159 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
14171 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
14175 lval1 = UINT64(lval1) / UINT64(lval2);
14183 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
14187 lval1 = UINT64(lval1) % UINT64(lval2);
14195 if (fieldSeq != FieldSeqStore::NotAField())
14203 printf("\nFolding long operator with constant nodes into a constant:\n");
14207 assert((GenTree::s_gtNodeSizes[GT_CNS_NATIVELONG] == TREE_NODE_SZ_SMALL) ||
14208 (tree->gtDebugFlags & GTF_DEBUG_NODE_LARGE));
14210 tree->ChangeOperConst(GT_CNS_NATIVELONG);
14211 tree->gtIntConCommon.SetLngValue(lval1);
14212 if (vnStore != nullptr)
14214 fgValueNumberTreeConst(tree);
14220 printf("Bashed to long constant:\n");
14226 /*-------------------------------------------------------------------------
14227 * Fold constant FLOAT or DOUBLE binary operator
14233 if (tree->gtOverflowEx())
14238 assert(op1->gtOper == GT_CNS_DBL);
14239 d1 = op1->gtDblCon.gtDconVal;
14241 assert(varTypeIsFloating(op2->gtType));
14242 assert(op2->gtOper == GT_CNS_DBL);
14243 d2 = op2->gtDblCon.gtDconVal;
14245 /* Special case - check if we have NaN operands.
14246 * For comparisons if not an unordered operation always return 0.
14247 * For unordered operations (i.e. the GTF_RELOP_NAN_UN flag is set)
14248 * the result is always true - return 1. */
14250 if (_isnan(d1) || _isnan(d2))
14255 printf("Double operator(s) is NaN\n");
14258 if (tree->OperKind() & GTK_RELOP)
14260 if (tree->gtFlags & GTF_RELOP_NAN_UN)
14262 /* Unordered comparison with NaN always succeeds */
14268 /* Normal comparison with NaN always fails */
14275 switch (tree->gtOper)
14297 // Floating point arithmetic should be done in declared
14298 // precision while doing constant folding. For this reason though TYP_FLOAT
14299 // constants are stored as double constants, while performing float arithmetic,
14300 // double constants should be converted to float. Here is an example case
14301 // where performing arithmetic in double precision would lead to incorrect
14305 // float a = float.MaxValue;
14306 // float b = a*a; This will produce +inf in single precision and 1.1579207543382391e+077 in double
14308 // flaot c = b/b; This will produce NaN in single precision and 1 in double precision.
14310 if (op1->TypeGet() == TYP_FLOAT)
14312 f1 = forceCastToFloat(d1);
14313 f2 = forceCastToFloat(d2);
14314 d1 = forceCastToFloat(f1 + f2);
14323 if (op1->TypeGet() == TYP_FLOAT)
14325 f1 = forceCastToFloat(d1);
14326 f2 = forceCastToFloat(d2);
14327 d1 = forceCastToFloat(f1 - f2);
14336 if (op1->TypeGet() == TYP_FLOAT)
14338 f1 = forceCastToFloat(d1);
14339 f2 = forceCastToFloat(d2);
14340 d1 = forceCastToFloat(f1 * f2);
14353 if (op1->TypeGet() == TYP_FLOAT)
14355 f1 = forceCastToFloat(d1);
14356 f2 = forceCastToFloat(d2);
14357 d1 = forceCastToFloat(f1 / f2);
14374 printf("\nFolding fp operator with constant nodes into a fp constant:\n");
14379 assert((GenTree::s_gtNodeSizes[GT_CNS_DBL] == TREE_NODE_SZ_SMALL) ||
14380 (tree->gtDebugFlags & GTF_DEBUG_NODE_LARGE));
14382 tree->ChangeOperConst(GT_CNS_DBL);
14383 tree->gtDblCon.gtDconVal = d1;
14384 if (vnStore != nullptr)
14386 fgValueNumberTreeConst(tree);
14391 printf("Bashed to fp constant:\n");
14398 /* not a foldable typ */
14402 //-------------------------------------------------------------------------
14406 /* Make sure no side effect flags are set on this constant node */
14408 tree->gtFlags &= ~GTF_ALL_EFFECT;
14413 #pragma warning(pop)
14416 //------------------------------------------------------------------------
14417 // gtNewTempAssign: Create an assignment of the given value to a temp.
14420 // tmp - local number for a compiler temp
14421 // val - value to assign to the temp
14422 // pAfterStmt - statement to insert any additional statements after
14423 // ilOffset - il offset for new statements
14424 // block - block to insert any additional statements in
14427 // Normally a new assignment node.
14428 // However may return a nop node if val is simply a reference to the temp.
14431 // Self-assignments may be represented via NOPs.
14433 // May update the type of the temp, if it was previously unknown.
14435 // May set compFloatingPointUsed.
14437 GenTree* Compiler::gtNewTempAssign(
14438 unsigned tmp, GenTree* val, GenTreeStmt** pAfterStmt, IL_OFFSETX ilOffset, BasicBlock* block)
14440 // Self-assignment is a nop.
14441 if (val->OperGet() == GT_LCL_VAR && val->gtLclVarCommon.gtLclNum == tmp)
14443 return gtNewNothingNode();
14446 LclVarDsc* varDsc = lvaTable + tmp;
14448 if (varDsc->TypeGet() == TYP_I_IMPL && val->TypeGet() == TYP_BYREF)
14450 impBashVarAddrsToI(val);
14453 var_types valTyp = val->TypeGet();
14454 if (val->OperGet() == GT_LCL_VAR && lvaTable[val->gtLclVar.gtLclNum].lvNormalizeOnLoad())
14456 valTyp = lvaGetRealType(val->gtLclVar.gtLclNum);
14457 val->gtType = valTyp;
14459 var_types dstTyp = varDsc->TypeGet();
14461 /* If the variable's lvType is not yet set then set it here */
14462 if (dstTyp == TYP_UNDEF)
14464 varDsc->lvType = dstTyp = genActualType(valTyp);
14465 if (varTypeIsGC(dstTyp))
14467 varDsc->lvStructGcCount = 1;
14470 else if (varTypeIsSIMD(dstTyp))
14472 varDsc->lvSIMDType = 1;
14478 /* Make sure the actual types match */
14479 if (genActualType(valTyp) != genActualType(dstTyp))
14481 // Plus some other exceptions that are apparently legal:
14482 // 1) TYP_REF or BYREF = TYP_I_IMPL
14484 if (varTypeIsGC(dstTyp) && (valTyp == TYP_I_IMPL))
14488 // 2) TYP_DOUBLE = TYP_FLOAT or TYP_FLOAT = TYP_DOUBLE
14489 else if (varTypeIsFloating(dstTyp) && varTypeIsFloating(valTyp))
14493 // 3) TYP_BYREF = TYP_REF when object stack allocation is enabled
14494 else if (JitConfig.JitObjectStackAllocation() && (dstTyp == TYP_BYREF) && (valTyp == TYP_REF))
14502 assert(!"Incompatible types for gtNewTempAssign");
14507 // Floating Point assignments can be created during inlining
14508 // see "Zero init inlinee locals:" in fgInlinePrependStatements
14509 // thus we may need to set compFloatingPointUsed to true here.
14511 if (varTypeIsFloating(dstTyp) && (compFloatingPointUsed == false))
14513 compFloatingPointUsed = true;
14516 /* Create the assignment node */
14519 GenTree* dest = gtNewLclvNode(tmp, dstTyp);
14520 dest->gtFlags |= GTF_VAR_DEF;
14522 // With first-class structs, we should be propagating the class handle on all non-primitive
14523 // struct types. We don't have a convenient way to do that for all SIMD temps, since some
14524 // internal trees use SIMD types that are not used by the input IL. In this case, we allow
14525 // a null type handle and derive the necessary information about the type from its varType.
14526 CORINFO_CLASS_HANDLE structHnd = gtGetStructHandleIfPresent(val);
14527 if (varTypeIsStruct(valTyp) && ((structHnd != NO_CLASS_HANDLE) || (varTypeIsSIMD(valTyp))))
14529 // The struct value may be be a child of a GT_COMMA.
14530 GenTree* valx = val->gtEffectiveVal(/*commaOnly*/ true);
14532 if (structHnd != NO_CLASS_HANDLE)
14534 lvaSetStruct(tmp, structHnd, false);
14538 assert(valx->gtOper != GT_OBJ);
14540 dest->gtFlags |= GTF_DONT_CSE;
14541 valx->gtFlags |= GTF_DONT_CSE;
14542 asg = impAssignStruct(dest, val, structHnd, (unsigned)CHECK_SPILL_NONE, pAfterStmt, ilOffset, block);
14546 asg = gtNewAssignNode(dest, val);
14549 if (compRationalIRForm)
14551 Rationalizer::RewriteAssignmentIntoStoreLcl(asg->AsOp());
14557 /*****************************************************************************
14559 * Create a helper call to access a COM field (iff 'assg' is non-zero this is
14560 * an assignment and 'assg' is the new value).
14563 GenTree* Compiler::gtNewRefCOMfield(GenTree* objPtr,
14564 CORINFO_RESOLVED_TOKEN* pResolvedToken,
14565 CORINFO_ACCESS_FLAGS access,
14566 CORINFO_FIELD_INFO* pFieldInfo,
14568 CORINFO_CLASS_HANDLE structType,
14571 assert(pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER ||
14572 pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_ADDR_HELPER ||
14573 pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_ADDR_HELPER);
14575 /* If we can't access it directly, we need to call a helper function */
14576 GenTreeArgList* args = nullptr;
14577 var_types helperType = TYP_BYREF;
14579 if (pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER)
14581 if (access & CORINFO_ACCESS_SET)
14583 assert(assg != nullptr);
14584 // helper needs pointer to struct, not struct itself
14585 if (pFieldInfo->helper == CORINFO_HELP_SETFIELDSTRUCT)
14587 assert(structType != nullptr);
14588 assg = impGetStructAddr(assg, structType, (unsigned)CHECK_SPILL_ALL, true);
14590 else if (lclTyp == TYP_DOUBLE && assg->TypeGet() == TYP_FLOAT)
14592 assg = gtNewCastNode(TYP_DOUBLE, assg, false, TYP_DOUBLE);
14594 else if (lclTyp == TYP_FLOAT && assg->TypeGet() == TYP_DOUBLE)
14596 assg = gtNewCastNode(TYP_FLOAT, assg, false, TYP_FLOAT);
14599 args = gtNewArgList(assg);
14600 helperType = TYP_VOID;
14602 else if (access & CORINFO_ACCESS_GET)
14604 helperType = lclTyp;
14606 // The calling convention for the helper does not take into
14607 // account optimization of primitive structs.
14608 if ((pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT) && !varTypeIsStruct(lclTyp))
14610 helperType = TYP_STRUCT;
14615 if (pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT || pFieldInfo->helper == CORINFO_HELP_SETFIELDSTRUCT)
14617 assert(pFieldInfo->structType != nullptr);
14618 args = gtNewListNode(gtNewIconEmbClsHndNode(pFieldInfo->structType), args);
14621 GenTree* fieldHnd = impTokenToHandle(pResolvedToken);
14622 if (fieldHnd == nullptr)
14623 { // compDonotInline()
14627 args = gtNewListNode(fieldHnd, args);
14629 // If it's a static field, we shouldn't have an object node
14630 // If it's an instance field, we have an object node
14631 assert((pFieldInfo->fieldAccessor != CORINFO_FIELD_STATIC_ADDR_HELPER) ^ (objPtr == nullptr));
14633 if (objPtr != nullptr)
14635 args = gtNewListNode(objPtr, args);
14638 GenTreeCall* call = gtNewHelperCallNode(pFieldInfo->helper, genActualType(helperType), args);
14640 #if FEATURE_MULTIREG_RET
14641 if (varTypeIsStruct(call))
14643 // Initialize Return type descriptor of call node.
14644 ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc();
14645 retTypeDesc->InitializeStructReturnType(this, structType);
14647 #endif // FEATURE_MULTIREG_RET
14649 GenTree* result = call;
14651 if (pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER)
14653 if (access & CORINFO_ACCESS_GET)
14655 if (pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT)
14657 if (!varTypeIsStruct(lclTyp))
14659 // get the result as primitive type
14660 result = impGetStructAddr(result, structType, (unsigned)CHECK_SPILL_ALL, true);
14661 result = gtNewOperNode(GT_IND, lclTyp, result);
14664 else if (varTypeIsIntegral(lclTyp) && genTypeSize(lclTyp) < genTypeSize(TYP_INT))
14666 // The helper does not extend the small return types.
14667 result = gtNewCastNode(genActualType(lclTyp), result, false, lclTyp);
14673 // OK, now do the indirection
14674 if (access & CORINFO_ACCESS_GET)
14676 if (varTypeIsStruct(lclTyp))
14678 result = gtNewObjNode(structType, result);
14682 result = gtNewOperNode(GT_IND, lclTyp, result);
14684 result->gtFlags |= (GTF_EXCEPT | GTF_GLOB_REF);
14686 else if (access & CORINFO_ACCESS_SET)
14688 if (varTypeIsStruct(lclTyp))
14690 result = impAssignStructPtr(result, assg, structType, (unsigned)CHECK_SPILL_ALL);
14694 result = gtNewOperNode(GT_IND, lclTyp, result);
14695 result->gtFlags |= (GTF_EXCEPT | GTF_GLOB_REF | GTF_IND_TGTANYWHERE);
14696 result = gtNewAssignNode(result, assg);
14704 /*****************************************************************************
14706 * Return true if the given node (excluding children trees) contains side effects.
14707 * Note that it does not recurse, and children need to be handled separately.
14708 * It may return false even if the node has GTF_SIDE_EFFECT (because of its children).
14710 * Similar to OperMayThrow() (but handles GT_CALLs specially), but considers
14714 bool Compiler::gtNodeHasSideEffects(GenTree* tree, unsigned flags)
14716 if (flags & GTF_ASG)
14718 // TODO-Cleanup: This only checks for GT_ASG but according to OperRequiresAsgFlag there
14719 // are many more opers that are considered to have an assignment side effect: atomic ops
14720 // (GT_CMPXCHG & co.), GT_MEMORYBARRIER (not classified as an atomic op) and HW intrinsic
14721 // memory stores. Atomic ops have special handling in gtExtractSideEffList but the others
14722 // will simply be dropped is they are ever subject to an "extract side effects" operation.
14723 // It is possible that the reason no bugs have yet been observed in this area is that the
14724 // other nodes are likely to always be tree roots.
14725 if (tree->OperIs(GT_ASG))
14731 // Are there only GTF_CALL side effects remaining? (and no other side effect kinds)
14732 if (flags & GTF_CALL)
14734 if (tree->OperGet() == GT_CALL)
14736 GenTreeCall* const call = tree->AsCall();
14737 const bool ignoreExceptions = (flags & GTF_EXCEPT) == 0;
14738 const bool ignoreCctors = (flags & GTF_IS_IN_CSE) != 0; // We can CSE helpers that run cctors.
14739 if (!call->HasSideEffects(this, ignoreExceptions, ignoreCctors))
14741 // If this call is otherwise side effect free, check its arguments.
14742 for (GenTreeArgList* args = call->gtCallArgs; args != nullptr; args = args->Rest())
14744 if (gtTreeHasSideEffects(args->Current(), flags))
14749 // I'm a little worried that args that assign to temps that are late args will look like
14750 // side effects...but better to be conservative for now.
14751 for (GenTreeArgList* args = call->gtCallLateArgs; args != nullptr; args = args->Rest())
14753 if (gtTreeHasSideEffects(args->Current(), flags))
14763 // Otherwise the GT_CALL is considered to have side-effects.
14768 if (flags & GTF_EXCEPT)
14770 if (tree->OperMayThrow(this))
14776 // Expressions declared as CSE by (e.g.) hoisting code are considered to have relevant side
14777 // effects (if we care about GTF_MAKE_CSE).
14778 if ((flags & GTF_MAKE_CSE) && (tree->gtFlags & GTF_MAKE_CSE))
14786 /*****************************************************************************
14787 * Returns true if the expr tree has any side effects.
14790 bool Compiler::gtTreeHasSideEffects(GenTree* tree, unsigned flags /* = GTF_SIDE_EFFECT*/)
14792 // These are the side effect flags that we care about for this tree
14793 unsigned sideEffectFlags = tree->gtFlags & flags;
14795 // Does this tree have any Side-effect flags set that we care about?
14796 if (sideEffectFlags == 0)
14802 if (sideEffectFlags == GTF_CALL)
14804 if (tree->OperGet() == GT_CALL)
14806 // Generally all trees that contain GT_CALL nodes are considered to have side-effects.
14808 if (tree->gtCall.gtCallType == CT_HELPER)
14810 // If this node is a helper call we may not care about the side-effects.
14811 // Note that gtNodeHasSideEffects checks the side effects of the helper itself
14812 // as well as the side effects of its arguments.
14813 return gtNodeHasSideEffects(tree, flags);
14816 else if (tree->OperGet() == GT_INTRINSIC)
14818 if (gtNodeHasSideEffects(tree, flags))
14823 if (gtNodeHasSideEffects(tree->gtOp.gtOp1, flags))
14828 if ((tree->gtOp.gtOp2 != nullptr) && gtNodeHasSideEffects(tree->gtOp.gtOp2, flags))
14840 GenTree* Compiler::gtBuildCommaList(GenTree* list, GenTree* expr)
14842 // 'list' starts off as null,
14843 // and when it is null we haven't started the list yet.
14845 if (list != nullptr)
14847 // Create a GT_COMMA that appends 'expr' in front of the remaining set of expressions in (*list)
14848 GenTree* result = gtNewOperNode(GT_COMMA, TYP_VOID, expr, list);
14850 // Set the flags in the comma node
14851 result->gtFlags |= (list->gtFlags & GTF_ALL_EFFECT);
14852 result->gtFlags |= (expr->gtFlags & GTF_ALL_EFFECT);
14854 // 'list' and 'expr' should have valuenumbers defined for both or for neither one (unless we are remorphing,
14855 // in which case a prior transform involving either node may have discarded or otherwise invalidated the value
14857 assert((list->gtVNPair.BothDefined() == expr->gtVNPair.BothDefined()) || !fgGlobalMorph);
14859 // Set the ValueNumber 'gtVNPair' for the new GT_COMMA node
14861 if (list->gtVNPair.BothDefined() && expr->gtVNPair.BothDefined())
14863 // The result of a GT_COMMA node is op2, the normal value number is op2vnp
14864 // But we also need to include the union of side effects from op1 and op2.
14865 // we compute this value into exceptions_vnp.
14866 ValueNumPair op1vnp;
14867 ValueNumPair op1Xvnp = ValueNumStore::VNPForEmptyExcSet();
14868 ValueNumPair op2vnp;
14869 ValueNumPair op2Xvnp = ValueNumStore::VNPForEmptyExcSet();
14871 vnStore->VNPUnpackExc(expr->gtVNPair, &op1vnp, &op1Xvnp);
14872 vnStore->VNPUnpackExc(list->gtVNPair, &op2vnp, &op2Xvnp);
14874 ValueNumPair exceptions_vnp = ValueNumStore::VNPForEmptyExcSet();
14876 exceptions_vnp = vnStore->VNPExcSetUnion(exceptions_vnp, op1Xvnp);
14877 exceptions_vnp = vnStore->VNPExcSetUnion(exceptions_vnp, op2Xvnp);
14879 result->gtVNPair = vnStore->VNPWithExc(op2vnp, exceptions_vnp);
14886 // The 'expr' will start the list of expressions
14891 //------------------------------------------------------------------------
14892 // gtExtractSideEffList: Extracts side effects from the given expression.
14895 // expr - the expression tree to extract side effects from
14896 // pList - pointer to a (possibly null) GT_COMMA list that
14897 // will contain the extracted side effects
14898 // flags - side effect flags to be considered
14899 // ignoreRoot - ignore side effects on the expression root node
14902 // Side effects are prepended to the GT_COMMA list such that op1 of
14903 // each comma node holds the side effect tree and op2 points to the
14904 // next comma node. The original side effect execution order is preserved.
14906 void Compiler::gtExtractSideEffList(GenTree* expr,
14908 unsigned flags /* = GTF_SIDE_EFFECT*/,
14909 bool ignoreRoot /* = false */)
14911 class SideEffectExtractor final : public GenTreeVisitor<SideEffectExtractor>
14914 const unsigned m_flags;
14915 ArrayStack<GenTree*> m_sideEffects;
14920 UseExecutionOrder = true
14923 SideEffectExtractor(Compiler* compiler, unsigned flags)
14924 : GenTreeVisitor(compiler), m_flags(flags), m_sideEffects(compiler->getAllocator(CMK_SideEffects))
14928 fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
14930 GenTree* node = *use;
14932 bool treeHasSideEffects = m_compiler->gtTreeHasSideEffects(node, m_flags);
14934 if (treeHasSideEffects)
14936 if (m_compiler->gtNodeHasSideEffects(node, m_flags))
14938 m_sideEffects.Push(node);
14939 return Compiler::WALK_SKIP_SUBTREES;
14942 // TODO-Cleanup: These have GTF_ASG set but for some reason gtNodeHasSideEffects ignores
14943 // them. See the related gtNodeHasSideEffects comment as well.
14944 // Also, these nodes must always be preserved, no matter what side effect flags are passed
14945 // in. But then it should never be the case that gtExtractSideEffList gets called without
14946 // specifying GTF_ASG so there doesn't seem to be any reason to be inconsistent with
14947 // gtNodeHasSideEffects and make this check unconditionally.
14948 if (node->OperIsAtomicOp())
14950 m_sideEffects.Push(node);
14951 return Compiler::WALK_SKIP_SUBTREES;
14954 if ((m_flags & GTF_EXCEPT) != 0)
14956 // Special case - GT_ADDR of GT_IND nodes of TYP_STRUCT have to be kept together.
14957 if (node->OperIs(GT_ADDR) && node->gtGetOp1()->OperIsIndir() &&
14958 (node->gtGetOp1()->TypeGet() == TYP_STRUCT))
14961 if (m_compiler->verbose)
14963 printf("Keep the GT_ADDR and GT_IND together:\n");
14966 m_sideEffects.Push(node);
14967 return Compiler::WALK_SKIP_SUBTREES;
14971 // Generally all GT_CALL nodes are considered to have side-effects.
14972 // So if we get here it must be a helper call that we decided it does
14973 // not have side effects that we needed to keep.
14974 assert(!node->OperIs(GT_CALL) || (node->AsCall()->gtCallType == CT_HELPER));
14977 if ((m_flags & GTF_IS_IN_CSE) != 0)
14979 // If we're doing CSE then we also need to unmark CSE nodes. This will fail for CSE defs,
14980 // those need to be extracted as if they're side effects.
14981 if (!UnmarkCSE(node))
14983 m_sideEffects.Push(node);
14984 return Compiler::WALK_SKIP_SUBTREES;
14987 // The existence of CSE defs and uses is not propagated up the tree like side
14988 // effects are. We need to continue visiting the tree as if it has side effects.
14989 treeHasSideEffects = true;
14992 return treeHasSideEffects ? Compiler::WALK_CONTINUE : Compiler::WALK_SKIP_SUBTREES;
14996 bool UnmarkCSE(GenTree* node)
14998 assert(m_compiler->optValnumCSE_phase);
15000 if (m_compiler->optUnmarkCSE(node))
15002 // The call to optUnmarkCSE(node) should have cleared any CSE info.
15003 assert(!IS_CSE_INDEX(node->gtCSEnum));
15008 assert(IS_CSE_DEF(node->gtCSEnum));
15010 if (m_compiler->verbose)
15012 printf("Preserving the CSE def #%02d at ", GET_CSE_INDEX(node->gtCSEnum));
15013 m_compiler->printTreeID(node);
15021 assert(!expr->OperIs(GT_STMT));
15023 SideEffectExtractor extractor(this, flags);
15027 for (GenTree* op : expr->Operands())
15029 extractor.WalkTree(&op, nullptr);
15034 extractor.WalkTree(&expr, nullptr);
15037 GenTree* list = *pList;
15039 // The extractor returns side effects in execution order but gtBuildCommaList prepends
15040 // to the comma-based side effect list so we have to build the list in reverse order.
15041 // This is also why the list cannot be built while traversing the tree.
15042 // The number of side effects is usually small (<= 4), less than the ArrayStack's
15043 // built-in size, so memory allocation is avoided.
15044 while (!extractor.m_sideEffects.Empty())
15046 list = gtBuildCommaList(list, extractor.m_sideEffects.Pop());
15052 /*****************************************************************************
15054 * For debugging only - displays a tree node list and makes sure all the
15055 * links are correctly set.
15060 void dispNodeList(GenTree* list, bool verbose)
15062 GenTree* last = nullptr;
15072 next = list->gtNext;
15076 printf("%08X -> %08X -> %08X\n", last, list, next);
15079 assert(!last || last->gtNext == list);
15081 assert(next == nullptr || next->gtPrev == list);
15091 printf(""); // null string means flush
15094 /*****************************************************************************
15095 * Callback to assert that the nodes of a qmark-colon subtree are marked
15099 Compiler::fgWalkResult Compiler::gtAssertColonCond(GenTree** pTree, fgWalkData* data)
15101 assert(data->pCallbackData == nullptr);
15103 assert((*pTree)->gtFlags & GTF_COLON_COND);
15105 return WALK_CONTINUE;
15109 /*****************************************************************************
15110 * Callback to mark the nodes of a qmark-colon subtree that are conditionally
15115 Compiler::fgWalkResult Compiler::gtMarkColonCond(GenTree** pTree, fgWalkData* data)
15117 assert(data->pCallbackData == nullptr);
15119 (*pTree)->gtFlags |= GTF_COLON_COND;
15121 return WALK_CONTINUE;
15124 /*****************************************************************************
15125 * Callback to clear the conditionally executed flags of nodes that no longer
15126 will be conditionally executed. Note that when we find another colon we must
15127 stop, as the nodes below this one WILL be conditionally executed. This callback
15128 is called when folding a qmark condition (ie the condition is constant).
15132 Compiler::fgWalkResult Compiler::gtClearColonCond(GenTree** pTree, fgWalkData* data)
15134 GenTree* tree = *pTree;
15136 assert(data->pCallbackData == nullptr);
15138 if (tree->OperGet() == GT_COLON)
15140 // Nodes below this will be conditionally executed.
15141 return WALK_SKIP_SUBTREES;
15144 tree->gtFlags &= ~GTF_COLON_COND;
15145 return WALK_CONTINUE;
15148 struct FindLinkData
15150 GenTree* nodeToFind;
15154 /*****************************************************************************
15156 * Callback used by the tree walker to implement fgFindLink()
15158 static Compiler::fgWalkResult gtFindLinkCB(GenTree** pTree, Compiler::fgWalkData* cbData)
15160 FindLinkData* data = (FindLinkData*)cbData->pCallbackData;
15161 if (*pTree == data->nodeToFind)
15163 data->result = pTree;
15164 return Compiler::WALK_ABORT;
15167 return Compiler::WALK_CONTINUE;
15170 GenTree** Compiler::gtFindLink(GenTreeStmt* stmt, GenTree* node)
15172 FindLinkData data = {node, nullptr};
15174 fgWalkResult result = fgWalkTreePre(&stmt->gtStmtExpr, gtFindLinkCB, &data);
15176 if (result == WALK_ABORT)
15178 assert(data.nodeToFind == *data.result);
15179 return data.result;
15187 /*****************************************************************************
15189 * Callback that checks if a tree node has oper type GT_CATCH_ARG
15192 static Compiler::fgWalkResult gtFindCatchArg(GenTree** pTree, Compiler::fgWalkData* /* data */)
15194 return ((*pTree)->OperGet() == GT_CATCH_ARG) ? Compiler::WALK_ABORT : Compiler::WALK_CONTINUE;
15197 /*****************************************************************************/
15198 bool Compiler::gtHasCatchArg(GenTree* tree)
15200 if (((tree->gtFlags & GTF_ORDER_SIDEEFF) != 0) && (fgWalkTreePre(&tree, gtFindCatchArg) == WALK_ABORT))
15207 //------------------------------------------------------------------------
15208 // gtHasCallOnStack:
15211 // parentStack: a context (stack of parent nodes)
15214 // returns true if any of the parent nodes are a GT_CALL
15217 // We have a stack of parent nodes. This generally requires that
15218 // we are performing a recursive tree walk using struct fgWalkData
15220 //------------------------------------------------------------------------
15221 /* static */ bool Compiler::gtHasCallOnStack(GenTreeStack* parentStack)
15223 for (int i = 0; i < parentStack->Height(); i++)
15225 GenTree* node = parentStack->Index(i);
15226 if (node->OperGet() == GT_CALL)
15234 //------------------------------------------------------------------------
15235 // gtGetTypeProducerKind: determine if a tree produces a runtime type, and
15239 // tree - tree to examine
15242 // TypeProducerKind for the tree.
15245 // Checks to see if this tree returns a RuntimeType value, and if so,
15246 // how that value is determined.
15248 // Currently handles these cases
15249 // 1) The result of Object::GetType
15250 // 2) The result of typeof(...)
15251 // 3) A null reference
15252 // 4) Tree is otherwise known to have type RuntimeType
15254 // The null reference case is surprisingly common because operator
15255 // overloading turns the otherwise innocuous
15260 // into a method call.
15262 Compiler::TypeProducerKind Compiler::gtGetTypeProducerKind(GenTree* tree)
15264 if (tree->gtOper == GT_CALL)
15266 if (tree->gtCall.gtCallType == CT_HELPER)
15268 if (gtIsTypeHandleToRuntimeTypeHelper(tree->AsCall()))
15273 else if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC)
15275 if (info.compCompHnd->getIntrinsicID(tree->gtCall.gtCallMethHnd) == CORINFO_INTRINSIC_Object_GetType)
15277 return TPK_GetType;
15281 else if ((tree->gtOper == GT_INTRINSIC) && (tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType))
15283 return TPK_GetType;
15285 else if ((tree->gtOper == GT_CNS_INT) && (tree->gtIntCon.gtIconVal == 0))
15291 bool isExact = false;
15292 bool isNonNull = false;
15293 CORINFO_CLASS_HANDLE clsHnd = gtGetClassHandle(tree, &isExact, &isNonNull);
15295 if (clsHnd != NO_CLASS_HANDLE && clsHnd == info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE))
15300 return TPK_Unknown;
15303 //------------------------------------------------------------------------
15304 // gtIsTypeHandleToRuntimeTypeHelperCall -- see if tree is constructing
15305 // a RuntimeType from a handle
15308 // tree - tree to examine
15313 bool Compiler::gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call)
15315 return call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE) ||
15316 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL);
15319 //------------------------------------------------------------------------
15320 // gtIsTypeHandleToRuntimeTypeHandleHelperCall -- see if tree is constructing
15321 // a RuntimeTypeHandle from a handle
15324 // tree - tree to examine
15325 // pHelper - optional pointer to a variable that receives the type of the helper
15330 bool Compiler::gtIsTypeHandleToRuntimeTypeHandleHelper(GenTreeCall* call, CorInfoHelpFunc* pHelper)
15332 CorInfoHelpFunc helper = CORINFO_HELP_UNDEF;
15334 if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE))
15336 helper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE;
15338 else if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL))
15340 helper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL;
15343 if (pHelper != nullptr)
15348 return helper != CORINFO_HELP_UNDEF;
15351 bool Compiler::gtIsActiveCSE_Candidate(GenTree* tree)
15353 return (optValnumCSE_phase && IS_CSE_INDEX(tree->gtCSEnum));
15356 /*****************************************************************************/
15358 struct ComplexityStruct
15360 unsigned m_numNodes;
15361 unsigned m_nodeLimit;
15362 ComplexityStruct(unsigned nodeLimit) : m_numNodes(0), m_nodeLimit(nodeLimit)
15367 static Compiler::fgWalkResult ComplexityExceedsWalker(GenTree** pTree, Compiler::fgWalkData* data)
15369 ComplexityStruct* pComplexity = (ComplexityStruct*)data->pCallbackData;
15370 if (++pComplexity->m_numNodes > pComplexity->m_nodeLimit)
15372 return Compiler::WALK_ABORT;
15376 return Compiler::WALK_CONTINUE;
15380 bool Compiler::gtComplexityExceeds(GenTree** tree, unsigned limit)
15382 ComplexityStruct complexity(limit);
15383 if (fgWalkTreePre(tree, &ComplexityExceedsWalker, &complexity) == WALK_ABORT)
15393 bool GenTree::IsPhiNode()
15395 return (OperGet() == GT_PHI_ARG) || (OperGet() == GT_PHI) || IsPhiDefn();
15398 bool GenTree::IsPhiDefn()
15400 bool res = ((OperGet() == GT_ASG) && (gtOp.gtOp2 != nullptr) && (gtOp.gtOp2->OperGet() == GT_PHI)) ||
15401 ((OperGet() == GT_STORE_LCL_VAR) && (gtOp.gtOp1 != nullptr) && (gtOp.gtOp1->OperGet() == GT_PHI));
15402 assert(!res || OperGet() == GT_STORE_LCL_VAR || gtOp.gtOp1->OperGet() == GT_LCL_VAR);
15406 bool GenTree::IsPhiDefnStmt()
15408 if (OperGet() != GT_STMT)
15412 GenTree* asg = gtStmt.gtStmtExpr;
15413 return asg->IsPhiDefn();
15416 // IsPartialLclFld: Check for a GT_LCL_FLD whose type is a different size than the lclVar.
15419 // comp - the Compiler object.
15422 // Returns "true" iff 'this' is a GT_LCL_FLD or GT_STORE_LCL_FLD on which the type
15423 // is not the same size as the type of the GT_LCL_VAR
15425 bool GenTree::IsPartialLclFld(Compiler* comp)
15427 return ((gtOper == GT_LCL_FLD) &&
15428 (comp->lvaTable[this->gtLclVarCommon.gtLclNum].lvExactSize != genTypeSize(gtType)));
15431 bool GenTree::DefinesLocal(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, bool* pIsEntire)
15433 GenTreeBlk* blkNode = nullptr;
15434 if (OperIs(GT_ASG))
15436 if (gtOp.gtOp1->IsLocal())
15438 GenTreeLclVarCommon* lclVarTree = gtOp.gtOp1->AsLclVarCommon();
15439 *pLclVarTree = lclVarTree;
15440 if (pIsEntire != nullptr)
15442 if (lclVarTree->IsPartialLclFld(comp))
15444 *pIsEntire = false;
15453 else if (gtOp.gtOp1->OperGet() == GT_IND)
15455 GenTree* indArg = gtOp.gtOp1->gtOp.gtOp1;
15456 return indArg->DefinesLocalAddr(comp, genTypeSize(gtOp.gtOp1->TypeGet()), pLclVarTree, pIsEntire);
15458 else if (gtOp.gtOp1->OperIsBlk())
15460 blkNode = gtOp.gtOp1->AsBlk();
15463 else if (OperIsBlk())
15465 blkNode = this->AsBlk();
15467 if (blkNode != nullptr)
15469 GenTree* destAddr = blkNode->Addr();
15470 unsigned width = blkNode->gtBlkSize;
15471 // Do we care about whether this assigns the entire variable?
15472 if (pIsEntire != nullptr && width == 0)
15474 assert(blkNode->gtOper == GT_DYN_BLK);
15475 GenTree* blockWidth = blkNode->AsDynBlk()->gtDynamicSize;
15476 if (blockWidth->IsCnsIntOrI())
15478 if (blockWidth->IsIconHandle())
15480 // If it's a handle, it must be a class handle. We only create such block operations
15481 // for initialization of struct types, so the type of the argument(s) will match this
15482 // type, by construction, and be "entire".
15483 assert(blockWidth->IsIconHandle(GTF_ICON_CLASS_HDL));
15484 width = comp->info.compCompHnd->getClassSize(
15485 CORINFO_CLASS_HANDLE(blockWidth->gtIntConCommon.IconValue()));
15489 ssize_t swidth = blockWidth->AsIntConCommon()->IconValue();
15490 assert(swidth >= 0);
15491 // cpblk of size zero exists in the wild (in yacc-generated code in SQL) and is valid IL.
15496 width = unsigned(swidth);
15500 return destAddr->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
15506 // Returns true if this GenTree defines a result which is based on the address of a local.
15507 bool GenTree::DefinesLocalAddr(Compiler* comp, unsigned width, GenTreeLclVarCommon** pLclVarTree, bool* pIsEntire)
15509 if (OperGet() == GT_ADDR || OperGet() == GT_LCL_VAR_ADDR)
15511 GenTree* addrArg = this;
15512 if (OperGet() == GT_ADDR)
15514 addrArg = gtOp.gtOp1;
15517 if (addrArg->IsLocal() || addrArg->OperIsLocalAddr())
15519 GenTreeLclVarCommon* addrArgLcl = addrArg->AsLclVarCommon();
15520 *pLclVarTree = addrArgLcl;
15521 if (pIsEntire != nullptr)
15523 unsigned lclOffset = 0;
15524 if (addrArg->OperIsLocalField())
15526 lclOffset = addrArg->gtLclFld.gtLclOffs;
15529 if (lclOffset != 0)
15531 // We aren't updating the bytes at [0..lclOffset-1] so *pIsEntire should be set to false
15532 *pIsEntire = false;
15536 unsigned lclNum = addrArgLcl->GetLclNum();
15537 unsigned varWidth = comp->lvaLclExactSize(lclNum);
15538 if (comp->lvaTable[lclNum].lvNormalizeOnStore())
15540 // It's normalize on store, so use the full storage width -- writing to low bytes won't
15541 // necessarily yield a normalized value.
15542 varWidth = genTypeStSz(var_types(comp->lvaTable[lclNum].lvType)) * sizeof(int);
15544 *pIsEntire = (varWidth == width);
15549 else if (addrArg->OperGet() == GT_IND)
15551 // A GT_ADDR of a GT_IND can both be optimized away, recurse using the child of the GT_IND
15552 return addrArg->gtOp.gtOp1->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
15555 else if (OperGet() == GT_ADD)
15557 if (gtOp.gtOp1->IsCnsIntOrI())
15559 // If we just adding a zero then we allow an IsEntire match against width
15560 // otherwise we change width to zero to disallow an IsEntire Match
15561 return gtOp.gtOp2->DefinesLocalAddr(comp, gtOp.gtOp1->IsIntegralConst(0) ? width : 0, pLclVarTree,
15564 else if (gtOp.gtOp2->IsCnsIntOrI())
15566 // If we just adding a zero then we allow an IsEntire match against width
15567 // otherwise we change width to zero to disallow an IsEntire Match
15568 return gtOp.gtOp1->DefinesLocalAddr(comp, gtOp.gtOp2->IsIntegralConst(0) ? width : 0, pLclVarTree,
15572 // Post rationalization we could have GT_IND(GT_LEA(..)) trees.
15573 else if (OperGet() == GT_LEA)
15575 // This method gets invoked during liveness computation and therefore it is critical
15576 // that we don't miss 'use' of any local. The below logic is making the assumption
15577 // that in case of LEA(base, index, offset) - only base can be a GT_LCL_VAR_ADDR
15578 // and index is not.
15579 CLANG_FORMAT_COMMENT_ANCHOR;
15582 GenTree* index = gtOp.gtOp2;
15583 if (index != nullptr)
15585 assert(!index->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire));
15590 GenTree* base = gtOp.gtOp1;
15591 if (base != nullptr)
15593 // Lea could have an Indir as its base.
15594 if (base->OperGet() == GT_IND)
15596 base = base->gtOp.gtOp1->gtEffectiveVal(/*commas only*/ true);
15598 return base->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
15605 //------------------------------------------------------------------------
15606 // IsLocalExpr: Determine if this is a LclVarCommon node and return some
15607 // additional info about it in the two out parameters.
15610 // comp - The Compiler instance
15611 // pLclVarTree - An "out" argument that returns the local tree as a
15612 // LclVarCommon, if it is indeed local.
15613 // pFldSeq - An "out" argument that returns the value numbering field
15614 // sequence for the node, if any.
15617 // Returns true, and sets the out arguments accordingly, if this is
15618 // a LclVarCommon node.
15620 bool GenTree::IsLocalExpr(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, FieldSeqNode** pFldSeq)
15622 if (IsLocal()) // Note that this covers "GT_LCL_FLD."
15624 *pLclVarTree = AsLclVarCommon();
15625 if (OperGet() == GT_LCL_FLD)
15627 // Otherwise, prepend this field to whatever we've already accumulated outside in.
15628 *pFldSeq = comp->GetFieldSeqStore()->Append(AsLclFld()->gtFieldSeq, *pFldSeq);
15638 // If this tree evaluates some sum of a local address and some constants,
15639 // return the node for the local being addressed
15641 GenTreeLclVarCommon* GenTree::IsLocalAddrExpr()
15643 if (OperGet() == GT_ADDR)
15645 return gtOp.gtOp1->IsLocal() ? gtOp.gtOp1->AsLclVarCommon() : nullptr;
15647 else if (OperIsLocalAddr())
15649 return this->AsLclVarCommon();
15651 else if (OperGet() == GT_ADD)
15653 if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
15655 return gtOp.gtOp2->IsLocalAddrExpr();
15657 else if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
15659 return gtOp.gtOp1->IsLocalAddrExpr();
15666 bool GenTree::IsLocalAddrExpr(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, FieldSeqNode** pFldSeq)
15668 if (OperGet() == GT_ADDR)
15670 assert(!comp->compRationalIRForm);
15671 GenTree* addrArg = gtOp.gtOp1;
15672 if (addrArg->IsLocal()) // Note that this covers "GT_LCL_FLD."
15674 *pLclVarTree = addrArg->AsLclVarCommon();
15675 if (addrArg->OperGet() == GT_LCL_FLD)
15677 // Otherwise, prepend this field to whatever we've already accumulated outside in.
15678 *pFldSeq = comp->GetFieldSeqStore()->Append(addrArg->AsLclFld()->gtFieldSeq, *pFldSeq);
15687 else if (OperIsLocalAddr())
15689 *pLclVarTree = this->AsLclVarCommon();
15690 if (this->OperGet() == GT_LCL_FLD_ADDR)
15692 *pFldSeq = comp->GetFieldSeqStore()->Append(this->AsLclFld()->gtFieldSeq, *pFldSeq);
15696 else if (OperGet() == GT_ADD)
15698 if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
15700 if (gtOp.gtOp1->AsIntCon()->gtFieldSeq == nullptr)
15704 // Otherwise, prepend this field to whatever we've already accumulated outside in.
15705 *pFldSeq = comp->GetFieldSeqStore()->Append(gtOp.gtOp1->AsIntCon()->gtFieldSeq, *pFldSeq);
15706 return gtOp.gtOp2->IsLocalAddrExpr(comp, pLclVarTree, pFldSeq);
15708 else if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
15710 if (gtOp.gtOp2->AsIntCon()->gtFieldSeq == nullptr)
15714 // Otherwise, prepend this field to whatever we've already accumulated outside in.
15715 *pFldSeq = comp->GetFieldSeqStore()->Append(gtOp.gtOp2->AsIntCon()->gtFieldSeq, *pFldSeq);
15716 return gtOp.gtOp1->IsLocalAddrExpr(comp, pLclVarTree, pFldSeq);
15723 //------------------------------------------------------------------------
15724 // IsLclVarUpdateTree: Determine whether this is an assignment tree of the
15725 // form Vn = Vn 'oper' 'otherTree' where Vn is a lclVar
15728 // pOtherTree - An "out" argument in which 'otherTree' will be returned.
15729 // pOper - An "out" argument in which 'oper' will be returned.
15732 // If the tree is of the above form, the lclNum of the variable being
15733 // updated is returned, and 'pOtherTree' and 'pOper' are set.
15734 // Otherwise, returns BAD_VAR_NUM.
15737 // 'otherTree' can have any shape.
15738 // We avoid worrying about whether the op is commutative by only considering the
15739 // first operand of the rhs. It is expected that most trees of this form will
15740 // already have the lclVar on the lhs.
15741 // TODO-CQ: Evaluate whether there are missed opportunities due to this, or
15742 // whether gtSetEvalOrder will already have put the lclVar on the lhs in
15743 // the cases of interest.
15745 unsigned GenTree::IsLclVarUpdateTree(GenTree** pOtherTree, genTreeOps* pOper)
15747 unsigned lclNum = BAD_VAR_NUM;
15748 if (OperIs(GT_ASG))
15750 GenTree* lhs = gtOp.gtOp1;
15751 if (lhs->OperGet() == GT_LCL_VAR)
15753 unsigned lhsLclNum = lhs->AsLclVarCommon()->gtLclNum;
15754 GenTree* rhs = gtOp.gtOp2;
15755 if (rhs->OperIsBinary() && (rhs->gtOp.gtOp1->gtOper == GT_LCL_VAR) &&
15756 (rhs->gtOp.gtOp1->AsLclVarCommon()->gtLclNum == lhsLclNum))
15758 lclNum = lhsLclNum;
15759 *pOtherTree = rhs->gtOp.gtOp2;
15760 *pOper = rhs->gtOper;
15767 //------------------------------------------------------------------------
15768 // canBeContained: check whether this tree node may be a subcomponent of its parent for purposes
15769 // of code generation.
15771 // Return value: returns true if it is possible to contain this node and false otherwise.
15772 bool GenTree::canBeContained() const
15781 // It is not possible for nodes that do not produce values or that are not containable values
15782 // to be contained.
15783 if (((OperKind() & (GTK_NOVALUE | GTK_NOCONTAIN)) != 0) || (OperIsHWIntrinsic() && !isContainableHWIntrinsic()))
15791 //------------------------------------------------------------------------
15792 // isContained: check whether this tree node is a subcomponent of its parent for codegen purposes
15795 // Returns true if there is no code generated explicitly for this node.
15796 // Essentially, it will be rolled into the code generation for the parent.
15799 // This method relies upon the value of the GTF_CONTAINED flag.
15800 // Therefore this method is only valid after Lowering.
15801 // Also note that register allocation or other subsequent phases may cause
15802 // nodes to become contained (or not) and therefore this property may change.
15804 bool GenTree::isContained() const
15807 const bool isMarkedContained = ((gtFlags & GTF_CONTAINED) != 0);
15810 if (!canBeContained())
15812 assert(!isMarkedContained);
15815 // these actually produce a register (the flags reg, we just don't model it)
15816 // and are a separate instruction from the branch that consumes the result.
15817 // They can only produce a result if the child is a SIMD equality comparison.
15818 else if (OperKind() & GTK_RELOP)
15820 // We have to cast away const-ness since AsOp() method is non-const.
15821 GenTree* childNode = const_cast<GenTree*>(this)->AsOp()->gtOp1;
15822 assert((isMarkedContained == false) || childNode->IsSIMDEqualityOrInequality());
15825 // these either produce a result in register or set flags reg.
15826 else if (IsSIMDEqualityOrInequality())
15828 assert(!isMarkedContained);
15831 // if it's contained it can't be unused.
15832 if (isMarkedContained)
15834 assert(!IsUnusedValue());
15837 return isMarkedContained;
15840 // return true if node is contained and an indir
15841 bool GenTree::isContainedIndir() const
15843 return isIndir() && isContained();
15846 bool GenTree::isIndirAddrMode()
15848 return isIndir() && AsIndir()->Addr()->OperIsAddrMode() && AsIndir()->Addr()->isContained();
15851 bool GenTree::isIndir() const
15853 return OperGet() == GT_IND || OperGet() == GT_STOREIND;
15856 bool GenTreeIndir::HasBase()
15858 return Base() != nullptr;
15861 bool GenTreeIndir::HasIndex()
15863 return Index() != nullptr;
15866 GenTree* GenTreeIndir::Base()
15868 GenTree* addr = Addr();
15870 if (isIndirAddrMode())
15872 GenTree* result = addr->AsAddrMode()->Base();
15873 if (result != nullptr)
15875 result = result->gtEffectiveVal();
15881 return addr; // TODO: why do we return 'addr' here, but we return 'nullptr' in the equivalent Index() case?
15885 GenTree* GenTreeIndir::Index()
15887 if (isIndirAddrMode())
15889 GenTree* result = Addr()->AsAddrMode()->Index();
15890 if (result != nullptr)
15892 result = result->gtEffectiveVal();
15902 unsigned GenTreeIndir::Scale()
15906 return Addr()->AsAddrMode()->gtScale;
15914 ssize_t GenTreeIndir::Offset()
15916 if (isIndirAddrMode())
15918 return Addr()->AsAddrMode()->Offset();
15920 else if (Addr()->gtOper == GT_CLS_VAR_ADDR)
15922 return static_cast<ssize_t>(reinterpret_cast<intptr_t>(Addr()->gtClsVar.gtClsVarHnd));
15924 else if (Addr()->IsCnsIntOrI() && Addr()->isContained())
15926 return Addr()->AsIntConCommon()->IconValue();
15934 //------------------------------------------------------------------------
15935 // GenTreeIntConCommon::ImmedValNeedsReloc: does this immediate value needs recording a relocation with the VM?
15938 // comp - Compiler instance
15941 // True if this immediate value requires us to record a relocation for it; false otherwise.
15943 bool GenTreeIntConCommon::ImmedValNeedsReloc(Compiler* comp)
15945 return comp->opts.compReloc && (gtOper == GT_CNS_INT) && IsIconHandle();
15948 //------------------------------------------------------------------------
15949 // ImmedValCanBeFolded: can this immediate value be folded for op?
15952 // comp - Compiler instance
15953 // op - Tree operator
15956 // True if this immediate value can be folded for op; false otherwise.
15958 bool GenTreeIntConCommon::ImmedValCanBeFolded(Compiler* comp, genTreeOps op)
15960 // In general, immediate values that need relocations can't be folded.
15961 // There are cases where we do want to allow folding of handle comparisons
15962 // (e.g., typeof(T) == typeof(int)).
15963 return !ImmedValNeedsReloc(comp) || (op == GT_EQ) || (op == GT_NE);
15966 #ifdef _TARGET_AMD64_
15967 // Returns true if this absolute address fits within the base of an addr mode.
15968 // On Amd64 this effectively means, whether an absolute indirect address can
15969 // be encoded as 32-bit offset relative to IP or zero.
15970 bool GenTreeIntConCommon::FitsInAddrBase(Compiler* comp)
15973 // Early out if PC-rel encoding of absolute addr is disabled.
15974 if (!comp->opts.compEnablePCRelAddr)
15980 if (comp->opts.compReloc)
15982 // During Ngen JIT is always asked to generate relocatable code.
15983 // Hence JIT will try to encode only icon handles as pc-relative offsets.
15984 return IsIconHandle() && (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue()));
15988 // During Jitting, we are allowed to generate non-relocatable code.
15989 // On Amd64 we can encode an absolute indirect addr as an offset relative to zero or RIP.
15990 // An absolute indir addr that can fit within 32-bits can ben encoded as an offset relative
15991 // to zero. All other absolute indir addr could be attempted to be encoded as RIP relative
15992 // based on reloc hint provided by VM. RIP relative encoding is preferred over relative
15993 // to zero, because the former is one byte smaller than the latter. For this reason
15994 // we check for reloc hint first and then whether addr fits in 32-bits next.
15996 // VM starts off with an initial state to allow both data and code address to be encoded as
15997 // pc-relative offsets. Hence JIT will attempt to encode all absolute addresses as pc-relative
15998 // offsets. It is possible while jitting a method, an address could not be encoded as a
15999 // pc-relative offset. In that case VM will note the overflow and will trigger re-jitting
16000 // of the method with reloc hints turned off for all future methods. Second time around
16001 // jitting will succeed since JIT will not attempt to encode data addresses as pc-relative
16002 // offsets. Note that JIT will always attempt to relocate code addresses (.e.g call addr).
16003 // After an overflow, VM will assume any relocation recorded is for a code address and will
16004 // emit jump thunk if it cannot be encoded as pc-relative offset.
16005 return (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue())) || FitsInI32();
16009 // Returns true if this icon value is encoded as addr needs recording a relocation with VM
16010 bool GenTreeIntConCommon::AddrNeedsReloc(Compiler* comp)
16012 if (comp->opts.compReloc)
16014 // During Ngen JIT is always asked to generate relocatable code.
16015 // Hence JIT will try to encode only icon handles as pc-relative offsets.
16016 return IsIconHandle() && (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue()));
16020 return IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue());
16024 #elif defined(_TARGET_X86_)
16025 // Returns true if this absolute address fits within the base of an addr mode.
16026 // On x86 all addresses are 4-bytes and can be directly encoded in an addr mode.
16027 bool GenTreeIntConCommon::FitsInAddrBase(Compiler* comp)
16030 // Early out if PC-rel encoding of absolute addr is disabled.
16031 if (!comp->opts.compEnablePCRelAddr)
16037 return IsCnsIntOrI();
16040 // Returns true if this icon value is encoded as addr needs recording a relocation with VM
16041 bool GenTreeIntConCommon::AddrNeedsReloc(Compiler* comp)
16043 // If generating relocatable code, icons should be reported for recording relocatons.
16044 return comp->opts.compReloc && IsIconHandle();
16046 #endif //_TARGET_X86_
16048 bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pObj, GenTree** pStatic, FieldSeqNode** pFldSeq)
16050 FieldSeqNode* newFldSeq = nullptr;
16051 GenTree* baseAddr = nullptr;
16052 bool mustBeStatic = false;
16054 FieldSeqNode* statStructFldSeq = nullptr;
16055 if (TypeGet() == TYP_REF)
16057 // Recognize struct static field patterns...
16058 if (OperGet() == GT_IND)
16060 GenTree* addr = gtOp.gtOp1;
16061 GenTreeIntCon* icon = nullptr;
16062 if (addr->OperGet() == GT_CNS_INT)
16064 icon = addr->AsIntCon();
16066 else if (addr->OperGet() == GT_ADD)
16068 // op1 should never be a field sequence (or any other kind of handle)
16069 assert((addr->gtOp.gtOp1->gtOper != GT_CNS_INT) || !addr->gtOp.gtOp1->IsIconHandle());
16070 if (addr->gtOp.gtOp2->OperGet() == GT_CNS_INT)
16072 icon = addr->gtOp.gtOp2->AsIntCon();
16075 if (icon != nullptr && !icon->IsIconHandle(GTF_ICON_STR_HDL) // String handles are a source of TYP_REFs.
16076 && icon->gtFieldSeq != nullptr &&
16077 icon->gtFieldSeq->m_next == nullptr // A static field should be a singleton
16078 // TODO-Review: A pseudoField here indicates an issue - this requires investigation
16079 // See test case src\ddsuites\src\clr\x86\CoreMangLib\Dev\Globalization\CalendarRegressions.exe
16080 && !(FieldSeqStore::IsPseudoField(icon->gtFieldSeq->m_fieldHnd)) &&
16081 icon->gtFieldSeq != FieldSeqStore::NotAField()) // Ignore non-fields.
16083 statStructFldSeq = icon->gtFieldSeq;
16087 addr = addr->gtEffectiveVal();
16089 // Perhaps it's a direct indirection of a helper call or a cse with a zero offset annotation.
16090 if ((addr->OperGet() == GT_CALL) || (addr->OperGet() == GT_LCL_VAR))
16092 FieldSeqNode* zeroFieldSeq = nullptr;
16093 if (comp->GetZeroOffsetFieldMap()->Lookup(addr, &zeroFieldSeq))
16095 if (zeroFieldSeq->m_next == nullptr)
16097 statStructFldSeq = zeroFieldSeq;
16103 else if (OperGet() == GT_CLS_VAR)
16105 GenTreeClsVar* clsVar = AsClsVar();
16106 if (clsVar->gtFieldSeq != nullptr && clsVar->gtFieldSeq->m_next == nullptr)
16108 statStructFldSeq = clsVar->gtFieldSeq;
16111 else if (OperIsLocal())
16113 // If we have a GT_LCL_VAR, it can be result of a CSE substitution
16114 // If it is then the CSE assignment will have a ValueNum that
16115 // describes the RHS of the CSE assignment.
16117 // The CSE could be a pointer to a boxed struct
16119 GenTreeLclVarCommon* lclVar = AsLclVarCommon();
16120 ValueNum vn = gtVNPair.GetLiberal();
16121 if (vn != ValueNumStore::NoVN)
16123 // Is the ValueNum a MapSelect involving a SharedStatic helper?
16124 VNFuncApp funcApp1;
16125 if (comp->vnStore->GetVNFunc(vn, &funcApp1) && (funcApp1.m_func == VNF_MapSelect) &&
16126 (comp->vnStore->IsSharedStatic(funcApp1.m_args[1])))
16128 ValueNum mapVN = funcApp1.m_args[0];
16129 // Is this new 'mapVN' ValueNum, a MapSelect involving a handle?
16130 VNFuncApp funcApp2;
16131 if (comp->vnStore->GetVNFunc(mapVN, &funcApp2) && (funcApp2.m_func == VNF_MapSelect) &&
16132 (comp->vnStore->IsVNHandle(funcApp2.m_args[1])))
16134 ValueNum fldHndVN = funcApp2.m_args[1];
16135 // Is this new 'fldHndVN' VNhandle a FieldHandle?
16136 unsigned flags = comp->vnStore->GetHandleFlags(fldHndVN);
16137 if (flags == GTF_ICON_FIELD_HDL)
16139 CORINFO_FIELD_HANDLE fieldHnd =
16140 CORINFO_FIELD_HANDLE(comp->vnStore->ConstantValue<ssize_t>(fldHndVN));
16142 // Record this field sequence in 'statStructFldSeq' as it is likely to be a Boxed Struct
16144 statStructFldSeq = comp->GetFieldSeqStore()->CreateSingleton(fieldHnd);
16151 if (statStructFldSeq != nullptr)
16153 assert(statStructFldSeq->m_next == nullptr);
16154 // Is this a pointer to a boxed struct?
16155 if (comp->gtIsStaticFieldPtrToBoxedStruct(TYP_REF, statStructFldSeq->m_fieldHnd))
16157 *pFldSeq = comp->GetFieldSeqStore()->Append(statStructFldSeq, *pFldSeq);
16166 *pStatic = nullptr;
16169 else if (OperGet() == GT_ADD)
16171 // If one operator is a field sequence/handle, the other operator must not also be a field sequence/handle.
16172 if ((gtOp.gtOp1->OperGet() == GT_CNS_INT) && gtOp.gtOp1->IsIconHandle())
16174 assert((gtOp.gtOp2->gtOper != GT_CNS_INT) || !gtOp.gtOp2->IsIconHandle());
16175 newFldSeq = gtOp.gtOp1->AsIntCon()->gtFieldSeq;
16176 baseAddr = gtOp.gtOp2;
16178 else if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
16180 assert((gtOp.gtOp1->gtOper != GT_CNS_INT) || !gtOp.gtOp1->IsIconHandle());
16181 newFldSeq = gtOp.gtOp2->AsIntCon()->gtFieldSeq;
16182 baseAddr = gtOp.gtOp1;
16187 // Check if "this" has a zero-offset annotation.
16188 if (!comp->GetZeroOffsetFieldMap()->Lookup(this, &newFldSeq))
16190 // If not, this is not a field address.
16196 mustBeStatic = true;
16200 // If not we don't have a field seq, it's not a field address.
16201 if (newFldSeq == nullptr || newFldSeq == FieldSeqStore::NotAField())
16206 // Prepend this field to whatever we've already accumulated (outside-in).
16207 *pFldSeq = comp->GetFieldSeqStore()->Append(newFldSeq, *pFldSeq);
16209 // Is it a static or instance field?
16210 if (!FieldSeqStore::IsPseudoField(newFldSeq->m_fieldHnd) &&
16211 comp->info.compCompHnd->isFieldStatic(newFldSeq->m_fieldHnd))
16213 // It is a static field. We're done.
16215 *pStatic = baseAddr;
16218 else if ((baseAddr != nullptr) && !mustBeStatic)
16220 // It's an instance field...but it must be for a struct field, since we've not yet encountered
16221 // a "TYP_REF" address. Analyze the reset of the address.
16222 return baseAddr->gtEffectiveVal()->IsFieldAddr(comp, pObj, pStatic, pFldSeq);
16229 bool Compiler::gtIsStaticFieldPtrToBoxedStruct(var_types fieldNodeType, CORINFO_FIELD_HANDLE fldHnd)
16231 if (fieldNodeType != TYP_REF)
16235 noway_assert(fldHnd != nullptr);
16236 CorInfoType cit = info.compCompHnd->getFieldType(fldHnd);
16237 var_types fieldTyp = JITtype2varType(cit);
16238 return fieldTyp != TYP_REF;
16241 #ifdef FEATURE_SIMD
16242 //------------------------------------------------------------------------
16243 // gtGetSIMDZero: Get a zero value of the appropriate SIMD type.
16246 // var_types - The simdType
16247 // baseType - The base type we need
16248 // simdHandle - The handle for the SIMD type
16251 // A node generating the appropriate Zero, if we are able to discern it,
16252 // otherwise null (note that this shouldn't happen, but callers should
16253 // be tolerant of this case).
16255 GenTree* Compiler::gtGetSIMDZero(var_types simdType, var_types baseType, CORINFO_CLASS_HANDLE simdHandle)
16257 bool found = false;
16258 bool isHWSIMD = true;
16259 noway_assert(m_simdHandleCache != nullptr);
16261 // First, determine whether this is Vector<T>.
16262 if (simdType == getSIMDVectorType())
16267 found = (simdHandle == m_simdHandleCache->SIMDFloatHandle);
16270 found = (simdHandle == m_simdHandleCache->SIMDDoubleHandle);
16273 found = (simdHandle == m_simdHandleCache->SIMDIntHandle);
16276 found = (simdHandle == m_simdHandleCache->SIMDUShortHandle);
16279 found = (simdHandle == m_simdHandleCache->SIMDUByteHandle);
16282 found = (simdHandle == m_simdHandleCache->SIMDShortHandle);
16285 found = (simdHandle == m_simdHandleCache->SIMDByteHandle);
16288 found = (simdHandle == m_simdHandleCache->SIMDLongHandle);
16291 found = (simdHandle == m_simdHandleCache->SIMDUIntHandle);
16294 found = (simdHandle == m_simdHandleCache->SIMDULongHandle);
16307 // We must still have isHWSIMD set to true, and the only non-HW types left are the fixed types.
16314 if (simdHandle == m_simdHandleCache->SIMDVector2Handle)
16318 #if defined(_TARGET_ARM64_) && defined(FEATURE_HW_INTRINSICS)
16321 assert(simdHandle == m_simdHandleCache->Vector64FloatHandle);
16325 assert(simdHandle == m_simdHandleCache->Vector64IntHandle);
16328 assert(simdHandle == m_simdHandleCache->Vector64UShortHandle);
16331 assert(simdHandle == m_simdHandleCache->Vector64UByteHandle);
16334 assert(simdHandle == m_simdHandleCache->Vector64ShortHandle);
16337 assert(simdHandle == m_simdHandleCache->Vector64ByteHandle);
16340 assert(simdHandle == m_simdHandleCache->Vector64UIntHandle);
16342 #endif // defined(_TARGET_ARM64_) && defined(FEATURE_HW_INTRINSICS)
16349 assert((baseType == TYP_FLOAT) && (simdHandle == m_simdHandleCache->SIMDVector3Handle));
16357 if (simdHandle == m_simdHandleCache->SIMDVector4Handle)
16361 #if defined(FEATURE_HW_INTRINSICS)
16364 assert(simdHandle == m_simdHandleCache->Vector128FloatHandle);
16368 assert(simdHandle == m_simdHandleCache->Vector128DoubleHandle);
16371 assert(simdHandle == m_simdHandleCache->Vector128IntHandle);
16374 assert(simdHandle == m_simdHandleCache->Vector128UShortHandle);
16377 assert(simdHandle == m_simdHandleCache->Vector128UByteHandle);
16380 assert(simdHandle == m_simdHandleCache->Vector128ShortHandle);
16383 assert(simdHandle == m_simdHandleCache->Vector128ByteHandle);
16386 assert(simdHandle == m_simdHandleCache->Vector128LongHandle);
16389 assert(simdHandle == m_simdHandleCache->Vector128UIntHandle);
16392 assert(simdHandle == m_simdHandleCache->Vector128ULongHandle);
16394 #endif // defined(FEATURE_HW_INTRINSICS)
16401 #if defined(_TARGET_XARCH4_) && defined(FEATURE_HW_INTRINSICS)
16406 assert(simdHandle == m_simdHandleCache->Vector256FloatHandle);
16409 assert(simdHandle == m_simdHandleCache->Vector256DoubleHandle);
16412 assert(simdHandle == m_simdHandleCache->Vector256IntHandle);
16415 assert(simdHandle == m_simdHandleCache->Vector256UShortHandle);
16418 assert(simdHandle == m_simdHandleCache->Vector256UByteHandle);
16421 assert(simdHandle == m_simdHandleCache->Vector256ShortHandle);
16424 assert(simdHandle == m_simdHandleCache->Vector256ByteHandle);
16427 assert(simdHandle == m_simdHandleCache->Vector256LongHandle);
16430 assert(simdHandle == m_simdHandleCache->Vector256UIntHandle);
16433 assert(simdHandle == m_simdHandleCache->Vector256ULongHandle);
16439 #endif // _TARGET_XARCH_ && FEATURE_HW_INTRINSICS
16445 unsigned size = genTypeSize(simdType);
16448 #if defined(_TARGET_XARCH_) && defined(FEATURE_HW_INTRINSICS)
16452 if (compSupports(InstructionSet_SSE))
16454 // We only return the HWIntrinsicNode if SSE is supported, since it is possible for
16455 // the user to disable the SSE HWIntrinsic support via the COMPlus configuration knobs
16456 // even though the hardware vector types are still available.
16457 return gtNewSimdHWIntrinsicNode(simdType, NI_Vector128_Zero, baseType, size);
16461 if (compSupports(InstructionSet_AVX))
16463 // We only return the HWIntrinsicNode if AVX is supported, since it is possible for
16464 // the user to disable the AVX HWIntrinsic support via the COMPlus configuration knobs
16465 // even though the hardware vector types are still available.
16466 return gtNewSimdHWIntrinsicNode(simdType, NI_Vector256_Zero, baseType, size);
16472 #endif // _TARGET_XARCH_ && FEATURE_HW_INTRINSICS
16473 JITDUMP("Coudn't find the matching SIMD type for %s<%s> in gtGetSIMDZero\n", varTypeName(simdType),
16474 varTypeName(baseType));
16478 return gtNewSIMDVectorZero(simdType, baseType, size);
16482 #endif // FEATURE_SIMD
16484 CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleIfPresent(GenTree* tree)
16486 CORINFO_CLASS_HANDLE structHnd = NO_CLASS_HANDLE;
16487 tree = tree->gtEffectiveVal();
16488 if (varTypeIsStruct(tree->gtType))
16490 switch (tree->gtOper)
16495 structHnd = impGetRefAnyClass();
16498 structHnd = tree->gtObj.gtClass;
16501 structHnd = tree->gtCall.gtRetClsHnd;
16504 structHnd = tree->gtRetExpr.gtRetClsHnd;
16507 structHnd = tree->gtArgPlace.gtArgPlaceClsHnd;
16510 structHnd = tree->gtIndex.gtStructElemClass;
16512 case GT_INDEX_ADDR:
16513 structHnd = tree->AsIndexAddr()->gtStructElemClass;
16516 info.compCompHnd->getFieldType(tree->gtField.gtFldHnd, &structHnd);
16519 structHnd = gtGetStructHandleIfPresent(tree->gtGetOp1());
16522 #ifdef FEATURE_SIMD
16523 if (varTypeIsSIMD(tree))
16525 structHnd = gtGetStructHandleForSIMD(tree->gtType, TYP_FLOAT);
16530 structHnd = lvaTable[tree->AsLclVarCommon()->gtLclNum].lvVerTypeInfo.GetClassHandle();
16533 structHnd = gtGetStructHandleIfPresent(tree->gtOp.gtOp1);
16536 #ifdef FEATURE_SIMD
16537 if (varTypeIsSIMD(tree))
16539 structHnd = gtGetStructHandleForSIMD(tree->gtType, TYP_FLOAT);
16540 #ifdef FEATURE_HW_INTRINSICS
16541 if (structHnd == NO_CLASS_HANDLE)
16543 structHnd = gtGetStructHandleForHWSIMD(tree->gtType, TYP_FLOAT);
16550 // Attempt to find a handle for this expression.
16551 // We can do this for an array element indirection, or for a field indirection.
16553 if (TryGetArrayInfo(tree->AsIndir(), &arrInfo))
16555 structHnd = EncodeElemType(arrInfo.m_elemType, arrInfo.m_elemStructType);
16559 GenTree* addr = tree->AsIndir()->Addr();
16560 if ((addr->OperGet() == GT_ADD) && addr->gtGetOp2()->OperIs(GT_CNS_INT))
16562 FieldSeqNode* fieldSeq = addr->gtGetOp2()->AsIntCon()->gtFieldSeq;
16564 if (fieldSeq != nullptr)
16566 while (fieldSeq->m_next != nullptr)
16568 fieldSeq = fieldSeq->m_next;
16570 if (fieldSeq != FieldSeqStore::NotAField() && !fieldSeq->IsPseudoField())
16572 CORINFO_FIELD_HANDLE fieldHnd = fieldSeq->m_fieldHnd;
16573 CorInfoType fieldCorType = info.compCompHnd->getFieldType(fieldHnd, &structHnd);
16574 assert(fieldCorType == CORINFO_TYPE_VALUECLASS);
16581 #ifdef FEATURE_SIMD
16583 structHnd = gtGetStructHandleForSIMD(tree->gtType, tree->AsSIMD()->gtSIMDBaseType);
16585 #endif // FEATURE_SIMD
16586 #ifdef FEATURE_HW_INTRINSICS
16587 case GT_HWIntrinsic:
16588 structHnd = gtGetStructHandleForHWSIMD(tree->gtType, tree->AsHWIntrinsic()->gtSIMDBaseType);
16597 CORINFO_CLASS_HANDLE Compiler::gtGetStructHandle(GenTree* tree)
16599 CORINFO_CLASS_HANDLE structHnd = gtGetStructHandleIfPresent(tree);
16600 assert(structHnd != NO_CLASS_HANDLE);
16604 //------------------------------------------------------------------------
16605 // gtGetClassHandle: find class handle for a ref type
16608 // tree -- tree to find handle for
16609 // pIsExact [out] -- whether handle is exact type
16610 // pIsNonNull [out] -- whether tree value is known not to be null
16613 // nullptr if class handle is unknown,
16614 // otherwise the class handle.
16615 // *pIsExact set true if tree type is known to be exactly the handle type,
16616 // otherwise actual type may be a subtype.
16617 // *pIsNonNull set true if tree value is known not to be null,
16618 // otherwise a null value is possible.
16620 CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, bool* pIsNonNull)
16622 // Set default values for our out params.
16623 *pIsNonNull = false;
16625 CORINFO_CLASS_HANDLE objClass = nullptr;
16627 // Bail out if we're just importing and not generating code, since
16628 // the jit uses TYP_REF for CORINFO_TYPE_VAR locals and args, but
16629 // these may not be ref types.
16630 if (compIsForImportOnly())
16635 // Bail out if the tree is not a ref type.
16636 var_types treeType = tree->TypeGet();
16637 if (treeType != TYP_REF)
16642 // Tunnel through commas.
16643 GenTree* obj = tree->gtEffectiveVal(false);
16644 const genTreeOps objOp = obj->OperGet();
16650 // gtEffectiveVal above means we shouldn't see commas here.
16651 assert(!"unexpected GT_COMMA");
16657 // For locals, pick up type info from the local table.
16658 const unsigned objLcl = obj->AsLclVar()->GetLclNum();
16660 objClass = lvaTable[objLcl].lvClassHnd;
16661 *pIsExact = lvaTable[objLcl].lvClassIsExact;
16667 // For fields, get the type from the field handle.
16668 CORINFO_FIELD_HANDLE fieldHnd = obj->gtField.gtFldHnd;
16670 if (fieldHnd != nullptr)
16672 objClass = gtGetFieldClassHandle(fieldHnd, pIsExact, pIsNonNull);
16680 // If we see a RET_EXPR, recurse through to examine the
16681 // return value expression.
16682 GenTree* retExpr = tree->gtRetExpr.gtInlineCandidate;
16683 objClass = gtGetClassHandle(retExpr, pIsExact, pIsNonNull);
16689 GenTreeCall* call = tree->AsCall();
16690 if (call->IsInlineCandidate())
16692 // For inline candidates, we've already cached the return
16693 // type class handle in the inline info.
16694 InlineCandidateInfo* inlInfo = call->gtInlineCandidateInfo;
16695 assert(inlInfo != nullptr);
16697 // Grab it as our first cut at a return type.
16698 assert(inlInfo->methInfo.args.retType == CORINFO_TYPE_CLASS);
16699 objClass = inlInfo->methInfo.args.retTypeClass;
16701 // If the method is shared, the above may not capture
16702 // the most precise return type information (that is,
16703 // it may represent a shared return type and as such,
16704 // have instances of __Canon). See if we can use the
16705 // context to get at something more definite.
16707 // For now, we do this here on demand rather than when
16708 // processing the call, but we could/should apply
16709 // similar sharpening to the argument and local types
16711 const unsigned retClassFlags = info.compCompHnd->getClassAttribs(objClass);
16712 if (retClassFlags & CORINFO_FLG_SHAREDINST)
16714 CORINFO_CONTEXT_HANDLE context = inlInfo->exactContextHnd;
16716 if (context != nullptr)
16718 CORINFO_CLASS_HANDLE exactClass = nullptr;
16720 if (((size_t)context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
16722 exactClass = (CORINFO_CLASS_HANDLE)((size_t)context & ~CORINFO_CONTEXTFLAGS_MASK);
16726 CORINFO_METHOD_HANDLE exactMethod =
16727 (CORINFO_METHOD_HANDLE)((size_t)context & ~CORINFO_CONTEXTFLAGS_MASK);
16728 exactClass = info.compCompHnd->getMethodClass(exactMethod);
16731 // Grab the signature in this context.
16732 CORINFO_SIG_INFO sig;
16733 eeGetMethodSig(call->gtCallMethHnd, &sig, exactClass);
16734 assert(sig.retType == CORINFO_TYPE_CLASS);
16735 objClass = sig.retTypeClass;
16739 else if (call->gtCallType == CT_USER_FUNC)
16741 // For user calls, we can fetch the approximate return
16742 // type info from the method handle. Unfortunately
16743 // we've lost the exact context, so this is the best
16744 // we can do for now.
16745 CORINFO_METHOD_HANDLE method = call->gtCallMethHnd;
16746 CORINFO_CLASS_HANDLE exactClass = nullptr;
16747 CORINFO_SIG_INFO sig;
16748 eeGetMethodSig(method, &sig, exactClass);
16749 if (sig.retType == CORINFO_TYPE_VOID)
16751 // This is a constructor call.
16752 const unsigned methodFlags = info.compCompHnd->getMethodAttribs(method);
16753 assert((methodFlags & CORINFO_FLG_CONSTRUCTOR) != 0);
16754 objClass = info.compCompHnd->getMethodClass(method);
16756 *pIsNonNull = true;
16760 assert(sig.retType == CORINFO_TYPE_CLASS);
16761 objClass = sig.retTypeClass;
16764 else if (call->gtCallType == CT_HELPER)
16766 objClass = gtGetHelperCallClassHandle(call, pIsExact, pIsNonNull);
16774 GenTreeIntrinsic* intrinsic = obj->AsIntrinsic();
16776 if (intrinsic->gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType)
16778 CORINFO_CLASS_HANDLE runtimeType = info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE);
16779 assert(runtimeType != NO_CLASS_HANDLE);
16781 objClass = runtimeType;
16783 *pIsNonNull = true;
16791 // For literal strings, we know the class and that the
16792 // value is not null.
16793 objClass = impGetStringClass();
16795 *pIsNonNull = true;
16801 GenTreeIndir* indir = obj->AsIndir();
16803 if (indir->HasBase() && !indir->HasIndex())
16805 // indir(addr(lcl)) --> lcl
16807 // This comes up during constrained callvirt on ref types.
16809 GenTree* base = indir->Base();
16810 GenTreeLclVarCommon* lcl = base->IsLocalAddrExpr();
16812 if ((lcl != nullptr) && (base->OperGet() != GT_ADD))
16814 const unsigned objLcl = lcl->GetLclNum();
16815 objClass = lvaTable[objLcl].lvClassHnd;
16816 *pIsExact = lvaTable[objLcl].lvClassIsExact;
16818 else if (base->OperGet() == GT_ARR_ELEM)
16820 // indir(arr_elem(...)) -> array element type
16822 GenTree* array = base->AsArrElem()->gtArrObj;
16824 objClass = gtGetArrayElementClassHandle(array);
16826 *pIsNonNull = false;
16828 else if (base->OperGet() == GT_ADD)
16830 // This could be a static field access.
16832 // See if op1 is a static field base helper call
16833 // and if so, op2 will have the field info.
16834 GenTree* op1 = base->gtOp.gtOp1;
16835 GenTree* op2 = base->gtOp.gtOp2;
16837 const bool op1IsStaticFieldBase = gtIsStaticGCBaseHelperCall(op1);
16839 if (op1IsStaticFieldBase && (op2->OperGet() == GT_CNS_INT))
16841 FieldSeqNode* fieldSeq = op2->AsIntCon()->gtFieldSeq;
16843 if (fieldSeq != nullptr)
16845 while (fieldSeq->m_next != nullptr)
16847 fieldSeq = fieldSeq->m_next;
16850 assert(!fieldSeq->IsPseudoField());
16852 // No benefit to calling gtGetFieldClassHandle here, as
16853 // the exact field being accessed can vary.
16854 CORINFO_FIELD_HANDLE fieldHnd = fieldSeq->m_fieldHnd;
16855 CORINFO_CLASS_HANDLE fieldClass = nullptr;
16856 CorInfoType fieldCorType = info.compCompHnd->getFieldType(fieldHnd, &fieldClass);
16858 assert(fieldCorType == CORINFO_TYPE_CLASS);
16859 objClass = fieldClass;
16870 // Box should just wrap a local var reference which has
16871 // the type we're looking for. Also box only represents a
16872 // non-nullable value type so result cannot be null.
16873 GenTreeBox* box = obj->AsBox();
16874 GenTree* boxTemp = box->BoxOp();
16875 assert(boxTemp->IsLocal());
16876 const unsigned boxTempLcl = boxTemp->AsLclVar()->GetLclNum();
16877 objClass = lvaTable[boxTempLcl].lvClassHnd;
16878 *pIsExact = lvaTable[boxTempLcl].lvClassIsExact;
16879 *pIsNonNull = true;
16885 GenTree* array = obj->AsIndex()->Arr();
16887 objClass = gtGetArrayElementClassHandle(array);
16889 *pIsNonNull = false;
16902 //------------------------------------------------------------------------
16903 // gtGetHelperCallClassHandle: find class handle for return value of a
16907 // call - helper call to examine
16908 // pIsExact - [OUT] true if type is known exactly
16909 // pIsNonNull - [OUT] true if return value is not null
16912 // nullptr if helper call result is not a ref class, or the class handle
16913 // is unknown, otherwise the class handle.
16915 CORINFO_CLASS_HANDLE Compiler::gtGetHelperCallClassHandle(GenTreeCall* call, bool* pIsExact, bool* pIsNonNull)
16917 assert(call->gtCallType == CT_HELPER);
16919 *pIsNonNull = false;
16921 CORINFO_CLASS_HANDLE objClass = nullptr;
16922 const CorInfoHelpFunc helper = eeGetHelperNum(call->gtCallMethHnd);
16926 case CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE:
16927 case CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL:
16929 // Note for some runtimes these helpers return exact types.
16931 // But in those cases the types are also sealed, so there's no
16932 // need to claim exactness here.
16933 const bool helperResultNonNull = (helper == CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE);
16934 CORINFO_CLASS_HANDLE runtimeType = info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE);
16936 assert(runtimeType != NO_CLASS_HANDLE);
16938 objClass = runtimeType;
16939 *pIsNonNull = helperResultNonNull;
16943 case CORINFO_HELP_CHKCASTCLASS:
16944 case CORINFO_HELP_CHKCASTANY:
16945 case CORINFO_HELP_CHKCASTARRAY:
16946 case CORINFO_HELP_CHKCASTINTERFACE:
16947 case CORINFO_HELP_CHKCASTCLASS_SPECIAL:
16948 case CORINFO_HELP_ISINSTANCEOFINTERFACE:
16949 case CORINFO_HELP_ISINSTANCEOFARRAY:
16950 case CORINFO_HELP_ISINSTANCEOFCLASS:
16951 case CORINFO_HELP_ISINSTANCEOFANY:
16953 // Fetch the class handle from the helper call arglist
16954 GenTreeArgList* args = call->gtCallArgs;
16955 GenTree* typeArg = args->Current();
16956 CORINFO_CLASS_HANDLE castHnd = gtGetHelperArgClassHandle(typeArg);
16958 // We generally assume the type being cast to is the best type
16959 // for the result, unless it is an interface type.
16961 // TODO-CQ: when we have default interface methods then
16962 // this might not be the best assumption. We could also
16963 // explore calling something like mergeClasses to identify
16964 // the more specific class. A similar issue arises when
16965 // typing the temp in impCastClassOrIsInstToTree, when we
16966 // expand the cast inline.
16967 if (castHnd != nullptr)
16969 DWORD attrs = info.compCompHnd->getClassAttribs(castHnd);
16971 if ((attrs & CORINFO_FLG_INTERFACE) != 0)
16977 // If we don't have a good estimate for the type we can use the
16978 // type from the value being cast instead.
16979 if (castHnd == nullptr)
16981 GenTree* valueArg = args->Rest()->Current();
16982 castHnd = gtGetClassHandle(valueArg, pIsExact, pIsNonNull);
16985 // We don't know at jit time if the cast will succeed or fail, but if it
16986 // fails at runtime then an exception is thrown for cast helpers, or the
16987 // result is set null for instance helpers.
16989 // So it safe to claim the result has the cast type.
16990 // Note we don't know for sure that it is exactly this type.
16991 if (castHnd != nullptr)
16993 objClass = castHnd;
17006 //------------------------------------------------------------------------
17007 // gtGetArrayElementClassHandle: find class handle for elements of an array
17011 // array -- array to find handle for
17014 // nullptr if element class handle is unknown, otherwise the class handle.
17016 CORINFO_CLASS_HANDLE Compiler::gtGetArrayElementClassHandle(GenTree* array)
17018 bool isArrayExact = false;
17019 bool isArrayNonNull = false;
17020 CORINFO_CLASS_HANDLE arrayClassHnd = gtGetClassHandle(array, &isArrayExact, &isArrayNonNull);
17022 if (arrayClassHnd != nullptr)
17024 // We know the class of the reference
17025 DWORD attribs = info.compCompHnd->getClassAttribs(arrayClassHnd);
17027 if ((attribs & CORINFO_FLG_ARRAY) != 0)
17029 // We know for sure it is an array
17030 CORINFO_CLASS_HANDLE elemClassHnd = nullptr;
17031 CorInfoType arrayElemType = info.compCompHnd->getChildType(arrayClassHnd, &elemClassHnd);
17033 if (arrayElemType == CORINFO_TYPE_CLASS)
17035 // We know it is an array of ref types
17036 return elemClassHnd;
17044 //------------------------------------------------------------------------
17045 // gtGetFieldClassHandle: find class handle for a field
17048 // fieldHnd - field handle for field in question
17049 // pIsExact - [OUT] true if type is known exactly
17050 // pIsNonNull - [OUT] true if field value is not null
17053 // nullptr if helper call result is not a ref class, or the class handle
17054 // is unknown, otherwise the class handle.
17056 // May examine runtime state of static field instances.
17058 CORINFO_CLASS_HANDLE Compiler::gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldHnd, bool* pIsExact, bool* pIsNonNull)
17060 CORINFO_CLASS_HANDLE fieldClass = nullptr;
17061 CorInfoType fieldCorType = info.compCompHnd->getFieldType(fieldHnd, &fieldClass);
17063 if (fieldCorType == CORINFO_TYPE_CLASS)
17065 // Optionally, look at the actual type of the field's value
17066 bool queryForCurrentClass = true;
17067 INDEBUG(queryForCurrentClass = (JitConfig.JitQueryCurrentStaticFieldClass() > 0););
17069 if (queryForCurrentClass)
17073 const char* fieldClassName = nullptr;
17074 const char* fieldName = eeGetFieldName(fieldHnd, &fieldClassName);
17075 JITDUMP("Querying runtime about current class of field %s.%s (declared as %s)\n", fieldClassName, fieldName,
17076 eeGetClassName(fieldClass));
17079 // Is this a fully initialized init-only static field?
17081 // Note we're not asking for speculative results here, yet.
17082 CORINFO_CLASS_HANDLE currentClass = info.compCompHnd->getStaticFieldCurrentClass(fieldHnd);
17084 if (currentClass != NO_CLASS_HANDLE)
17086 // Yes! We know the class exactly and can rely on this to always be true.
17087 fieldClass = currentClass;
17089 *pIsNonNull = true;
17090 JITDUMP("Runtime reports field is init-only and initialized and has class %s\n",
17091 eeGetClassName(fieldClass));
17095 JITDUMP("Field's current class not available\n");
17103 //------------------------------------------------------------------------
17104 // gtIsGCStaticBaseHelperCall: true if tree is fetching the gc static base
17105 // for a subsequent static field access
17108 // tree - tree to consider
17111 // true if the tree is a suitable helper call
17114 // Excludes R2R helpers as they specify the target field in a way
17115 // that is opaque to the jit.
17117 bool Compiler::gtIsStaticGCBaseHelperCall(GenTree* tree)
17119 if (tree->OperGet() != GT_CALL)
17124 GenTreeCall* call = tree->AsCall();
17126 if (call->gtCallType != CT_HELPER)
17131 const CorInfoHelpFunc helper = eeGetHelperNum(call->gtCallMethHnd);
17135 // We are looking for a REF type so only need to check for the GC base helpers
17136 case CORINFO_HELP_GETGENERICS_GCSTATIC_BASE:
17137 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE:
17138 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR:
17139 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS:
17140 case CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE:
17141 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE:
17142 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR:
17143 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS:
17152 void GenTree::ParseArrayAddress(
17153 Compiler* comp, ArrayInfo* arrayInfo, GenTree** pArr, ValueNum* pInxVN, FieldSeqNode** pFldSeq)
17156 ValueNum inxVN = ValueNumStore::NoVN;
17157 target_ssize_t offset = 0;
17158 FieldSeqNode* fldSeq = nullptr;
17160 ParseArrayAddressWork(comp, 1, pArr, &inxVN, &offset, &fldSeq);
17162 // If we didn't find an array reference (perhaps it is the constant null?) we will give up.
17163 if (*pArr == nullptr)
17168 // OK, new we have to figure out if any part of the "offset" is a constant contribution to the index.
17169 // First, sum the offsets of any fields in fldSeq.
17170 unsigned fieldOffsets = 0;
17171 FieldSeqNode* fldSeqIter = fldSeq;
17172 // Also, find the first non-pseudo field...
17173 assert(*pFldSeq == nullptr);
17174 while (fldSeqIter != nullptr)
17176 if (fldSeqIter == FieldSeqStore::NotAField())
17178 // TODO-Review: A NotAField here indicates a failure to properly maintain the field sequence
17179 // See test case self_host_tests_x86\jit\regression\CLR-x86-JIT\v1-m12-beta2\ b70992\ b70992.exe
17180 // Safest thing to do here is to drop back to MinOpts
17181 CLANG_FORMAT_COMMENT_ANCHOR;
17184 if (comp->opts.optRepeat)
17186 // We don't guarantee preserving these annotations through the entire optimizer, so
17187 // just conservatively return null if under optRepeat.
17192 noway_assert(!"fldSeqIter is NotAField() in ParseArrayAddress");
17195 if (!FieldSeqStore::IsPseudoField(fldSeqIter->m_fieldHnd))
17197 if (*pFldSeq == nullptr)
17199 *pFldSeq = fldSeqIter;
17201 CORINFO_CLASS_HANDLE fldCls = nullptr;
17202 noway_assert(fldSeqIter->m_fieldHnd != nullptr);
17203 CorInfoType cit = comp->info.compCompHnd->getFieldType(fldSeqIter->m_fieldHnd, &fldCls);
17204 fieldOffsets += comp->compGetTypeSize(cit, fldCls);
17206 fldSeqIter = fldSeqIter->m_next;
17209 // Is there some portion of the "offset" beyond the first-elem offset and the struct field suffix we just computed?
17210 if (!FitsIn<target_ssize_t>(fieldOffsets + arrayInfo->m_elemOffset) ||
17211 !FitsIn<target_ssize_t>(arrayInfo->m_elemSize))
17213 // This seems unlikely, but no harm in being safe...
17214 *pInxVN = comp->GetValueNumStore()->VNForExpr(nullptr, TYP_INT);
17218 target_ssize_t offsetAccountedFor = static_cast<target_ssize_t>(fieldOffsets + arrayInfo->m_elemOffset);
17219 target_ssize_t elemSize = static_cast<target_ssize_t>(arrayInfo->m_elemSize);
17221 target_ssize_t constIndOffset = offset - offsetAccountedFor;
17222 // This should be divisible by the element size...
17223 assert((constIndOffset % elemSize) == 0);
17224 target_ssize_t constInd = constIndOffset / elemSize;
17226 ValueNumStore* vnStore = comp->GetValueNumStore();
17228 if (inxVN == ValueNumStore::NoVN)
17230 // Must be a constant index.
17231 *pInxVN = vnStore->VNForPtrSizeIntCon(constInd);
17236 // Perform ((inxVN / elemSizeVN) + vnForConstInd)
17239 // The value associated with the index value number (inxVN) is the offset into the array,
17240 // which has been scaled by element size. We need to recover the array index from that offset
17241 if (vnStore->IsVNConstant(inxVN))
17243 target_ssize_t index = vnStore->CoercedConstantValue<target_ssize_t>(inxVN);
17244 noway_assert(elemSize > 0 && ((index % elemSize) == 0));
17245 *pInxVN = vnStore->VNForPtrSizeIntCon((index / elemSize) + constInd);
17249 bool canFoldDiv = false;
17251 // If the index VN is a MUL by elemSize, see if we can eliminate it instead of adding
17252 // the division by elemSize.
17254 if (vnStore->GetVNFunc(inxVN, &funcApp) && funcApp.m_func == (VNFunc)GT_MUL)
17256 ValueNum vnForElemSize = vnStore->VNForLongCon(elemSize);
17258 // One of the multiply operand is elemSize, so the resulting
17259 // index VN should simply be the other operand.
17260 if (funcApp.m_args[1] == vnForElemSize)
17262 *pInxVN = funcApp.m_args[0];
17265 else if (funcApp.m_args[0] == vnForElemSize)
17267 *pInxVN = funcApp.m_args[1];
17272 // Perform ((inxVN / elemSizeVN) + vnForConstInd)
17275 ValueNum vnForElemSize = vnStore->VNForPtrSizeIntCon(elemSize);
17276 ValueNum vnForScaledInx =
17277 vnStore->VNForFunc(TYP_I_IMPL, GetVNFuncForOper(GT_DIV, VOK_Default), inxVN, vnForElemSize);
17278 *pInxVN = vnForScaledInx;
17283 ValueNum vnForConstInd = comp->GetValueNumStore()->VNForPtrSizeIntCon(constInd);
17284 VNFunc vnFunc = GetVNFuncForOper(GT_ADD, VOK_Default);
17286 *pInxVN = comp->GetValueNumStore()->VNForFunc(TYP_I_IMPL, vnFunc, *pInxVN, vnForConstInd);
17292 void GenTree::ParseArrayAddressWork(Compiler* comp,
17293 target_ssize_t inputMul,
17296 target_ssize_t* pOffset,
17297 FieldSeqNode** pFldSeq)
17299 if (TypeGet() == TYP_REF)
17301 // This must be the array pointer.
17303 assert(inputMul == 1); // Can't multiply the array pointer by anything.
17310 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, gtIntCon.gtFieldSeq);
17311 assert(!gtIntCon.ImmedValNeedsReloc(comp));
17312 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntCon::gtIconVal had target_ssize_t
17314 *pOffset += (inputMul * (target_ssize_t)(gtIntCon.gtIconVal));
17319 gtOp.gtOp1->ParseArrayAddressWork(comp, inputMul, pArr, pInxVN, pOffset, pFldSeq);
17320 if (OperGet() == GT_SUB)
17322 inputMul = -inputMul;
17324 gtOp.gtOp2->ParseArrayAddressWork(comp, inputMul, pArr, pInxVN, pOffset, pFldSeq);
17329 // If one op is a constant, continue parsing down.
17330 target_ssize_t subMul = 0;
17331 GenTree* nonConst = nullptr;
17332 if (gtOp.gtOp1->IsCnsIntOrI())
17334 // If the other arg is an int constant, and is a "not-a-field", choose
17335 // that as the multiplier, thus preserving constant index offsets...
17336 if (gtOp.gtOp2->OperGet() == GT_CNS_INT &&
17337 gtOp.gtOp2->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField())
17339 assert(!gtOp.gtOp2->gtIntCon.ImmedValNeedsReloc(comp));
17340 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntConCommon::gtIconVal had
17341 // target_ssize_t type.
17342 subMul = (target_ssize_t)gtOp.gtOp2->gtIntConCommon.IconValue();
17343 nonConst = gtOp.gtOp1;
17347 assert(!gtOp.gtOp1->gtIntCon.ImmedValNeedsReloc(comp));
17348 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntConCommon::gtIconVal had
17349 // target_ssize_t type.
17350 subMul = (target_ssize_t)gtOp.gtOp1->gtIntConCommon.IconValue();
17351 nonConst = gtOp.gtOp2;
17354 else if (gtOp.gtOp2->IsCnsIntOrI())
17356 assert(!gtOp.gtOp2->gtIntCon.ImmedValNeedsReloc(comp));
17357 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntConCommon::gtIconVal had
17358 // target_ssize_t type.
17359 subMul = (target_ssize_t)gtOp.gtOp2->gtIntConCommon.IconValue();
17360 nonConst = gtOp.gtOp1;
17362 if (nonConst != nullptr)
17364 nonConst->ParseArrayAddressWork(comp, inputMul * subMul, pArr, pInxVN, pOffset, pFldSeq);
17367 // Otherwise, exit the switch, treat as a contribution to the index.
17372 // If one op is a constant, continue parsing down.
17373 if (gtOp.gtOp2->IsCnsIntOrI())
17375 assert(!gtOp.gtOp2->gtIntCon.ImmedValNeedsReloc(comp));
17376 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntCon::gtIconVal had target_ssize_t
17378 target_ssize_t subMul = target_ssize_t{1} << (target_ssize_t)gtOp.gtOp2->gtIntConCommon.IconValue();
17379 gtOp.gtOp1->ParseArrayAddressWork(comp, inputMul * subMul, pArr, pInxVN, pOffset, pFldSeq);
17382 // Otherwise, exit the switch, treat as a contribution to the index.
17386 // We don't care about exceptions for this purpose.
17387 if ((gtOp.gtOp1->OperGet() == GT_ARR_BOUNDS_CHECK) || gtOp.gtOp1->IsNothingNode())
17389 gtOp.gtOp2->ParseArrayAddressWork(comp, inputMul, pArr, pInxVN, pOffset, pFldSeq);
17397 // If we didn't return above, must be a contribution to the non-constant part of the index VN.
17398 ValueNum vn = comp->GetValueNumStore()->VNLiberalNormalValue(gtVNPair);
17401 ValueNum mulVN = comp->GetValueNumStore()->VNForLongCon(inputMul);
17402 vn = comp->GetValueNumStore()->VNForFunc(TypeGet(), GetVNFuncForOper(GT_MUL, VOK_Default), mulVN, vn);
17404 if (*pInxVN == ValueNumStore::NoVN)
17411 comp->GetValueNumStore()->VNForFunc(TypeGet(), GetVNFuncForOper(GT_ADD, VOK_Default), *pInxVN, vn);
17416 bool GenTree::ParseArrayElemForm(Compiler* comp, ArrayInfo* arrayInfo, FieldSeqNode** pFldSeq)
17420 if (gtFlags & GTF_IND_ARR_INDEX)
17422 bool b = comp->GetArrayInfoMap()->Lookup(this, arrayInfo);
17428 GenTree* addr = AsIndir()->Addr();
17429 return addr->ParseArrayElemAddrForm(comp, arrayInfo, pFldSeq);
17437 bool GenTree::ParseArrayElemAddrForm(Compiler* comp, ArrayInfo* arrayInfo, FieldSeqNode** pFldSeq)
17443 GenTree* arrAddr = nullptr;
17444 GenTree* offset = nullptr;
17445 if (gtOp.gtOp1->TypeGet() == TYP_BYREF)
17447 arrAddr = gtOp.gtOp1;
17448 offset = gtOp.gtOp2;
17450 else if (gtOp.gtOp2->TypeGet() == TYP_BYREF)
17452 arrAddr = gtOp.gtOp2;
17453 offset = gtOp.gtOp1;
17459 if (!offset->ParseOffsetForm(comp, pFldSeq))
17463 return arrAddr->ParseArrayElemAddrForm(comp, arrayInfo, pFldSeq);
17468 GenTree* addrArg = gtOp.gtOp1;
17469 if (addrArg->OperGet() != GT_IND)
17475 // The "Addr" node might be annotated with a zero-offset field sequence.
17476 FieldSeqNode* zeroOffsetFldSeq = nullptr;
17477 if (comp->GetZeroOffsetFieldMap()->Lookup(this, &zeroOffsetFldSeq))
17479 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, zeroOffsetFldSeq);
17481 return addrArg->ParseArrayElemForm(comp, arrayInfo, pFldSeq);
17490 bool GenTree::ParseOffsetForm(Compiler* comp, FieldSeqNode** pFldSeq)
17496 GenTreeIntCon* icon = AsIntCon();
17497 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, icon->gtFieldSeq);
17502 if (!gtOp.gtOp1->ParseOffsetForm(comp, pFldSeq))
17506 return gtOp.gtOp2->ParseOffsetForm(comp, pFldSeq);
17513 void GenTree::LabelIndex(Compiler* comp, bool isConst)
17518 // If we got here, this is a contribution to the constant part of the index.
17521 gtIntCon.gtFieldSeq =
17522 comp->GetFieldSeqStore()->CreateSingleton(FieldSeqStore::ConstantIndexPseudoField);
17527 gtFlags |= GTF_VAR_ARR_INDEX;
17532 gtOp.gtOp1->LabelIndex(comp, isConst);
17533 gtOp.gtOp2->LabelIndex(comp, isConst);
17537 gtOp.gtOp1->LabelIndex(comp, isConst);
17540 case GT_ARR_LENGTH:
17541 gtFlags |= GTF_ARRLEN_ARR_IDX;
17545 // For all other operators, peel off one constant; and then label the other if it's also a constant.
17546 if (OperIsArithmetic() || OperIsCompare())
17548 if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
17550 gtOp.gtOp1->LabelIndex(comp, isConst);
17553 else if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
17555 gtOp.gtOp2->LabelIndex(comp, isConst);
17558 // Otherwise continue downward on both, labeling vars.
17559 gtOp.gtOp1->LabelIndex(comp, false);
17560 gtOp.gtOp2->LabelIndex(comp, false);
17566 // Note that the value of the below field doesn't matter; it exists only to provide a distinguished address.
17569 FieldSeqNode FieldSeqStore::s_notAField(nullptr, nullptr);
17571 // FieldSeqStore methods.
17572 FieldSeqStore::FieldSeqStore(CompAllocator alloc) : m_alloc(alloc), m_canonMap(new (alloc) FieldSeqNodeCanonMap(alloc))
17576 FieldSeqNode* FieldSeqStore::CreateSingleton(CORINFO_FIELD_HANDLE fieldHnd)
17578 FieldSeqNode fsn(fieldHnd, nullptr);
17579 FieldSeqNode* res = nullptr;
17580 if (m_canonMap->Lookup(fsn, &res))
17586 res = m_alloc.allocate<FieldSeqNode>(1);
17588 m_canonMap->Set(fsn, res);
17593 FieldSeqNode* FieldSeqStore::Append(FieldSeqNode* a, FieldSeqNode* b)
17599 else if (a == NotAField())
17601 return NotAField();
17603 else if (b == nullptr)
17607 else if (b == NotAField())
17609 return NotAField();
17610 // Extremely special case for ConstantIndex pseudo-fields -- appending consecutive such
17611 // together collapse to one.
17613 else if (a->m_next == nullptr && a->m_fieldHnd == ConstantIndexPseudoField &&
17614 b->m_fieldHnd == ConstantIndexPseudoField)
17620 FieldSeqNode* tmp = Append(a->m_next, b);
17621 FieldSeqNode fsn(a->m_fieldHnd, tmp);
17622 FieldSeqNode* res = nullptr;
17623 if (m_canonMap->Lookup(fsn, &res))
17629 res = m_alloc.allocate<FieldSeqNode>(1);
17631 m_canonMap->Set(fsn, res);
17638 int FieldSeqStore::FirstElemPseudoFieldStruct;
17639 int FieldSeqStore::ConstantIndexPseudoFieldStruct;
17641 CORINFO_FIELD_HANDLE FieldSeqStore::FirstElemPseudoField =
17642 (CORINFO_FIELD_HANDLE)&FieldSeqStore::FirstElemPseudoFieldStruct;
17643 CORINFO_FIELD_HANDLE FieldSeqStore::ConstantIndexPseudoField =
17644 (CORINFO_FIELD_HANDLE)&FieldSeqStore::ConstantIndexPseudoFieldStruct;
17646 bool FieldSeqNode::IsFirstElemFieldSeq()
17648 // this must be non-null per ISO C++
17649 return m_fieldHnd == FieldSeqStore::FirstElemPseudoField;
17652 bool FieldSeqNode::IsConstantIndexFieldSeq()
17654 // this must be non-null per ISO C++
17655 return m_fieldHnd == FieldSeqStore::ConstantIndexPseudoField;
17658 bool FieldSeqNode::IsPseudoField()
17660 if (this == nullptr)
17664 return m_fieldHnd == FieldSeqStore::FirstElemPseudoField || m_fieldHnd == FieldSeqStore::ConstantIndexPseudoField;
17667 #ifdef FEATURE_SIMD
17668 GenTreeSIMD* Compiler::gtNewSIMDNode(
17669 var_types type, GenTree* op1, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size)
17671 assert(op1 != nullptr);
17672 SetOpLclRelatedToSIMDIntrinsic(op1);
17674 return new (this, GT_SIMD) GenTreeSIMD(type, op1, simdIntrinsicID, baseType, size);
17677 GenTreeSIMD* Compiler::gtNewSIMDNode(
17678 var_types type, GenTree* op1, GenTree* op2, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size)
17680 assert(op1 != nullptr);
17681 SetOpLclRelatedToSIMDIntrinsic(op1);
17682 SetOpLclRelatedToSIMDIntrinsic(op2);
17684 return new (this, GT_SIMD) GenTreeSIMD(type, op1, op2, simdIntrinsicID, baseType, size);
17687 //-------------------------------------------------------------------
17688 // SetOpLclRelatedToSIMDIntrinsic: Determine if the tree has a local var that needs to be set
17689 // as used by a SIMD intrinsic, and if so, set that local var appropriately.
17692 // op - The tree, to be an operand of a new GT_SIMD node, to check.
17694 void Compiler::SetOpLclRelatedToSIMDIntrinsic(GenTree* op)
17698 if (op->OperIsLocal())
17700 setLclRelatedToSIMDIntrinsic(op);
17702 else if ((op->OperGet() == GT_OBJ) && (op->gtOp.gtOp1->OperGet() == GT_ADDR) &&
17703 op->gtOp.gtOp1->gtOp.gtOp1->OperIsLocal())
17705 setLclRelatedToSIMDIntrinsic(op->gtOp.gtOp1->gtOp.gtOp1);
17710 bool GenTree::isCommutativeSIMDIntrinsic()
17712 assert(gtOper == GT_SIMD);
17713 switch (AsSIMD()->gtSIMDIntrinsicID)
17715 case SIMDIntrinsicAdd:
17716 case SIMDIntrinsicBitwiseAnd:
17717 case SIMDIntrinsicBitwiseOr:
17718 case SIMDIntrinsicBitwiseXor:
17719 case SIMDIntrinsicEqual:
17720 case SIMDIntrinsicMax:
17721 case SIMDIntrinsicMin:
17722 case SIMDIntrinsicMul:
17723 case SIMDIntrinsicOpEquality:
17724 case SIMDIntrinsicOpInEquality:
17730 #endif // FEATURE_SIMD
17732 #ifdef FEATURE_HW_INTRINSICS
17733 bool GenTree::isCommutativeHWIntrinsic() const
17735 assert(gtOper == GT_HWIntrinsic);
17737 #ifdef _TARGET_XARCH_
17738 return HWIntrinsicInfo::IsCommutative(AsHWIntrinsic()->gtHWIntrinsicId);
17741 #endif // _TARGET_XARCH_
17744 bool GenTree::isContainableHWIntrinsic() const
17746 assert(gtOper == GT_HWIntrinsic);
17748 #ifdef _TARGET_XARCH_
17749 switch (AsHWIntrinsic()->gtHWIntrinsicId)
17751 case NI_SSE_LoadAlignedVector128:
17752 case NI_SSE_LoadScalarVector128:
17753 case NI_SSE_LoadVector128:
17754 case NI_SSE2_LoadAlignedVector128:
17755 case NI_SSE2_LoadScalarVector128:
17756 case NI_SSE2_LoadVector128:
17757 case NI_AVX_LoadAlignedVector256:
17758 case NI_AVX_LoadVector256:
17770 #endif // _TARGET_XARCH_
17773 bool GenTree::isRMWHWIntrinsic(Compiler* comp)
17775 assert(gtOper == GT_HWIntrinsic);
17776 assert(comp != nullptr);
17778 #ifdef _TARGET_XARCH_
17779 if (!comp->canUseVexEncoding())
17781 return HWIntrinsicInfo::HasRMWSemantics(AsHWIntrinsic()->gtHWIntrinsicId);
17784 switch (AsHWIntrinsic()->gtHWIntrinsicId)
17786 // TODO-XArch-Cleanup: Move this switch block to be table driven.
17788 case NI_SSE42_Crc32:
17789 case NI_SSE42_X64_Crc32:
17790 case NI_FMA_MultiplyAdd:
17791 case NI_FMA_MultiplyAddNegated:
17792 case NI_FMA_MultiplyAddNegatedScalar:
17793 case NI_FMA_MultiplyAddScalar:
17794 case NI_FMA_MultiplyAddSubtract:
17795 case NI_FMA_MultiplySubtract:
17796 case NI_FMA_MultiplySubtractAdd:
17797 case NI_FMA_MultiplySubtractNegated:
17798 case NI_FMA_MultiplySubtractNegatedScalar:
17799 case NI_FMA_MultiplySubtractScalar:
17811 #endif // _TARGET_XARCH_
17814 GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type,
17815 NamedIntrinsic hwIntrinsicID,
17816 var_types baseType,
17819 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, hwIntrinsicID, baseType, size);
17822 GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(
17823 var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned simdSize)
17825 SetOpLclRelatedToSIMDIntrinsic(op1);
17827 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, hwIntrinsicID, baseType, simdSize);
17830 GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(
17831 var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned simdSize)
17833 SetOpLclRelatedToSIMDIntrinsic(op1);
17834 SetOpLclRelatedToSIMDIntrinsic(op2);
17836 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, op2, hwIntrinsicID, baseType, simdSize);
17839 GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type,
17843 NamedIntrinsic hwIntrinsicID,
17844 var_types baseType,
17847 SetOpLclRelatedToSIMDIntrinsic(op1);
17848 SetOpLclRelatedToSIMDIntrinsic(op2);
17849 SetOpLclRelatedToSIMDIntrinsic(op3);
17851 return new (this, GT_HWIntrinsic)
17852 GenTreeHWIntrinsic(type, gtNewArgList(op1, op2, op3), hwIntrinsicID, baseType, size);
17855 GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type,
17860 NamedIntrinsic hwIntrinsicID,
17861 var_types baseType,
17864 SetOpLclRelatedToSIMDIntrinsic(op1);
17865 SetOpLclRelatedToSIMDIntrinsic(op2);
17866 SetOpLclRelatedToSIMDIntrinsic(op3);
17867 SetOpLclRelatedToSIMDIntrinsic(op4);
17869 return new (this, GT_HWIntrinsic)
17870 GenTreeHWIntrinsic(type, gtNewArgList(op1, op2, op3, op4), hwIntrinsicID, baseType, size);
17873 GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID)
17875 SetOpLclRelatedToSIMDIntrinsic(op1);
17877 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, hwIntrinsicID, TYP_UNKNOWN, 0);
17880 GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type,
17883 NamedIntrinsic hwIntrinsicID)
17885 SetOpLclRelatedToSIMDIntrinsic(op1);
17886 SetOpLclRelatedToSIMDIntrinsic(op2);
17888 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, op2, hwIntrinsicID, TYP_UNKNOWN, 0);
17891 GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(
17892 var_types type, GenTree* op1, GenTree* op2, GenTree* op3, NamedIntrinsic hwIntrinsicID)
17894 SetOpLclRelatedToSIMDIntrinsic(op1);
17895 SetOpLclRelatedToSIMDIntrinsic(op2);
17896 SetOpLclRelatedToSIMDIntrinsic(op3);
17898 return new (this, GT_HWIntrinsic)
17899 GenTreeHWIntrinsic(type, gtNewArgList(op1, op2, op3), hwIntrinsicID, TYP_UNKNOWN, 0);
17902 //---------------------------------------------------------------------------------------
17903 // gtNewMustThrowException:
17904 // create a throw node (calling into JIT helper) that must be thrown.
17905 // The result would be a comma node: COMMA(jithelperthrow(void), x) where x's type should be specified.
17908 // helper - JIT helper ID
17909 // type - return type of the node
17912 // pointer to the throw node
17914 GenTree* Compiler::gtNewMustThrowException(unsigned helper, var_types type, CORINFO_CLASS_HANDLE clsHnd)
17916 GenTreeCall* node = gtNewHelperCallNode(helper, TYP_VOID);
17917 node->gtCallMoreFlags |= GTF_CALL_M_DOES_NOT_RETURN;
17918 if (type != TYP_VOID)
17920 unsigned dummyTemp = lvaGrabTemp(true DEBUGARG("dummy temp of must thrown exception"));
17921 if (type == TYP_STRUCT)
17923 lvaSetStruct(dummyTemp, clsHnd, false);
17924 type = lvaTable[dummyTemp].lvType; // struct type is normalized
17928 lvaTable[dummyTemp].lvType = type;
17930 GenTree* dummyNode = gtNewLclvNode(dummyTemp, type);
17931 return gtNewOperNode(GT_COMMA, type, node, dummyNode);
17936 // Returns true for the HW Instrinsic instructions that have MemoryLoad semantics, false otherwise
17937 bool GenTreeHWIntrinsic::OperIsMemoryLoad()
17939 #ifdef _TARGET_XARCH_
17940 // Some xarch instructions have MemoryLoad sematics
17941 HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(gtHWIntrinsicId);
17942 if (category == HW_Category_MemoryLoad)
17946 else if (HWIntrinsicInfo::MaybeMemoryLoad(gtHWIntrinsicId))
17948 // Some intrinsics (without HW_Category_MemoryLoad) also have MemoryLoad semantics
17950 if (category == HW_Category_SIMDScalar)
17952 // Avx2.BroadcastScalarToVector128/256 have vector and pointer overloads both, e.g.,
17953 // Vector128<byte> BroadcastScalarToVector128(Vector128<byte> value)
17954 // Vector128<byte> BroadcastScalarToVector128(byte* source)
17955 // So, we need to check the argument's type is memory-reference or Vector128
17956 assert(HWIntrinsicInfo::lookupNumArgs(this) == 1);
17957 return (gtHWIntrinsicId == NI_AVX2_BroadcastScalarToVector128 ||
17958 gtHWIntrinsicId == NI_AVX2_BroadcastScalarToVector256) &&
17959 gtOp.gtOp1->TypeGet() != TYP_SIMD16;
17961 else if (category == HW_Category_IMM)
17963 // Do we have less than 3 operands?
17964 if (HWIntrinsicInfo::lookupNumArgs(this) < 3)
17968 else if (HWIntrinsicInfo::isAVX2GatherIntrinsic(gtHWIntrinsicId))
17974 #endif // _TARGET_XARCH_
17978 // Returns true for the HW Instrinsic instructions that have MemoryStore semantics, false otherwise
17979 bool GenTreeHWIntrinsic::OperIsMemoryStore()
17981 #ifdef _TARGET_XARCH_
17982 // Some xarch instructions have MemoryStore sematics
17983 HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(gtHWIntrinsicId);
17984 if (category == HW_Category_MemoryStore)
17988 else if (HWIntrinsicInfo::MaybeMemoryStore(gtHWIntrinsicId) &&
17989 (category == HW_Category_IMM || category == HW_Category_Scalar))
17991 // Some intrinsics (without HW_Category_MemoryStore) also have MemoryStore semantics
17993 // Bmi2/Bmi2.X64.MultiplyNoFlags may return the lower half result by a out argument
17994 // unsafe ulong MultiplyNoFlags(ulong left, ulong right, ulong* low)
17996 // So, the 3-argument form is MemoryStore
17997 if (HWIntrinsicInfo::lookupNumArgs(this) == 3)
17999 switch (gtHWIntrinsicId)
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);