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.
4
5/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7XX XX
8XX GenTree XX
9XX XX
10XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12*/
13
14#include "jitpch.h"
15#include "hwintrinsic.h"
16#include "simd.h"
17
18#ifdef _MSC_VER
19#pragma hdrstop
20#endif
21
22/*****************************************************************************/
23
24const unsigned short GenTree::gtOperKindTable[] = {
25#define GTNODE(en, st, cm, ok) ok + GTK_COMMUTE *cm,
26#include "gtlist.h"
27};
28
29/*****************************************************************************
30 *
31 * The types of different GenTree nodes
32 */
33
34#ifdef DEBUG
35
36#define INDENT_SIZE 3
37
38//--------------------------------------------
39//
40// IndentStack: This struct is used, along with its related enums and strings,
41// to control both the indendtation and the printing of arcs.
42//
43// Notes:
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.
48
49enum IndentChars
50{
51 ICVertical,
52 ICBottom,
53 ICTop,
54 ICMiddle,
55 ICDash,
56 ICEmbedded,
57 ICTerminal,
58 ICError,
59 IndentCharCount
60};
61
62// clang-format off
63// Sets of strings for different dumping options vert bot top mid dash embedded terminal error
64static const char* emptyIndents[IndentCharCount] = { " ", " ", " ", " ", " ", "{", "", "?" };
65static const char* asciiIndents[IndentCharCount] = { "|", "\\", "/", "+", "-", "{", "*", "?" };
66static const char* unicodeIndents[IndentCharCount] = { "\xe2\x94\x82", "\xe2\x94\x94", "\xe2\x94\x8c", "\xe2\x94\x9c", "\xe2\x94\x80", "{", "\xe2\x96\x8c", "?" };
67// clang-format on
68
69typedef ArrayStack<Compiler::IndentInfo> IndentInfoStack;
70struct IndentStack
71{
72 IndentInfoStack stack;
73 const char** indents;
74
75 // Constructor for IndentStack. Uses 'compiler' to determine the mode of printing.
76 IndentStack(Compiler* compiler) : stack(compiler->getAllocator(CMK_DebugOnly))
77 {
78 if (compiler->asciiTrees)
79 {
80 indents = asciiIndents;
81 }
82 else
83 {
84 indents = unicodeIndents;
85 }
86 }
87
88 // Return the depth of the current indentation.
89 unsigned Depth()
90 {
91 return stack.Height();
92 }
93
94 // Push a new indentation onto the stack, of the given type.
95 void Push(Compiler::IndentInfo info)
96 {
97 stack.Push(info);
98 }
99
100 // Pop the most recent indentation type off the stack.
101 Compiler::IndentInfo Pop()
102 {
103 return stack.Pop();
104 }
105
106 // Print the current indentation and arcs.
107 void print()
108 {
109 unsigned indentCount = Depth();
110 for (unsigned i = 0; i < indentCount; i++)
111 {
112 unsigned index = indentCount - 1 - i;
113 switch (stack.Index(index))
114 {
115 case Compiler::IndentInfo::IINone:
116 printf(" ");
117 break;
118 case Compiler::IndentInfo::IIEmbedded:
119 printf("%s ", indents[ICEmbedded]);
120 break;
121 case Compiler::IndentInfo::IIArc:
122 if (index == 0)
123 {
124 printf("%s%s%s", indents[ICMiddle], indents[ICDash], indents[ICDash]);
125 }
126 else
127 {
128 printf("%s ", indents[ICVertical]);
129 }
130 break;
131 case Compiler::IndentInfo::IIArcBottom:
132 printf("%s%s%s", indents[ICBottom], indents[ICDash], indents[ICDash]);
133 break;
134 case Compiler::IndentInfo::IIArcTop:
135 printf("%s%s%s", indents[ICTop], indents[ICDash], indents[ICDash]);
136 break;
137 case Compiler::IndentInfo::IIError:
138 printf("%s%s%s", indents[ICError], indents[ICDash], indents[ICDash]);
139 break;
140 default:
141 unreached();
142 }
143 }
144 printf("%s", indents[ICTerminal]);
145 }
146};
147
148//------------------------------------------------------------------------
149// printIndent: This is a static method which simply invokes the 'print'
150// method on its 'indentStack' argument.
151//
152// Arguments:
153// indentStack - specifies the information for the indentation & arcs to be printed
154//
155// Notes:
156// This method exists to localize the checking for the case where indentStack is null.
157
158static void printIndent(IndentStack* indentStack)
159{
160 if (indentStack == nullptr)
161 {
162 return;
163 }
164 indentStack->print();
165}
166
167#endif
168
169#if defined(DEBUG) || NODEBASH_STATS || MEASURE_NODE_SIZE || COUNT_AST_OPERS
170
171static const char* opNames[] = {
172#define GTNODE(en, st, cm, ok) #en,
173#include "gtlist.h"
174};
175
176const char* GenTree::OpName(genTreeOps op)
177{
178 assert((unsigned)op < _countof(opNames));
179
180 return opNames[op];
181}
182
183#endif
184
185#if MEASURE_NODE_SIZE && SMALL_TREE_NODES
186
187static const char* opStructNames[] = {
188#define GTNODE(en, st, cm, ok) #st,
189#include "gtlist.h"
190};
191
192const char* GenTree::OpStructName(genTreeOps op)
193{
194 assert((unsigned)op < _countof(opStructNames));
195
196 return opStructNames[op];
197}
198
199#endif
200
201/*****************************************************************************
202 *
203 * When 'SMALL_TREE_NODES' is enabled, we allocate tree nodes in 2 different
204 * sizes: 'TREE_NODE_SZ_SMALL' for most nodes and 'TREE_NODE_SZ_LARGE' for the
205 * few nodes (such as calls) that have more fields and take up a lot more space.
206 */
207
208#if SMALL_TREE_NODES
209
210/* GT_COUNT'th oper is overloaded as 'undefined oper', so allocate storage for GT_COUNT'th oper also */
211/* static */
212unsigned char GenTree::s_gtNodeSizes[GT_COUNT + 1];
213
214#if NODEBASH_STATS || MEASURE_NODE_SIZE || COUNT_AST_OPERS
215
216unsigned char GenTree::s_gtTrueSizes[GT_COUNT + 1]{
217#define GTNODE(en, st, cm, ok) sizeof(st),
218#include "gtlist.h"
219};
220
221#endif // NODEBASH_STATS || MEASURE_NODE_SIZE || COUNT_AST_OPERS
222
223#if COUNT_AST_OPERS
224LONG GenTree::s_gtNodeCounts[GT_COUNT + 1] = {0};
225#endif // COUNT_AST_OPERS
226
227/* static */
228void GenTree::InitNodeSize()
229{
230 /* Set all sizes to 'small' first */
231
232 for (unsigned op = 0; op <= GT_COUNT; op++)
233 {
234 GenTree::s_gtNodeSizes[op] = TREE_NODE_SZ_SMALL;
235 }
236
237 // Now set all of the appropriate entries to 'large'
238 CLANG_FORMAT_COMMENT_ANCHOR;
239
240// clang-format off
241#if defined(FEATURE_HFA) || defined(UNIX_AMD64_ABI)
242 // On ARM32, ARM64 and System V for struct returning
243 // there is code that does GT_ASG-tree.CopyObj call.
244 // CopyObj is a large node and the GT_ASG is small, which triggers an exception.
245 GenTree::s_gtNodeSizes[GT_ASG] = TREE_NODE_SZ_LARGE;
246 GenTree::s_gtNodeSizes[GT_RETURN] = TREE_NODE_SZ_LARGE;
247#endif // defined(FEATURE_HFA) || defined(UNIX_AMD64_ABI)
248
249 GenTree::s_gtNodeSizes[GT_CALL] = TREE_NODE_SZ_LARGE;
250 GenTree::s_gtNodeSizes[GT_CAST] = TREE_NODE_SZ_LARGE;
251 GenTree::s_gtNodeSizes[GT_FTN_ADDR] = TREE_NODE_SZ_LARGE;
252 GenTree::s_gtNodeSizes[GT_BOX] = TREE_NODE_SZ_LARGE;
253 GenTree::s_gtNodeSizes[GT_INDEX] = TREE_NODE_SZ_LARGE;
254 GenTree::s_gtNodeSizes[GT_INDEX_ADDR] = TREE_NODE_SZ_LARGE;
255 GenTree::s_gtNodeSizes[GT_ARR_BOUNDS_CHECK] = TREE_NODE_SZ_LARGE;
256#ifdef FEATURE_SIMD
257 GenTree::s_gtNodeSizes[GT_SIMD_CHK] = TREE_NODE_SZ_LARGE;
258#endif // FEATURE_SIMD
259#ifdef FEATURE_HW_INTRINSICS
260 GenTree::s_gtNodeSizes[GT_HW_INTRINSIC_CHK] = TREE_NODE_SZ_LARGE;
261#endif // FEATURE_HW_INTRINSICS
262
263 GenTree::s_gtNodeSizes[GT_ARR_ELEM] = TREE_NODE_SZ_LARGE;
264 GenTree::s_gtNodeSizes[GT_ARR_INDEX] = TREE_NODE_SZ_LARGE;
265 GenTree::s_gtNodeSizes[GT_ARR_OFFSET] = TREE_NODE_SZ_LARGE;
266 GenTree::s_gtNodeSizes[GT_RET_EXPR] = TREE_NODE_SZ_LARGE;
267 GenTree::s_gtNodeSizes[GT_OBJ] = TREE_NODE_SZ_LARGE;
268 GenTree::s_gtNodeSizes[GT_FIELD] = TREE_NODE_SZ_LARGE;
269 GenTree::s_gtNodeSizes[GT_STMT] = TREE_NODE_SZ_LARGE;
270 GenTree::s_gtNodeSizes[GT_CMPXCHG] = TREE_NODE_SZ_LARGE;
271 GenTree::s_gtNodeSizes[GT_QMARK] = TREE_NODE_SZ_LARGE;
272 GenTree::s_gtNodeSizes[GT_LEA] = TREE_NODE_SZ_LARGE;
273 GenTree::s_gtNodeSizes[GT_STORE_OBJ] = TREE_NODE_SZ_LARGE;
274 GenTree::s_gtNodeSizes[GT_DYN_BLK] = TREE_NODE_SZ_LARGE;
275 GenTree::s_gtNodeSizes[GT_STORE_DYN_BLK] = TREE_NODE_SZ_LARGE;
276 GenTree::s_gtNodeSizes[GT_INTRINSIC] = TREE_NODE_SZ_LARGE;
277 GenTree::s_gtNodeSizes[GT_ALLOCOBJ] = TREE_NODE_SZ_LARGE;
278#if USE_HELPERS_FOR_INT_DIV
279 GenTree::s_gtNodeSizes[GT_DIV] = TREE_NODE_SZ_LARGE;
280 GenTree::s_gtNodeSizes[GT_UDIV] = TREE_NODE_SZ_LARGE;
281 GenTree::s_gtNodeSizes[GT_MOD] = TREE_NODE_SZ_LARGE;
282 GenTree::s_gtNodeSizes[GT_UMOD] = TREE_NODE_SZ_LARGE;
283#endif
284#ifdef FEATURE_PUT_STRUCT_ARG_STK
285 // TODO-Throughput: This should not need to be a large node. The object info should be
286 // obtained from the child node.
287 GenTree::s_gtNodeSizes[GT_PUTARG_STK] = TREE_NODE_SZ_LARGE;
288#if FEATURE_ARG_SPLIT
289 GenTree::s_gtNodeSizes[GT_PUTARG_SPLIT] = TREE_NODE_SZ_LARGE;
290#endif // FEATURE_ARG_SPLIT
291#endif // FEATURE_PUT_STRUCT_ARG_STK
292
293 assert(GenTree::s_gtNodeSizes[GT_RETURN] == GenTree::s_gtNodeSizes[GT_ASG]);
294
295 // This list of assertions should come to contain all GenTree subtypes that are declared
296 // "small".
297 assert(sizeof(GenTreeLclFld) <= GenTree::s_gtNodeSizes[GT_LCL_FLD]);
298 assert(sizeof(GenTreeLclVar) <= GenTree::s_gtNodeSizes[GT_LCL_VAR]);
299
300 static_assert_no_msg(sizeof(GenTree) <= TREE_NODE_SZ_SMALL);
301 static_assert_no_msg(sizeof(GenTreeUnOp) <= TREE_NODE_SZ_SMALL);
302 static_assert_no_msg(sizeof(GenTreeOp) <= TREE_NODE_SZ_SMALL);
303 static_assert_no_msg(sizeof(GenTreeVal) <= TREE_NODE_SZ_SMALL);
304 static_assert_no_msg(sizeof(GenTreeIntConCommon) <= TREE_NODE_SZ_SMALL);
305 static_assert_no_msg(sizeof(GenTreePhysReg) <= TREE_NODE_SZ_SMALL);
306 static_assert_no_msg(sizeof(GenTreeJumpTable) <= TREE_NODE_SZ_SMALL);
307 static_assert_no_msg(sizeof(GenTreeIntCon) <= TREE_NODE_SZ_SMALL);
308 static_assert_no_msg(sizeof(GenTreeLngCon) <= TREE_NODE_SZ_SMALL);
309 static_assert_no_msg(sizeof(GenTreeDblCon) <= TREE_NODE_SZ_SMALL);
310 static_assert_no_msg(sizeof(GenTreeStrCon) <= TREE_NODE_SZ_SMALL);
311 static_assert_no_msg(sizeof(GenTreeLclVarCommon) <= TREE_NODE_SZ_SMALL);
312 static_assert_no_msg(sizeof(GenTreeLclVar) <= TREE_NODE_SZ_SMALL);
313 static_assert_no_msg(sizeof(GenTreeLclFld) <= TREE_NODE_SZ_SMALL);
314 static_assert_no_msg(sizeof(GenTreeCC) <= TREE_NODE_SZ_SMALL);
315 static_assert_no_msg(sizeof(GenTreeCast) <= TREE_NODE_SZ_LARGE); // *** large node
316 static_assert_no_msg(sizeof(GenTreeBox) <= TREE_NODE_SZ_LARGE); // *** large node
317 static_assert_no_msg(sizeof(GenTreeField) <= TREE_NODE_SZ_LARGE); // *** large node
318 static_assert_no_msg(sizeof(GenTreeArgList) <= TREE_NODE_SZ_SMALL);
319 static_assert_no_msg(sizeof(GenTreeFieldList) <= TREE_NODE_SZ_SMALL);
320 static_assert_no_msg(sizeof(GenTreeColon) <= TREE_NODE_SZ_SMALL);
321 static_assert_no_msg(sizeof(GenTreeCall) <= TREE_NODE_SZ_LARGE); // *** large node
322 static_assert_no_msg(sizeof(GenTreeCmpXchg) <= TREE_NODE_SZ_LARGE); // *** large node
323 static_assert_no_msg(sizeof(GenTreeFptrVal) <= TREE_NODE_SZ_LARGE); // *** large node
324 static_assert_no_msg(sizeof(GenTreeQmark) <= TREE_NODE_SZ_LARGE); // *** large node
325 static_assert_no_msg(sizeof(GenTreeIntrinsic) <= TREE_NODE_SZ_LARGE); // *** large node
326 static_assert_no_msg(sizeof(GenTreeIndex) <= TREE_NODE_SZ_LARGE); // *** large node
327 static_assert_no_msg(sizeof(GenTreeArrLen) <= TREE_NODE_SZ_LARGE); // *** large node
328 static_assert_no_msg(sizeof(GenTreeBoundsChk) <= TREE_NODE_SZ_LARGE); // *** large node
329 static_assert_no_msg(sizeof(GenTreeArrElem) <= TREE_NODE_SZ_LARGE); // *** large node
330 static_assert_no_msg(sizeof(GenTreeArrIndex) <= TREE_NODE_SZ_LARGE); // *** large node
331 static_assert_no_msg(sizeof(GenTreeArrOffs) <= TREE_NODE_SZ_LARGE); // *** large node
332 static_assert_no_msg(sizeof(GenTreeIndir) <= TREE_NODE_SZ_SMALL);
333 static_assert_no_msg(sizeof(GenTreeStoreInd) <= TREE_NODE_SZ_SMALL);
334 static_assert_no_msg(sizeof(GenTreeAddrMode) <= TREE_NODE_SZ_SMALL);
335 static_assert_no_msg(sizeof(GenTreeObj) <= TREE_NODE_SZ_LARGE); // *** large node
336 static_assert_no_msg(sizeof(GenTreeBlk) <= TREE_NODE_SZ_SMALL);
337 static_assert_no_msg(sizeof(GenTreeRetExpr) <= TREE_NODE_SZ_LARGE); // *** large node
338 static_assert_no_msg(sizeof(GenTreeStmt) <= TREE_NODE_SZ_LARGE); // *** large node
339 static_assert_no_msg(sizeof(GenTreeClsVar) <= TREE_NODE_SZ_SMALL);
340 static_assert_no_msg(sizeof(GenTreeArgPlace) <= TREE_NODE_SZ_SMALL);
341 static_assert_no_msg(sizeof(GenTreeLabel) <= TREE_NODE_SZ_SMALL);
342 static_assert_no_msg(sizeof(GenTreePhiArg) <= TREE_NODE_SZ_SMALL);
343 static_assert_no_msg(sizeof(GenTreeAllocObj) <= TREE_NODE_SZ_LARGE); // *** large node
344#ifndef FEATURE_PUT_STRUCT_ARG_STK
345 static_assert_no_msg(sizeof(GenTreePutArgStk) <= TREE_NODE_SZ_SMALL);
346#else // FEATURE_PUT_STRUCT_ARG_STK
347 // TODO-Throughput: This should not need to be a large node. The object info should be
348 // obtained from the child node.
349 static_assert_no_msg(sizeof(GenTreePutArgStk) <= TREE_NODE_SZ_LARGE);
350#if FEATURE_ARG_SPLIT
351 static_assert_no_msg(sizeof(GenTreePutArgSplit) <= TREE_NODE_SZ_LARGE);
352#endif // FEATURE_ARG_SPLIT
353#endif // FEATURE_PUT_STRUCT_ARG_STK
354
355#ifdef FEATURE_SIMD
356 static_assert_no_msg(sizeof(GenTreeSIMD) <= TREE_NODE_SZ_SMALL);
357#endif // FEATURE_SIMD
358
359#ifdef FEATURE_HW_INTRINSICS
360 static_assert_no_msg(sizeof(GenTreeHWIntrinsic) <= TREE_NODE_SZ_SMALL);
361#endif // FEATURE_HW_INTRINSICS
362 // clang-format on
363}
364
365size_t GenTree::GetNodeSize() const
366{
367 return GenTree::s_gtNodeSizes[gtOper];
368}
369
370#ifdef DEBUG
371bool GenTree::IsNodeProperlySized() const
372{
373 size_t size;
374
375 if (gtDebugFlags & GTF_DEBUG_NODE_SMALL)
376 {
377 size = TREE_NODE_SZ_SMALL;
378 }
379 else
380 {
381 assert(gtDebugFlags & GTF_DEBUG_NODE_LARGE);
382 size = TREE_NODE_SZ_LARGE;
383 }
384
385 return GenTree::s_gtNodeSizes[gtOper] <= size;
386}
387#endif
388
389#if SMALL_TREE_NODES
390//------------------------------------------------------------------------
391// ReplaceWith: replace this with the src node. The source must be an isolated node
392// and cannot be used after the replacement.
393//
394// Arguments:
395// src - source tree, that replaces this.
396// comp - the compiler instance to transfer annotations for arrays.
397//
398void GenTree::ReplaceWith(GenTree* src, Compiler* comp)
399{
400 // The source may be big only if the target is also a big node
401 assert((gtDebugFlags & GTF_DEBUG_NODE_LARGE) || GenTree::s_gtNodeSizes[src->gtOper] == TREE_NODE_SZ_SMALL);
402
403 // The check is effective only if nodes have been already threaded.
404 assert((src->gtPrev == nullptr) && (src->gtNext == nullptr));
405
406 RecordOperBashing(OperGet(), src->OperGet()); // nop unless NODEBASH_STATS is enabled
407
408 GenTree* prev = gtPrev;
409 GenTree* next = gtNext;
410 // The VTable pointer is copied intentionally here
411 memcpy((void*)this, (void*)src, src->GetNodeSize());
412 this->gtPrev = prev;
413 this->gtNext = next;
414
415#ifdef DEBUG
416 gtSeqNum = 0;
417#endif
418 // Transfer any annotations.
419 if (src->OperGet() == GT_IND && src->gtFlags & GTF_IND_ARR_INDEX)
420 {
421 ArrayInfo arrInfo;
422 bool b = comp->GetArrayInfoMap()->Lookup(src, &arrInfo);
423 assert(b);
424 comp->GetArrayInfoMap()->Set(this, arrInfo);
425 }
426 DEBUG_DESTROY_NODE(src);
427}
428
429#endif
430
431/*****************************************************************************
432 *
433 * When 'NODEBASH_STATS' is enabled in "jit.h" we record all instances of
434 * an existing GenTree node having its operator changed. This can be useful
435 * for two (related) things - to see what is being bashed (and what isn't),
436 * and to verify that the existing choices for what nodes are marked 'large'
437 * are reasonable (to minimize "wasted" space).
438 *
439 * And yes, the hash function / logic is simplistic, but it is conflict-free
440 * and transparent for what we need.
441 */
442
443#if NODEBASH_STATS
444
445#define BASH_HASH_SIZE 211
446
447inline unsigned hashme(genTreeOps op1, genTreeOps op2)
448{
449 return ((op1 * 104729) ^ (op2 * 56569)) % BASH_HASH_SIZE;
450}
451
452struct BashHashDsc
453{
454 unsigned __int32 bhFullHash; // the hash value (unique for all old->new pairs)
455 unsigned __int32 bhCount; // the same old->new bashings seen so far
456 unsigned __int8 bhOperOld; // original gtOper
457 unsigned __int8 bhOperNew; // new gtOper
458};
459
460static BashHashDsc BashHash[BASH_HASH_SIZE];
461
462void GenTree::RecordOperBashing(genTreeOps operOld, genTreeOps operNew)
463{
464 unsigned hash = hashme(operOld, operNew);
465 BashHashDsc* desc = BashHash + hash;
466
467 if (desc->bhFullHash != hash)
468 {
469 noway_assert(desc->bhCount == 0); // if this ever fires, need fix the hash fn
470 desc->bhFullHash = hash;
471 }
472
473 desc->bhCount += 1;
474 desc->bhOperOld = operOld;
475 desc->bhOperNew = operNew;
476}
477
478void GenTree::ReportOperBashing(FILE* f)
479{
480 unsigned total = 0;
481
482 fflush(f);
483
484 fprintf(f, "\n");
485 fprintf(f, "Bashed gtOper stats:\n");
486 fprintf(f, "\n");
487 fprintf(f, " Old operator New operator #bytes old->new Count\n");
488 fprintf(f, " ---------------------------------------------------------------\n");
489
490 for (unsigned h = 0; h < BASH_HASH_SIZE; h++)
491 {
492 unsigned count = BashHash[h].bhCount;
493 if (count == 0)
494 continue;
495
496 unsigned opOld = BashHash[h].bhOperOld;
497 unsigned opNew = BashHash[h].bhOperNew;
498
499 fprintf(f, " GT_%-13s -> GT_%-13s [size: %3u->%3u] %c %7u\n", OpName((genTreeOps)opOld),
500 OpName((genTreeOps)opNew), s_gtTrueSizes[opOld], s_gtTrueSizes[opNew],
501 (s_gtTrueSizes[opOld] < s_gtTrueSizes[opNew]) ? 'X' : ' ', count);
502 total += count;
503 }
504 fprintf(f, "\n");
505 fprintf(f, "Total bashings: %u\n", total);
506 fprintf(f, "\n");
507
508 fflush(f);
509}
510
511#endif // NODEBASH_STATS
512
513#else // SMALL_TREE_NODES
514
515#ifdef DEBUG
516bool GenTree::IsNodeProperlySized() const
517{
518 return true;
519}
520#endif
521
522#endif // SMALL_TREE_NODES
523
524/*****************************************************************************/
525
526#if MEASURE_NODE_SIZE
527
528void GenTree::DumpNodeSizes(FILE* fp)
529{
530// Dump the sizes of the various GenTree flavors
531
532#if SMALL_TREE_NODES
533 fprintf(fp, "Small tree node size = %3u bytes\n", TREE_NODE_SZ_SMALL);
534#endif
535 fprintf(fp, "Large tree node size = %3u bytes\n", TREE_NODE_SZ_LARGE);
536 fprintf(fp, "\n");
537
538#if SMALL_TREE_NODES
539
540 // Verify that node sizes are set kosherly and dump sizes
541 for (unsigned op = GT_NONE + 1; op < GT_COUNT; op++)
542 {
543 unsigned needSize = s_gtTrueSizes[op];
544 unsigned nodeSize = s_gtNodeSizes[op];
545
546 const char* structNm = OpStructName((genTreeOps)op);
547 const char* operName = OpName((genTreeOps)op);
548
549 bool repeated = false;
550
551 // Have we seen this struct flavor before?
552 for (unsigned mop = GT_NONE + 1; mop < op; mop++)
553 {
554 if (strcmp(structNm, OpStructName((genTreeOps)mop)) == 0)
555 {
556 repeated = true;
557 break;
558 }
559 }
560
561 // Don't repeat the same GenTree flavor unless we have an error
562 if (!repeated || needSize > nodeSize)
563 {
564 unsigned sizeChar = '?';
565
566 if (nodeSize == TREE_NODE_SZ_SMALL)
567 sizeChar = 'S';
568 else if (nodeSize == TREE_NODE_SZ_LARGE)
569 sizeChar = 'L';
570
571 fprintf(fp, "GT_%-16s ... %-19s = %3u bytes (%c)", operName, structNm, needSize, sizeChar);
572 if (needSize > nodeSize)
573 {
574 fprintf(fp, " -- ERROR -- allocation is only %u bytes!", nodeSize);
575 }
576 else if (needSize <= TREE_NODE_SZ_SMALL && nodeSize == TREE_NODE_SZ_LARGE)
577 {
578 fprintf(fp, " ... could be small");
579 }
580
581 fprintf(fp, "\n");
582 }
583 }
584
585#endif
586}
587
588#endif // MEASURE_NODE_SIZE
589
590/*****************************************************************************
591 *
592 * Walk all basic blocks and call the given function pointer for all tree
593 * nodes contained therein.
594 */
595
596void Compiler::fgWalkAllTreesPre(fgWalkPreFn* visitor, void* pCallBackData)
597{
598 BasicBlock* block;
599
600 for (block = fgFirstBB; block; block = block->bbNext)
601 {
602 GenTree* tree;
603
604 for (tree = block->bbTreeList; tree; tree = tree->gtNext)
605 {
606 assert(tree->gtOper == GT_STMT);
607
608 fgWalkTreePre(&tree->gtStmt.gtStmtExpr, visitor, pCallBackData);
609 }
610 }
611}
612
613//-----------------------------------------------------------
614// CopyReg: Copy the _gtRegNum/gtRegTag fields.
615//
616// Arguments:
617// from - GenTree node from which to copy
618//
619// Return Value:
620// None
621void GenTree::CopyReg(GenTree* from)
622{
623 _gtRegNum = from->_gtRegNum;
624 INDEBUG(gtRegTag = from->gtRegTag;)
625
626 // Also copy multi-reg state if this is a call node
627 if (IsCall())
628 {
629 assert(from->IsCall());
630 this->AsCall()->CopyOtherRegs(from->AsCall());
631 }
632 else if (IsCopyOrReload())
633 {
634 this->AsCopyOrReload()->CopyOtherRegs(from->AsCopyOrReload());
635 }
636}
637
638//------------------------------------------------------------------
639// gtHasReg: Whether node beeen assigned a register by LSRA
640//
641// Arguments:
642// None
643//
644// Return Value:
645// Returns true if the node was assigned a register.
646//
647// In case of multi-reg call nodes, it is considered
648// having a reg if regs are allocated for all its
649// return values.
650//
651// In case of GT_COPY or GT_RELOAD of a multi-reg call,
652// GT_COPY/GT_RELOAD is considered having a reg if it
653// has a reg assigned to any of its positions.
654//
655// Assumption:
656// In order for this to work properly, gtClearReg must be called
657// prior to setting the register value.
658//
659bool GenTree::gtHasReg() const
660{
661 bool hasReg;
662
663 if (IsMultiRegCall())
664 {
665 // Have to cast away const-ness because GetReturnTypeDesc() is a non-const method
666 GenTree* tree = const_cast<GenTree*>(this);
667 GenTreeCall* call = tree->AsCall();
668 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
669 hasReg = false;
670
671 // A Multi-reg call node is said to have regs, if it has
672 // reg assigned to each of its result registers.
673 for (unsigned i = 0; i < regCount; ++i)
674 {
675 hasReg = (call->GetRegNumByIdx(i) != REG_NA);
676 if (!hasReg)
677 {
678 break;
679 }
680 }
681 }
682 else if (IsCopyOrReloadOfMultiRegCall())
683 {
684 GenTree* tree = const_cast<GenTree*>(this);
685 GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
686 GenTreeCall* call = copyOrReload->gtGetOp1()->AsCall();
687 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
688 hasReg = false;
689
690 // A Multi-reg copy or reload node is said to have regs,
691 // if it has valid regs in any of the positions.
692 for (unsigned i = 0; i < regCount; ++i)
693 {
694 hasReg = (copyOrReload->GetRegNumByIdx(i) != REG_NA);
695 if (hasReg)
696 {
697 break;
698 }
699 }
700 }
701 else
702 {
703 hasReg = (gtRegNum != REG_NA);
704 }
705
706 return hasReg;
707}
708
709//-----------------------------------------------------------------------------
710// GetRegisterDstCount: Get the number of registers defined by the node.
711//
712// Arguments:
713// None
714//
715// Return Value:
716// The number of registers that this node defines.
717//
718// Notes:
719// This should not be called on a contained node.
720// This does not look at the actual register assignments, if any, and so
721// is valid after Lowering.
722//
723int GenTree::GetRegisterDstCount() const
724{
725 assert(!isContained());
726 if (!IsMultiRegNode())
727 {
728 return (IsValue()) ? 1 : 0;
729 }
730 else if (IsMultiRegCall())
731 {
732 // temporarily cast away const-ness as AsCall() method is not declared const
733 GenTree* temp = const_cast<GenTree*>(this);
734 return temp->AsCall()->GetReturnTypeDesc()->GetReturnRegCount();
735 }
736 else if (IsCopyOrReload())
737 {
738 return gtGetOp1()->GetRegisterDstCount();
739 }
740#if FEATURE_ARG_SPLIT
741 else if (OperIsPutArgSplit())
742 {
743 return (const_cast<GenTree*>(this))->AsPutArgSplit()->gtNumRegs;
744 }
745#endif
746#if !defined(_TARGET_64BIT_)
747 else if (OperIsMultiRegOp())
748 {
749 // A MultiRegOp is a GT_MUL_LONG, GT_PUTARG_REG, or GT_BITCAST.
750 // For the latter two (ARM-only), they only have multiple registers if they produce a long value
751 // (GT_MUL_LONG always produces a long value).
752 CLANG_FORMAT_COMMENT_ANCHOR;
753#ifdef _TARGET_ARM_
754 return (TypeGet() == TYP_LONG) ? 2 : 1;
755#else
756 assert(OperIs(GT_MUL_LONG));
757 return 2;
758#endif
759 }
760#endif
761 assert(!"Unexpected multi-reg node");
762 return 0;
763}
764
765//---------------------------------------------------------------
766// gtGetRegMask: Get the reg mask of the node.
767//
768// Arguments:
769// None
770//
771// Return Value:
772// Reg Mask of GenTree node.
773//
774regMaskTP GenTree::gtGetRegMask() const
775{
776 regMaskTP resultMask;
777
778 if (IsMultiRegCall())
779 {
780 // temporarily cast away const-ness as AsCall() method is not declared const
781 resultMask = genRegMask(gtRegNum);
782 GenTree* temp = const_cast<GenTree*>(this);
783 resultMask |= temp->AsCall()->GetOtherRegMask();
784 }
785 else if (IsCopyOrReloadOfMultiRegCall())
786 {
787 // A multi-reg copy or reload, will have valid regs for only those
788 // positions that need to be copied or reloaded. Hence we need
789 // to consider only those registers for computing reg mask.
790
791 GenTree* tree = const_cast<GenTree*>(this);
792 GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
793 GenTreeCall* call = copyOrReload->gtGetOp1()->AsCall();
794 unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount();
795
796 resultMask = RBM_NONE;
797 for (unsigned i = 0; i < regCount; ++i)
798 {
799 regNumber reg = copyOrReload->GetRegNumByIdx(i);
800 if (reg != REG_NA)
801 {
802 resultMask |= genRegMask(reg);
803 }
804 }
805 }
806#if FEATURE_ARG_SPLIT
807 else if (OperIsPutArgSplit())
808 {
809 GenTree* tree = const_cast<GenTree*>(this);
810 GenTreePutArgSplit* splitArg = tree->AsPutArgSplit();
811 unsigned regCount = splitArg->gtNumRegs;
812
813 resultMask = RBM_NONE;
814 for (unsigned i = 0; i < regCount; ++i)
815 {
816 regNumber reg = splitArg->GetRegNumByIdx(i);
817 assert(reg != REG_NA);
818 resultMask |= genRegMask(reg);
819 }
820 }
821#endif // FEATURE_ARG_SPLIT
822 else
823 {
824 resultMask = genRegMask(gtRegNum);
825 }
826
827 return resultMask;
828}
829
830//---------------------------------------------------------------
831// GetOtherRegMask: Get the reg mask of gtOtherRegs of call node
832//
833// Arguments:
834// None
835//
836// Return Value:
837// Reg mask of gtOtherRegs of call node.
838//
839regMaskTP GenTreeCall::GetOtherRegMask() const
840{
841 regMaskTP resultMask = RBM_NONE;
842
843#if FEATURE_MULTIREG_RET
844 for (unsigned i = 0; i < MAX_RET_REG_COUNT - 1; ++i)
845 {
846 if (gtOtherRegs[i] != REG_NA)
847 {
848 resultMask |= genRegMask((regNumber)gtOtherRegs[i]);
849 continue;
850 }
851 break;
852 }
853#endif
854
855 return resultMask;
856}
857
858//-------------------------------------------------------------------------
859// IsPure:
860// Returns true if this call is pure. For now, this uses the same
861// definition of "pure" that is that used by HelperCallProperties: a
862// pure call does not read or write any aliased (e.g. heap) memory or
863// have other global side effects (e.g. class constructors, finalizers),
864// but is allowed to throw an exception.
865//
866// NOTE: this call currently only returns true if the call target is a
867// helper method that is known to be pure. No other analysis is
868// performed.
869//
870// Arguments:
871// Copiler - the compiler context.
872//
873// Returns:
874// True if the call is pure; false otherwise.
875//
876bool GenTreeCall::IsPure(Compiler* compiler) const
877{
878 return (gtCallType == CT_HELPER) &&
879 compiler->s_helperCallProperties.IsPure(compiler->eeGetHelperNum(gtCallMethHnd));
880}
881
882//-------------------------------------------------------------------------
883// HasSideEffects:
884// Returns true if this call has any side effects. All non-helpers are considered to have side-effects. Only helpers
885// that do not mutate the heap, do not run constructors, may not throw, and are either a) pure or b) non-finalizing
886// allocation functions are considered side-effect-free.
887//
888// Arguments:
889// compiler - the compiler instance
890// ignoreExceptions - when `true`, ignores exception side effects
891// ignoreCctors - when `true`, ignores class constructor side effects
892//
893// Return Value:
894// true if this call has any side-effects; false otherwise.
895bool GenTreeCall::HasSideEffects(Compiler* compiler, bool ignoreExceptions, bool ignoreCctors) const
896{
897 // Generally all GT_CALL nodes are considered to have side-effects, but we may have extra information about helper
898 // calls that can prove them side-effect-free.
899 if (gtCallType != CT_HELPER)
900 {
901 return true;
902 }
903
904 CorInfoHelpFunc helper = compiler->eeGetHelperNum(gtCallMethHnd);
905 HelperCallProperties& helperProperties = compiler->s_helperCallProperties;
906
907 // We definitely care about the side effects if MutatesHeap is true
908 if (helperProperties.MutatesHeap(helper))
909 {
910 return true;
911 }
912
913 // Unless we have been instructed to ignore cctors (CSE, for example, ignores cctors), consider them side effects.
914 if (!ignoreCctors && helperProperties.MayRunCctor(helper))
915 {
916 return true;
917 }
918
919 // If we also care about exceptions then check if the helper can throw
920 if (!ignoreExceptions && !helperProperties.NoThrow(helper))
921 {
922 return true;
923 }
924
925 // If this is not a Pure helper call or an allocator (that will not need to run a finalizer)
926 // then this call has side effects.
927 return !helperProperties.IsPure(helper) &&
928 (!helperProperties.IsAllocator(helper) || ((gtCallMoreFlags & GTF_CALL_M_ALLOC_SIDE_EFFECTS) != 0));
929}
930
931//-------------------------------------------------------------------------
932// HasNonStandardAddedArgs: Return true if the method has non-standard args added to the call
933// argument list during argument morphing (fgMorphArgs), e.g., passed in R10 or R11 on AMD64.
934// See also GetNonStandardAddedArgCount().
935//
936// Arguments:
937// compiler - the compiler instance
938//
939// Return Value:
940// true if there are any such args, false otherwise.
941//
942bool GenTreeCall::HasNonStandardAddedArgs(Compiler* compiler) const
943{
944 return GetNonStandardAddedArgCount(compiler) != 0;
945}
946
947//-------------------------------------------------------------------------
948// GetNonStandardAddedArgCount: Get the count of non-standard arguments that have been added
949// during call argument morphing (fgMorphArgs). Do not count non-standard args that are already
950// counted in the argument list prior to morphing.
951//
952// This function is used to help map the caller and callee arguments during tail call setup.
953//
954// Arguments:
955// compiler - the compiler instance
956//
957// Return Value:
958// The count of args, as described.
959//
960// Notes:
961// It would be more general to have fgMorphArgs set a bit on the call node when such
962// args are added to a call, and a bit on each such arg, and then have this code loop
963// over the call args when the special call bit is set, counting the args with the special
964// arg bit. This seems pretty heavyweight, though. Instead, this logic needs to be kept
965// in sync with fgMorphArgs.
966//
967int GenTreeCall::GetNonStandardAddedArgCount(Compiler* compiler) const
968{
969 if (IsUnmanaged() && !compiler->opts.ShouldUsePInvokeHelpers())
970 {
971 // R11 = PInvoke cookie param
972 return 1;
973 }
974 else if (IsVirtualStub())
975 {
976 // R11 = Virtual stub param
977 return 1;
978 }
979 else if ((gtCallType == CT_INDIRECT) && (gtCallCookie != nullptr))
980 {
981 // R10 = PInvoke target param
982 // R11 = PInvoke cookie param
983 return 2;
984 }
985 return 0;
986}
987
988//-------------------------------------------------------------------------
989// TreatAsHasRetBufArg:
990//
991// Arguments:
992// compiler, the compiler instance so that we can call eeGetHelperNum
993//
994// Return Value:
995// Returns true if we treat the call as if it has a retBuf argument
996// This method may actually have a retBuf argument
997// or it could be a JIT helper that we are still transforming during
998// the importer phase.
999//
1000// Notes:
1001// On ARM64 marking the method with the GTF_CALL_M_RETBUFFARG flag
1002// will make HasRetBufArg() return true, but will also force the
1003// use of register x8 to pass the RetBuf argument.
1004//
1005// These two Jit Helpers that we handle here by returning true
1006// aren't actually defined to return a struct, so they don't expect
1007// their RetBuf to be passed in x8, instead they expect it in x0.
1008//
1009bool GenTreeCall::TreatAsHasRetBufArg(Compiler* compiler) const
1010{
1011 if (HasRetBufArg())
1012 {
1013 return true;
1014 }
1015 else
1016 {
1017 // If we see a Jit helper call that returns a TYP_STRUCT we will
1018 // transform it as if it has a Return Buffer Argument
1019 //
1020 if (IsHelperCall() && (gtReturnType == TYP_STRUCT))
1021 {
1022 // There are two possible helper calls that use this path:
1023 // CORINFO_HELP_GETFIELDSTRUCT and CORINFO_HELP_UNBOX_NULLABLE
1024 //
1025 CorInfoHelpFunc helpFunc = compiler->eeGetHelperNum(gtCallMethHnd);
1026
1027 if (helpFunc == CORINFO_HELP_GETFIELDSTRUCT)
1028 {
1029 return true;
1030 }
1031 else if (helpFunc == CORINFO_HELP_UNBOX_NULLABLE)
1032 {
1033 return true;
1034 }
1035 else
1036 {
1037 assert(!"Unexpected JIT helper in TreatAsHasRetBufArg");
1038 }
1039 }
1040 }
1041 return false;
1042}
1043
1044//-------------------------------------------------------------------------
1045// IsHelperCall: Determine if this GT_CALL node is a specific helper call.
1046//
1047// Arguments:
1048// compiler - the compiler instance so that we can call eeFindHelper
1049//
1050// Return Value:
1051// Returns true if this GT_CALL node is a call to the specified helper.
1052//
1053bool GenTreeCall::IsHelperCall(Compiler* compiler, unsigned helper) const
1054{
1055 return IsHelperCall(compiler->eeFindHelper(helper));
1056}
1057
1058//------------------------------------------------------------------------
1059// GenTreeCall::ReplaceCallOperand:
1060// Replaces a given operand to a call node and updates the call
1061// argument table if necessary.
1062//
1063// Arguments:
1064// useEdge - the use edge that points to the operand to be replaced.
1065// replacement - the replacement node.
1066//
1067void GenTreeCall::ReplaceCallOperand(GenTree** useEdge, GenTree* replacement)
1068{
1069 assert(useEdge != nullptr);
1070 assert(replacement != nullptr);
1071 assert(TryGetUse(*useEdge, &useEdge));
1072
1073 GenTree* originalOperand = *useEdge;
1074 *useEdge = replacement;
1075
1076 const bool isArgument =
1077 (replacement != gtControlExpr) &&
1078 ((gtCallType != CT_INDIRECT) || ((replacement != gtCallCookie) && (replacement != gtCallAddr)));
1079
1080 if (isArgument)
1081 {
1082 if ((originalOperand->gtFlags & GTF_LATE_ARG) != 0)
1083 {
1084 replacement->gtFlags |= GTF_LATE_ARG;
1085 }
1086 else
1087 {
1088 assert((replacement->gtFlags & GTF_LATE_ARG) == 0);
1089
1090 fgArgTabEntry* fp = Compiler::gtArgEntryByNode(this, originalOperand);
1091 assert(fp->node == originalOperand);
1092 fp->node = replacement;
1093 }
1094 }
1095}
1096
1097//-------------------------------------------------------------------------
1098// AreArgsComplete: Determine if this GT_CALL node's arguments have been processed.
1099//
1100// Return Value:
1101// Returns true if fgMorphArgs has processed the arguments.
1102//
1103bool GenTreeCall::AreArgsComplete() const
1104{
1105 if (fgArgInfo == nullptr)
1106 {
1107 return false;
1108 }
1109 if (fgArgInfo->AreArgsComplete())
1110 {
1111 assert((gtCallLateArgs != nullptr) || !fgArgInfo->HasRegArgs());
1112 return true;
1113 }
1114 assert(gtCallArgs == nullptr);
1115 return false;
1116}
1117
1118#if !defined(FEATURE_PUT_STRUCT_ARG_STK)
1119unsigned GenTreePutArgStk::getArgSize()
1120{
1121 return genTypeSize(genActualType(gtOp1->gtType));
1122}
1123#endif // !defined(FEATURE_PUT_STRUCT_ARG_STK)
1124
1125/*****************************************************************************
1126 *
1127 * Returns non-zero if the two trees are identical.
1128 */
1129
1130bool GenTree::Compare(GenTree* op1, GenTree* op2, bool swapOK)
1131{
1132 genTreeOps oper;
1133 unsigned kind;
1134
1135// printf("tree1:\n"); gtDispTree(op1);
1136// printf("tree2:\n"); gtDispTree(op2);
1137
1138AGAIN:
1139
1140 if (op1 == nullptr)
1141 {
1142 return (op2 == nullptr);
1143 }
1144 if (op2 == nullptr)
1145 {
1146 return false;
1147 }
1148 if (op1 == op2)
1149 {
1150 return true;
1151 }
1152
1153 assert(op1->gtOper != GT_STMT);
1154 assert(op2->gtOper != GT_STMT);
1155
1156 oper = op1->OperGet();
1157
1158 /* The operators must be equal */
1159
1160 if (oper != op2->gtOper)
1161 {
1162 return false;
1163 }
1164
1165 /* The types must be equal */
1166
1167 if (op1->gtType != op2->gtType)
1168 {
1169 return false;
1170 }
1171
1172 /* Overflow must be equal */
1173 if (op1->gtOverflowEx() != op2->gtOverflowEx())
1174 {
1175 return false;
1176 }
1177
1178 /* Sensible flags must be equal */
1179 if ((op1->gtFlags & (GTF_UNSIGNED)) != (op2->gtFlags & (GTF_UNSIGNED)))
1180 {
1181 return false;
1182 }
1183
1184 /* Figure out what kind of nodes we're comparing */
1185
1186 kind = op1->OperKind();
1187
1188 /* Is this a constant node? */
1189
1190 if (kind & GTK_CONST)
1191 {
1192 switch (oper)
1193 {
1194 case GT_CNS_INT:
1195 if (op1->gtIntCon.gtIconVal == op2->gtIntCon.gtIconVal)
1196 {
1197 return true;
1198 }
1199 break;
1200#if 0
1201 // TODO-CQ: Enable this in the future
1202 case GT_CNS_LNG:
1203 if (op1->gtLngCon.gtLconVal == op2->gtLngCon.gtLconVal)
1204 return true;
1205 break;
1206
1207 case GT_CNS_DBL:
1208 if (op1->gtDblCon.gtDconVal == op2->gtDblCon.gtDconVal)
1209 return true;
1210 break;
1211#endif
1212 default:
1213 break;
1214 }
1215
1216 return false;
1217 }
1218
1219 /* Is this a leaf node? */
1220
1221 if (kind & GTK_LEAF)
1222 {
1223 switch (oper)
1224 {
1225 case GT_LCL_VAR:
1226 if (op1->gtLclVarCommon.gtLclNum != op2->gtLclVarCommon.gtLclNum)
1227 {
1228 break;
1229 }
1230
1231 return true;
1232
1233 case GT_LCL_FLD:
1234 if (op1->gtLclFld.gtLclNum != op2->gtLclFld.gtLclNum ||
1235 op1->gtLclFld.gtLclOffs != op2->gtLclFld.gtLclOffs)
1236 {
1237 break;
1238 }
1239
1240 return true;
1241
1242 case GT_CLS_VAR:
1243 if (op1->gtClsVar.gtClsVarHnd != op2->gtClsVar.gtClsVarHnd)
1244 {
1245 break;
1246 }
1247
1248 return true;
1249
1250 case GT_LABEL:
1251 return true;
1252
1253 case GT_ARGPLACE:
1254 if ((op1->gtType == TYP_STRUCT) &&
1255 (op1->gtArgPlace.gtArgPlaceClsHnd != op2->gtArgPlace.gtArgPlaceClsHnd))
1256 {
1257 break;
1258 }
1259 return true;
1260
1261 default:
1262 break;
1263 }
1264
1265 return false;
1266 }
1267
1268 /* Is it a 'simple' unary/binary operator? */
1269
1270 if (kind & GTK_UNOP)
1271 {
1272 if (IsExOp(kind))
1273 {
1274 // ExOp operators extend unary operator with extra, non-GenTree* members. In many cases,
1275 // these should be included in the comparison.
1276 switch (oper)
1277 {
1278 case GT_ARR_LENGTH:
1279 if (op1->gtArrLen.ArrLenOffset() != op2->gtArrLen.ArrLenOffset())
1280 {
1281 return false;
1282 }
1283 break;
1284 case GT_CAST:
1285 if (op1->gtCast.gtCastType != op2->gtCast.gtCastType)
1286 {
1287 return false;
1288 }
1289 break;
1290 case GT_OBJ:
1291 if (op1->AsObj()->gtClass != op2->AsObj()->gtClass)
1292 {
1293 return false;
1294 }
1295 break;
1296
1297 // For the ones below no extra argument matters for comparison.
1298 case GT_BOX:
1299 case GT_RUNTIMELOOKUP:
1300 break;
1301
1302 default:
1303 assert(!"unexpected unary ExOp operator");
1304 }
1305 }
1306 return Compare(op1->gtOp.gtOp1, op2->gtOp.gtOp1);
1307 }
1308
1309 if (kind & GTK_BINOP)
1310 {
1311 if (IsExOp(kind))
1312 {
1313 // ExOp operators extend unary operator with extra, non-GenTree* members. In many cases,
1314 // these should be included in the hash code.
1315 switch (oper)
1316 {
1317 case GT_INTRINSIC:
1318 if (op1->gtIntrinsic.gtIntrinsicId != op2->gtIntrinsic.gtIntrinsicId)
1319 {
1320 return false;
1321 }
1322 break;
1323 case GT_LEA:
1324 if (op1->gtAddrMode.gtScale != op2->gtAddrMode.gtScale)
1325 {
1326 return false;
1327 }
1328 if (op1->gtAddrMode.Offset() != op2->gtAddrMode.Offset())
1329 {
1330 return false;
1331 }
1332 break;
1333 case GT_INDEX:
1334 if (op1->gtIndex.gtIndElemSize != op2->gtIndex.gtIndElemSize)
1335 {
1336 return false;
1337 }
1338 break;
1339 case GT_INDEX_ADDR:
1340 if (op1->AsIndexAddr()->gtElemSize != op2->AsIndexAddr()->gtElemSize)
1341 {
1342 return false;
1343 }
1344 break;
1345#ifdef FEATURE_SIMD
1346 case GT_SIMD:
1347 if ((op1->AsSIMD()->gtSIMDIntrinsicID != op2->AsSIMD()->gtSIMDIntrinsicID) ||
1348 (op1->AsSIMD()->gtSIMDBaseType != op2->AsSIMD()->gtSIMDBaseType) ||
1349 (op1->AsSIMD()->gtSIMDSize != op2->AsSIMD()->gtSIMDSize))
1350 {
1351 return false;
1352 }
1353 break;
1354#endif // FEATURE_SIMD
1355
1356#ifdef FEATURE_HW_INTRINSICS
1357 case GT_HWIntrinsic:
1358 if ((op1->AsHWIntrinsic()->gtHWIntrinsicId != op2->AsHWIntrinsic()->gtHWIntrinsicId) ||
1359 (op1->AsHWIntrinsic()->gtSIMDBaseType != op2->AsHWIntrinsic()->gtSIMDBaseType) ||
1360 (op1->AsHWIntrinsic()->gtSIMDSize != op2->AsHWIntrinsic()->gtSIMDSize) ||
1361 (op1->AsHWIntrinsic()->gtIndexBaseType != op2->AsHWIntrinsic()->gtIndexBaseType))
1362 {
1363 return false;
1364 }
1365 break;
1366#endif
1367
1368 // For the ones below no extra argument matters for comparison.
1369 case GT_QMARK:
1370 break;
1371
1372 default:
1373 assert(!"unexpected binary ExOp operator");
1374 }
1375 }
1376
1377 if (op1->gtOp.gtOp2)
1378 {
1379 if (!Compare(op1->gtOp.gtOp1, op2->gtOp.gtOp1, swapOK))
1380 {
1381 if (swapOK && OperIsCommutative(oper) &&
1382 ((op1->gtOp.gtOp1->gtFlags | op1->gtOp.gtOp2->gtFlags | op2->gtOp.gtOp1->gtFlags |
1383 op2->gtOp.gtOp2->gtFlags) &
1384 GTF_ALL_EFFECT) == 0)
1385 {
1386 if (Compare(op1->gtOp.gtOp1, op2->gtOp.gtOp2, swapOK))
1387 {
1388 op1 = op1->gtOp.gtOp2;
1389 op2 = op2->gtOp.gtOp1;
1390 goto AGAIN;
1391 }
1392 }
1393
1394 return false;
1395 }
1396
1397 op1 = op1->gtOp.gtOp2;
1398 op2 = op2->gtOp.gtOp2;
1399
1400 goto AGAIN;
1401 }
1402 else
1403 {
1404
1405 op1 = op1->gtOp.gtOp1;
1406 op2 = op2->gtOp.gtOp1;
1407
1408 if (!op1)
1409 {
1410 return (op2 == nullptr);
1411 }
1412 if (!op2)
1413 {
1414 return false;
1415 }
1416
1417 goto AGAIN;
1418 }
1419 }
1420
1421 /* See what kind of a special operator we have here */
1422
1423 switch (oper)
1424 {
1425 case GT_FIELD:
1426 if (op1->gtField.gtFldHnd != op2->gtField.gtFldHnd)
1427 {
1428 break;
1429 }
1430
1431 op1 = op1->gtField.gtFldObj;
1432 op2 = op2->gtField.gtFldObj;
1433
1434 if (op1 || op2)
1435 {
1436 if (op1 && op2)
1437 {
1438 goto AGAIN;
1439 }
1440 }
1441
1442 return true;
1443
1444 case GT_CALL:
1445
1446 if (op1->gtCall.gtCallType != op2->gtCall.gtCallType)
1447 {
1448 return false;
1449 }
1450
1451 if (op1->gtCall.gtCallType != CT_INDIRECT)
1452 {
1453 if (op1->gtCall.gtCallMethHnd != op2->gtCall.gtCallMethHnd)
1454 {
1455 return false;
1456 }
1457
1458#ifdef FEATURE_READYTORUN_COMPILER
1459 if (op1->gtCall.gtEntryPoint.addr != op2->gtCall.gtEntryPoint.addr)
1460 {
1461 return false;
1462 }
1463#endif
1464 }
1465 else
1466 {
1467 if (!Compare(op1->gtCall.gtCallAddr, op2->gtCall.gtCallAddr))
1468 {
1469 return false;
1470 }
1471 }
1472
1473 if (Compare(op1->gtCall.gtCallLateArgs, op2->gtCall.gtCallLateArgs) &&
1474 Compare(op1->gtCall.gtCallArgs, op2->gtCall.gtCallArgs) &&
1475 Compare(op1->gtCall.gtControlExpr, op2->gtCall.gtControlExpr) &&
1476 Compare(op1->gtCall.gtCallObjp, op2->gtCall.gtCallObjp))
1477 {
1478 return true;
1479 }
1480 break;
1481
1482 case GT_ARR_ELEM:
1483
1484 if (op1->gtArrElem.gtArrRank != op2->gtArrElem.gtArrRank)
1485 {
1486 return false;
1487 }
1488
1489 // NOTE: gtArrElemSize may need to be handled
1490
1491 unsigned dim;
1492 for (dim = 0; dim < op1->gtArrElem.gtArrRank; dim++)
1493 {
1494 if (!Compare(op1->gtArrElem.gtArrInds[dim], op2->gtArrElem.gtArrInds[dim]))
1495 {
1496 return false;
1497 }
1498 }
1499
1500 op1 = op1->gtArrElem.gtArrObj;
1501 op2 = op2->gtArrElem.gtArrObj;
1502 goto AGAIN;
1503
1504 case GT_ARR_OFFSET:
1505 if (op1->gtArrOffs.gtCurrDim != op2->gtArrOffs.gtCurrDim ||
1506 op1->gtArrOffs.gtArrRank != op2->gtArrOffs.gtArrRank)
1507 {
1508 return false;
1509 }
1510 return (Compare(op1->gtArrOffs.gtOffset, op2->gtArrOffs.gtOffset) &&
1511 Compare(op1->gtArrOffs.gtIndex, op2->gtArrOffs.gtIndex) &&
1512 Compare(op1->gtArrOffs.gtArrObj, op2->gtArrOffs.gtArrObj));
1513
1514 case GT_CMPXCHG:
1515 return Compare(op1->gtCmpXchg.gtOpLocation, op2->gtCmpXchg.gtOpLocation) &&
1516 Compare(op1->gtCmpXchg.gtOpValue, op2->gtCmpXchg.gtOpValue) &&
1517 Compare(op1->gtCmpXchg.gtOpComparand, op2->gtCmpXchg.gtOpComparand);
1518
1519 case GT_ARR_BOUNDS_CHECK:
1520#ifdef FEATURE_SIMD
1521 case GT_SIMD_CHK:
1522#endif // FEATURE_SIMD
1523#ifdef FEATURE_HW_INTRINSICS
1524 case GT_HW_INTRINSIC_CHK:
1525#endif // FEATURE_HW_INTRINSICS
1526 return Compare(op1->gtBoundsChk.gtIndex, op2->gtBoundsChk.gtIndex) &&
1527 Compare(op1->gtBoundsChk.gtArrLen, op2->gtBoundsChk.gtArrLen) &&
1528 (op1->gtBoundsChk.gtThrowKind == op2->gtBoundsChk.gtThrowKind);
1529
1530 case GT_STORE_DYN_BLK:
1531 case GT_DYN_BLK:
1532 return Compare(op1->gtDynBlk.Addr(), op2->gtDynBlk.Addr()) &&
1533 Compare(op1->gtDynBlk.Data(), op2->gtDynBlk.Data()) &&
1534 Compare(op1->gtDynBlk.gtDynamicSize, op2->gtDynBlk.gtDynamicSize);
1535
1536 default:
1537 assert(!"unexpected operator");
1538 }
1539
1540 return false;
1541}
1542
1543/*****************************************************************************
1544 *
1545 * Returns non-zero if the given tree contains a use of a local #lclNum.
1546 */
1547
1548bool Compiler::gtHasRef(GenTree* tree, ssize_t lclNum, bool defOnly)
1549{
1550 genTreeOps oper;
1551 unsigned kind;
1552
1553AGAIN:
1554
1555 assert(tree);
1556
1557 oper = tree->OperGet();
1558 kind = tree->OperKind();
1559
1560 assert(oper != GT_STMT);
1561
1562 /* Is this a constant node? */
1563
1564 if (kind & GTK_CONST)
1565 {
1566 return false;
1567 }
1568
1569 /* Is this a leaf node? */
1570
1571 if (kind & GTK_LEAF)
1572 {
1573 if (oper == GT_LCL_VAR)
1574 {
1575 if (tree->gtLclVarCommon.gtLclNum == (unsigned)lclNum)
1576 {
1577 if (!defOnly)
1578 {
1579 return true;
1580 }
1581 }
1582 }
1583 else if (oper == GT_RET_EXPR)
1584 {
1585 return gtHasRef(tree->gtRetExpr.gtInlineCandidate, lclNum, defOnly);
1586 }
1587
1588 return false;
1589 }
1590
1591 /* Is it a 'simple' unary/binary operator? */
1592
1593 if (kind & GTK_SMPOP)
1594 {
1595 if (tree->gtGetOp2IfPresent())
1596 {
1597 if (gtHasRef(tree->gtOp.gtOp1, lclNum, defOnly))
1598 {
1599 return true;
1600 }
1601
1602 tree = tree->gtOp.gtOp2;
1603 goto AGAIN;
1604 }
1605 else
1606 {
1607 tree = tree->gtOp.gtOp1;
1608
1609 if (!tree)
1610 {
1611 return false;
1612 }
1613
1614 if (oper == GT_ASG)
1615 {
1616 // 'tree' is the gtOp1 of an assignment node. So we can handle
1617 // the case where defOnly is either true or false.
1618
1619 if (tree->gtOper == GT_LCL_VAR && tree->gtLclVarCommon.gtLclNum == (unsigned)lclNum)
1620 {
1621 return true;
1622 }
1623 else if (tree->gtOper == GT_FIELD && lclNum == (ssize_t)tree->gtField.gtFldHnd)
1624 {
1625 return true;
1626 }
1627 }
1628
1629 goto AGAIN;
1630 }
1631 }
1632
1633 /* See what kind of a special operator we have here */
1634
1635 switch (oper)
1636 {
1637 case GT_FIELD:
1638 if (lclNum == (ssize_t)tree->gtField.gtFldHnd)
1639 {
1640 if (!defOnly)
1641 {
1642 return true;
1643 }
1644 }
1645
1646 tree = tree->gtField.gtFldObj;
1647 if (tree)
1648 {
1649 goto AGAIN;
1650 }
1651 break;
1652
1653 case GT_CALL:
1654
1655 if (tree->gtCall.gtCallObjp)
1656 {
1657 if (gtHasRef(tree->gtCall.gtCallObjp, lclNum, defOnly))
1658 {
1659 return true;
1660 }
1661 }
1662
1663 if (tree->gtCall.gtCallArgs)
1664 {
1665 if (gtHasRef(tree->gtCall.gtCallArgs, lclNum, defOnly))
1666 {
1667 return true;
1668 }
1669 }
1670
1671 if (tree->gtCall.gtCallLateArgs)
1672 {
1673 if (gtHasRef(tree->gtCall.gtCallLateArgs, lclNum, defOnly))
1674 {
1675 return true;
1676 }
1677 }
1678
1679 if (tree->gtCall.gtControlExpr)
1680 {
1681 if (gtHasRef(tree->gtCall.gtControlExpr, lclNum, defOnly))
1682 {
1683 return true;
1684 }
1685 }
1686
1687 if (tree->gtCall.gtCallType == CT_INDIRECT)
1688 {
1689 // pinvoke-calli cookie is a constant, or constant indirection
1690 assert(tree->gtCall.gtCallCookie == nullptr || tree->gtCall.gtCallCookie->gtOper == GT_CNS_INT ||
1691 tree->gtCall.gtCallCookie->gtOper == GT_IND);
1692
1693 tree = tree->gtCall.gtCallAddr;
1694 }
1695 else
1696 {
1697 tree = nullptr;
1698 }
1699
1700 if (tree)
1701 {
1702 goto AGAIN;
1703 }
1704
1705 break;
1706
1707 case GT_ARR_ELEM:
1708 if (gtHasRef(tree->gtArrElem.gtArrObj, lclNum, defOnly))
1709 {
1710 return true;
1711 }
1712
1713 unsigned dim;
1714 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
1715 {
1716 if (gtHasRef(tree->gtArrElem.gtArrInds[dim], lclNum, defOnly))
1717 {
1718 return true;
1719 }
1720 }
1721
1722 break;
1723
1724 case GT_ARR_OFFSET:
1725 if (gtHasRef(tree->gtArrOffs.gtOffset, lclNum, defOnly) ||
1726 gtHasRef(tree->gtArrOffs.gtIndex, lclNum, defOnly) ||
1727 gtHasRef(tree->gtArrOffs.gtArrObj, lclNum, defOnly))
1728 {
1729 return true;
1730 }
1731 break;
1732
1733 case GT_CMPXCHG:
1734 if (gtHasRef(tree->gtCmpXchg.gtOpLocation, lclNum, defOnly))
1735 {
1736 return true;
1737 }
1738 if (gtHasRef(tree->gtCmpXchg.gtOpValue, lclNum, defOnly))
1739 {
1740 return true;
1741 }
1742 if (gtHasRef(tree->gtCmpXchg.gtOpComparand, lclNum, defOnly))
1743 {
1744 return true;
1745 }
1746 break;
1747
1748 case GT_ARR_BOUNDS_CHECK:
1749#ifdef FEATURE_SIMD
1750 case GT_SIMD_CHK:
1751#endif // FEATURE_SIMD
1752#ifdef FEATURE_HW_INTRINSICS
1753 case GT_HW_INTRINSIC_CHK:
1754#endif // FEATURE_HW_INTRINSICS
1755 if (gtHasRef(tree->gtBoundsChk.gtIndex, lclNum, defOnly))
1756 {
1757 return true;
1758 }
1759 if (gtHasRef(tree->gtBoundsChk.gtArrLen, lclNum, defOnly))
1760 {
1761 return true;
1762 }
1763 break;
1764
1765 case GT_STORE_DYN_BLK:
1766 if (gtHasRef(tree->gtDynBlk.Data(), lclNum, defOnly))
1767 {
1768 return true;
1769 }
1770 __fallthrough;
1771 case GT_DYN_BLK:
1772 if (gtHasRef(tree->gtDynBlk.Addr(), lclNum, defOnly))
1773 {
1774 return true;
1775 }
1776 if (gtHasRef(tree->gtDynBlk.gtDynamicSize, lclNum, defOnly))
1777 {
1778 return true;
1779 }
1780 break;
1781
1782 default:
1783#ifdef DEBUG
1784 gtDispTree(tree);
1785#endif
1786 assert(!"unexpected operator");
1787 }
1788
1789 return false;
1790}
1791
1792struct AddrTakenDsc
1793{
1794 Compiler* comp;
1795 bool hasAddrTakenLcl;
1796};
1797
1798/* static */
1799Compiler::fgWalkResult Compiler::gtHasLocalsWithAddrOpCB(GenTree** pTree, fgWalkData* data)
1800{
1801 GenTree* tree = *pTree;
1802 Compiler* comp = data->compiler;
1803
1804 if (tree->gtOper == GT_LCL_VAR)
1805 {
1806 unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
1807 LclVarDsc* varDsc = &comp->lvaTable[lclNum];
1808
1809 if (varDsc->lvHasLdAddrOp || varDsc->lvAddrExposed)
1810 {
1811 ((AddrTakenDsc*)data->pCallbackData)->hasAddrTakenLcl = true;
1812 return WALK_ABORT;
1813 }
1814 }
1815
1816 return WALK_CONTINUE;
1817}
1818
1819/*****************************************************************************
1820 *
1821 * Return true if this tree contains locals with lvHasLdAddrOp or lvAddrExposed
1822 * flag(s) set.
1823 */
1824
1825bool Compiler::gtHasLocalsWithAddrOp(GenTree* tree)
1826{
1827 AddrTakenDsc desc;
1828
1829 desc.comp = this;
1830 desc.hasAddrTakenLcl = false;
1831
1832 fgWalkTreePre(&tree, gtHasLocalsWithAddrOpCB, &desc);
1833
1834 return desc.hasAddrTakenLcl;
1835}
1836
1837#ifdef DEBUG
1838
1839/*****************************************************************************
1840 *
1841 * Helper used to compute hash values for trees.
1842 */
1843
1844inline unsigned genTreeHashAdd(unsigned old, unsigned add)
1845{
1846 return (old + old / 2) ^ add;
1847}
1848
1849inline unsigned genTreeHashAdd(unsigned old, void* add)
1850{
1851 return genTreeHashAdd(old, (unsigned)(size_t)add);
1852}
1853
1854/*****************************************************************************
1855 *
1856 * Given an arbitrary expression tree, compute a hash value for it.
1857 */
1858
1859unsigned Compiler::gtHashValue(GenTree* tree)
1860{
1861 genTreeOps oper;
1862 unsigned kind;
1863
1864 unsigned hash = 0;
1865
1866 GenTree* temp;
1867
1868AGAIN:
1869 assert(tree);
1870 assert(tree->gtOper != GT_STMT);
1871
1872 /* Figure out what kind of a node we have */
1873
1874 oper = tree->OperGet();
1875 kind = tree->OperKind();
1876
1877 /* Include the operator value in the hash */
1878
1879 hash = genTreeHashAdd(hash, oper);
1880
1881 /* Is this a constant or leaf node? */
1882
1883 if (kind & (GTK_CONST | GTK_LEAF))
1884 {
1885 size_t add;
1886
1887 switch (oper)
1888 {
1889 UINT64 bits;
1890 case GT_LCL_VAR:
1891 add = tree->gtLclVar.gtLclNum;
1892 break;
1893 case GT_LCL_FLD:
1894 hash = genTreeHashAdd(hash, tree->gtLclFld.gtLclNum);
1895 add = tree->gtLclFld.gtLclOffs;
1896 break;
1897
1898 case GT_CNS_INT:
1899 add = tree->gtIntCon.gtIconVal;
1900 break;
1901 case GT_CNS_LNG:
1902 bits = (UINT64)tree->gtLngCon.gtLconVal;
1903#ifdef _HOST_64BIT_
1904 add = bits;
1905#else // 32-bit host
1906 add = genTreeHashAdd(uhi32(bits), ulo32(bits));
1907#endif
1908 break;
1909 case GT_CNS_DBL:
1910 bits = *(UINT64*)(&tree->gtDblCon.gtDconVal);
1911#ifdef _HOST_64BIT_
1912 add = bits;
1913#else // 32-bit host
1914 add = genTreeHashAdd(uhi32(bits), ulo32(bits));
1915#endif
1916 break;
1917 case GT_CNS_STR:
1918 add = tree->gtStrCon.gtSconCPX;
1919 break;
1920
1921 case GT_JMP:
1922 add = tree->gtVal.gtVal1;
1923 break;
1924
1925 default:
1926 add = 0;
1927 break;
1928 }
1929
1930 // clang-format off
1931 // narrow 'add' into a 32-bit 'val'
1932 unsigned val;
1933#ifdef _HOST_64BIT_
1934 val = genTreeHashAdd(uhi32(add), ulo32(add));
1935#else // 32-bit host
1936 val = add;
1937#endif
1938 // clang-format on
1939
1940 hash = genTreeHashAdd(hash, val);
1941 goto DONE;
1942 }
1943
1944 /* Is it a 'simple' unary/binary operator? */
1945
1946 GenTree* op1;
1947
1948 if (kind & GTK_UNOP)
1949 {
1950 op1 = tree->gtOp.gtOp1;
1951 /* Special case: no sub-operand at all */
1952
1953 if (GenTree::IsExOp(kind))
1954 {
1955 // ExOp operators extend operators with extra, non-GenTree* members. In many cases,
1956 // these should be included in the hash code.
1957 switch (oper)
1958 {
1959 case GT_ARR_LENGTH:
1960 hash += tree->gtArrLen.ArrLenOffset();
1961 break;
1962 case GT_CAST:
1963 hash ^= tree->gtCast.gtCastType;
1964 break;
1965 case GT_INDEX:
1966 hash += tree->gtIndex.gtIndElemSize;
1967 break;
1968 case GT_INDEX_ADDR:
1969 hash += tree->AsIndexAddr()->gtElemSize;
1970 break;
1971 case GT_ALLOCOBJ:
1972 hash = genTreeHashAdd(hash, static_cast<unsigned>(
1973 reinterpret_cast<uintptr_t>(tree->gtAllocObj.gtAllocObjClsHnd)));
1974 hash = genTreeHashAdd(hash, tree->gtAllocObj.gtNewHelper);
1975 break;
1976 case GT_RUNTIMELOOKUP:
1977 hash =
1978 genTreeHashAdd(hash,
1979 static_cast<unsigned>(reinterpret_cast<uintptr_t>(tree->gtRuntimeLookup.gtHnd)));
1980 break;
1981
1982 case GT_OBJ:
1983 hash =
1984 genTreeHashAdd(hash, static_cast<unsigned>(reinterpret_cast<uintptr_t>(tree->gtObj.gtClass)));
1985 break;
1986 // For the ones below no extra argument matters for comparison.
1987 case GT_BOX:
1988 break;
1989
1990 default:
1991 assert(!"unexpected unary ExOp operator");
1992 }
1993 }
1994
1995 if (!op1)
1996 {
1997 goto DONE;
1998 }
1999
2000 tree = op1;
2001 goto AGAIN;
2002 }
2003
2004 if (kind & GTK_BINOP)
2005 {
2006 if (GenTree::IsExOp(kind))
2007 {
2008 // ExOp operators extend operators with extra, non-GenTree* members. In many cases,
2009 // these should be included in the hash code.
2010 switch (oper)
2011 {
2012 case GT_INTRINSIC:
2013 hash += tree->gtIntrinsic.gtIntrinsicId;
2014 break;
2015 case GT_LEA:
2016 hash += static_cast<unsigned>(tree->gtAddrMode.Offset() << 3) + tree->gtAddrMode.gtScale;
2017 break;
2018
2019 case GT_BLK:
2020 case GT_STORE_BLK:
2021 hash += tree->gtBlk.gtBlkSize;
2022 break;
2023
2024 case GT_OBJ:
2025 case GT_STORE_OBJ:
2026 hash ^= PtrToUlong(tree->AsObj()->gtClass);
2027 break;
2028
2029 case GT_DYN_BLK:
2030 case GT_STORE_DYN_BLK:
2031 hash += gtHashValue(tree->AsDynBlk()->gtDynamicSize);
2032 break;
2033
2034 // For the ones below no extra argument matters for comparison.
2035 case GT_ARR_INDEX:
2036 case GT_QMARK:
2037 case GT_INDEX:
2038 case GT_INDEX_ADDR:
2039 break;
2040
2041#ifdef FEATURE_SIMD
2042 case GT_SIMD:
2043 hash += tree->gtSIMD.gtSIMDIntrinsicID;
2044 hash += tree->gtSIMD.gtSIMDBaseType;
2045 hash += tree->gtSIMD.gtSIMDSize;
2046 break;
2047#endif // FEATURE_SIMD
2048
2049#ifdef FEATURE_HW_INTRINSICS
2050 case GT_HWIntrinsic:
2051 hash += tree->gtHWIntrinsic.gtHWIntrinsicId;
2052 hash += tree->gtHWIntrinsic.gtSIMDBaseType;
2053 hash += tree->gtHWIntrinsic.gtSIMDSize;
2054 hash += tree->gtHWIntrinsic.gtIndexBaseType;
2055 break;
2056#endif // FEATURE_HW_INTRINSICS
2057
2058 default:
2059 assert(!"unexpected binary ExOp operator");
2060 }
2061 }
2062
2063 op1 = tree->gtOp.gtOp1;
2064 GenTree* op2 = tree->gtOp.gtOp2;
2065
2066 /* Is there a second sub-operand? */
2067
2068 if (!op2)
2069 {
2070 /* Special case: no sub-operands at all */
2071
2072 if (!op1)
2073 {
2074 goto DONE;
2075 }
2076
2077 /* This is a unary operator */
2078
2079 tree = op1;
2080 goto AGAIN;
2081 }
2082
2083 /* This is a binary operator */
2084
2085 unsigned hsh1 = gtHashValue(op1);
2086
2087 /* Add op1's hash to the running value and continue with op2 */
2088
2089 hash = genTreeHashAdd(hash, hsh1);
2090
2091 tree = op2;
2092 goto AGAIN;
2093 }
2094
2095 /* See what kind of a special operator we have here */
2096 switch (tree->gtOper)
2097 {
2098 case GT_FIELD:
2099 if (tree->gtField.gtFldObj)
2100 {
2101 temp = tree->gtField.gtFldObj;
2102 assert(temp);
2103 hash = genTreeHashAdd(hash, gtHashValue(temp));
2104 }
2105 break;
2106
2107 case GT_STMT:
2108 temp = tree->gtStmt.gtStmtExpr;
2109 assert(temp);
2110 hash = genTreeHashAdd(hash, gtHashValue(temp));
2111 break;
2112
2113 case GT_ARR_ELEM:
2114
2115 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrElem.gtArrObj));
2116
2117 unsigned dim;
2118 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
2119 {
2120 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrElem.gtArrInds[dim]));
2121 }
2122
2123 break;
2124
2125 case GT_ARR_OFFSET:
2126 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrOffs.gtOffset));
2127 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrOffs.gtIndex));
2128 hash = genTreeHashAdd(hash, gtHashValue(tree->gtArrOffs.gtArrObj));
2129 break;
2130
2131 case GT_CALL:
2132
2133 if (tree->gtCall.gtCallObjp && tree->gtCall.gtCallObjp->gtOper != GT_NOP)
2134 {
2135 temp = tree->gtCall.gtCallObjp;
2136 assert(temp);
2137 hash = genTreeHashAdd(hash, gtHashValue(temp));
2138 }
2139
2140 if (tree->gtCall.gtCallArgs)
2141 {
2142 temp = tree->gtCall.gtCallArgs;
2143 assert(temp);
2144 hash = genTreeHashAdd(hash, gtHashValue(temp));
2145 }
2146
2147 if (tree->gtCall.gtCallType == CT_INDIRECT)
2148 {
2149 temp = tree->gtCall.gtCallAddr;
2150 assert(temp);
2151 hash = genTreeHashAdd(hash, gtHashValue(temp));
2152 }
2153 else
2154 {
2155 hash = genTreeHashAdd(hash, tree->gtCall.gtCallMethHnd);
2156 }
2157
2158 if (tree->gtCall.gtCallLateArgs)
2159 {
2160 temp = tree->gtCall.gtCallLateArgs;
2161 assert(temp);
2162 hash = genTreeHashAdd(hash, gtHashValue(temp));
2163 }
2164 break;
2165
2166 case GT_CMPXCHG:
2167 hash = genTreeHashAdd(hash, gtHashValue(tree->gtCmpXchg.gtOpLocation));
2168 hash = genTreeHashAdd(hash, gtHashValue(tree->gtCmpXchg.gtOpValue));
2169 hash = genTreeHashAdd(hash, gtHashValue(tree->gtCmpXchg.gtOpComparand));
2170 break;
2171
2172 case GT_ARR_BOUNDS_CHECK:
2173#ifdef FEATURE_SIMD
2174 case GT_SIMD_CHK:
2175#endif // FEATURE_SIMD
2176#ifdef FEATURE_HW_INTRINSICS
2177 case GT_HW_INTRINSIC_CHK:
2178#endif // FEATURE_HW_INTRINSICS
2179 hash = genTreeHashAdd(hash, gtHashValue(tree->gtBoundsChk.gtIndex));
2180 hash = genTreeHashAdd(hash, gtHashValue(tree->gtBoundsChk.gtArrLen));
2181 hash = genTreeHashAdd(hash, tree->gtBoundsChk.gtThrowKind);
2182 break;
2183
2184 case GT_STORE_DYN_BLK:
2185 hash = genTreeHashAdd(hash, gtHashValue(tree->gtDynBlk.Data()));
2186 __fallthrough;
2187 case GT_DYN_BLK:
2188 hash = genTreeHashAdd(hash, gtHashValue(tree->gtDynBlk.Addr()));
2189 hash = genTreeHashAdd(hash, gtHashValue(tree->gtDynBlk.gtDynamicSize));
2190 break;
2191
2192 default:
2193#ifdef DEBUG
2194 gtDispTree(tree);
2195#endif
2196 assert(!"unexpected operator");
2197 break;
2198 }
2199
2200DONE:
2201
2202 return hash;
2203}
2204
2205#endif // DEBUG
2206
2207/*****************************************************************************
2208 *
2209 * Return a relational operator that is the reverse of the given one.
2210 */
2211
2212/* static */
2213genTreeOps GenTree::ReverseRelop(genTreeOps relop)
2214{
2215 static const genTreeOps reverseOps[] = {
2216 GT_NE, // GT_EQ
2217 GT_EQ, // GT_NE
2218 GT_GE, // GT_LT
2219 GT_GT, // GT_LE
2220 GT_LT, // GT_GE
2221 GT_LE, // GT_GT
2222 GT_TEST_NE, // GT_TEST_EQ
2223 GT_TEST_EQ, // GT_TEST_NE
2224 };
2225
2226 assert(reverseOps[GT_EQ - GT_EQ] == GT_NE);
2227 assert(reverseOps[GT_NE - GT_EQ] == GT_EQ);
2228
2229 assert(reverseOps[GT_LT - GT_EQ] == GT_GE);
2230 assert(reverseOps[GT_LE - GT_EQ] == GT_GT);
2231 assert(reverseOps[GT_GE - GT_EQ] == GT_LT);
2232 assert(reverseOps[GT_GT - GT_EQ] == GT_LE);
2233
2234 assert(reverseOps[GT_TEST_EQ - GT_EQ] == GT_TEST_NE);
2235 assert(reverseOps[GT_TEST_NE - GT_EQ] == GT_TEST_EQ);
2236
2237 assert(OperIsCompare(relop));
2238 assert(relop >= GT_EQ && (unsigned)(relop - GT_EQ) < sizeof(reverseOps));
2239
2240 return reverseOps[relop - GT_EQ];
2241}
2242
2243/*****************************************************************************
2244 *
2245 * Return a relational operator that will work for swapped operands.
2246 */
2247
2248/* static */
2249genTreeOps GenTree::SwapRelop(genTreeOps relop)
2250{
2251 static const genTreeOps swapOps[] = {
2252 GT_EQ, // GT_EQ
2253 GT_NE, // GT_NE
2254 GT_GT, // GT_LT
2255 GT_GE, // GT_LE
2256 GT_LE, // GT_GE
2257 GT_LT, // GT_GT
2258 GT_TEST_EQ, // GT_TEST_EQ
2259 GT_TEST_NE, // GT_TEST_NE
2260 };
2261
2262 assert(swapOps[GT_EQ - GT_EQ] == GT_EQ);
2263 assert(swapOps[GT_NE - GT_EQ] == GT_NE);
2264
2265 assert(swapOps[GT_LT - GT_EQ] == GT_GT);
2266 assert(swapOps[GT_LE - GT_EQ] == GT_GE);
2267 assert(swapOps[GT_GE - GT_EQ] == GT_LE);
2268 assert(swapOps[GT_GT - GT_EQ] == GT_LT);
2269
2270 assert(swapOps[GT_TEST_EQ - GT_EQ] == GT_TEST_EQ);
2271 assert(swapOps[GT_TEST_NE - GT_EQ] == GT_TEST_NE);
2272
2273 assert(OperIsCompare(relop));
2274 assert(relop >= GT_EQ && (unsigned)(relop - GT_EQ) < sizeof(swapOps));
2275
2276 return swapOps[relop - GT_EQ];
2277}
2278
2279/*****************************************************************************
2280 *
2281 * Reverse the meaning of the given test condition.
2282 */
2283
2284GenTree* Compiler::gtReverseCond(GenTree* tree)
2285{
2286 if (tree->OperIsCompare())
2287 {
2288 tree->SetOper(GenTree::ReverseRelop(tree->OperGet()));
2289
2290 // Flip the GTF_RELOP_NAN_UN bit
2291 // a ord b === (a != NaN && b != NaN)
2292 // a unord b === (a == NaN || b == NaN)
2293 // => !(a ord b) === (a unord b)
2294 if (varTypeIsFloating(tree->gtOp.gtOp1->TypeGet()))
2295 {
2296 tree->gtFlags ^= GTF_RELOP_NAN_UN;
2297 }
2298 }
2299 else if (tree->OperIs(GT_JCC, GT_SETCC))
2300 {
2301 GenTreeCC* cc = tree->AsCC();
2302 cc->gtCondition = GenTree::ReverseRelop(cc->gtCondition);
2303 }
2304 else if (tree->OperIs(GT_JCMP))
2305 {
2306 // Flip the GTF_JCMP_EQ
2307 //
2308 // This causes switching
2309 // cbz <=> cbnz
2310 // tbz <=> tbnz
2311 tree->gtFlags ^= GTF_JCMP_EQ;
2312 }
2313 else
2314 {
2315 tree = gtNewOperNode(GT_NOT, TYP_INT, tree);
2316 }
2317
2318 return tree;
2319}
2320
2321/*****************************************************************************/
2322
2323#ifdef DEBUG
2324
2325bool GenTree::gtIsValid64RsltMul()
2326{
2327 if ((gtOper != GT_MUL) || !(gtFlags & GTF_MUL_64RSLT))
2328 {
2329 return false;
2330 }
2331
2332 GenTree* op1 = gtOp.gtOp1;
2333 GenTree* op2 = gtOp.gtOp2;
2334
2335 if (TypeGet() != TYP_LONG || op1->TypeGet() != TYP_LONG || op2->TypeGet() != TYP_LONG)
2336 {
2337 return false;
2338 }
2339
2340 if (gtOverflow())
2341 {
2342 return false;
2343 }
2344
2345 // op1 has to be conv.i8(i4Expr)
2346 if ((op1->gtOper != GT_CAST) || (genActualType(op1->CastFromType()) != TYP_INT))
2347 {
2348 return false;
2349 }
2350
2351 // op2 has to be conv.i8(i4Expr)
2352 if ((op2->gtOper != GT_CAST) || (genActualType(op2->CastFromType()) != TYP_INT))
2353 {
2354 return false;
2355 }
2356
2357 // The signedness of both casts must be the same
2358 if (((op1->gtFlags & GTF_UNSIGNED) != 0) != ((op2->gtFlags & GTF_UNSIGNED) != 0))
2359 {
2360 return false;
2361 }
2362
2363 // Do unsigned mul iff both the casts are unsigned
2364 if (((op1->gtFlags & GTF_UNSIGNED) != 0) != ((gtFlags & GTF_UNSIGNED) != 0))
2365 {
2366 return false;
2367 }
2368
2369 return true;
2370}
2371
2372#endif // DEBUG
2373
2374//------------------------------------------------------------------------------
2375// gtSetListOrder : Figure out the evaluation order for a list of values.
2376//
2377//
2378// Arguments:
2379// list - List to figure out the evaluation order for
2380// isListCallArgs - True iff the list is a list of call arguments
2381// callArgsInRegs - True iff the list is a list of call arguments and they are passed in registers
2382//
2383// Return Value:
2384// True if the operation can be a root of a bitwise rotation tree; false otherwise.
2385
2386unsigned Compiler::gtSetListOrder(GenTree* list, bool isListCallArgs, bool callArgsInRegs)
2387{
2388 assert((list != nullptr) && list->OperIsAnyList());
2389 assert(!callArgsInRegs || isListCallArgs);
2390
2391 ArrayStack<GenTree*> listNodes(getAllocator(CMK_ArrayStack));
2392
2393 do
2394 {
2395 listNodes.Push(list);
2396 list = list->gtOp.gtOp2;
2397 } while ((list != nullptr) && (list->OperIsAnyList()));
2398
2399 unsigned nxtlvl = (list == nullptr) ? 0 : gtSetEvalOrder(list);
2400 while (!listNodes.Empty())
2401 {
2402 list = listNodes.Pop();
2403 assert(list && list->OperIsAnyList());
2404 GenTree* next = list->gtOp.gtOp2;
2405
2406 unsigned level = 0;
2407
2408 // TODO: Do we have to compute costs differently for argument lists and
2409 // all other lists?
2410 // https://github.com/dotnet/coreclr/issues/7095
2411 unsigned costSz = (isListCallArgs || (next == nullptr)) ? 0 : 1;
2412 unsigned costEx = (isListCallArgs || (next == nullptr)) ? 0 : 1;
2413
2414 if (next != nullptr)
2415 {
2416 if (isListCallArgs)
2417 {
2418 if (level < nxtlvl)
2419 {
2420 level = nxtlvl;
2421 }
2422 }
2423 costEx += next->gtCostEx;
2424 costSz += next->gtCostSz;
2425 }
2426
2427 GenTree* op1 = list->gtOp.gtOp1;
2428 unsigned lvl = gtSetEvalOrder(op1);
2429
2430 // Swap the level counts
2431 if (list->gtFlags & GTF_REVERSE_OPS)
2432 {
2433 unsigned tmpl;
2434
2435 tmpl = lvl;
2436 lvl = nxtlvl;
2437 nxtlvl = tmpl;
2438 }
2439
2440 // TODO: Do we have to compute levels differently for argument lists and
2441 // all other lists?
2442 // https://github.com/dotnet/coreclr/issues/7095
2443 if (isListCallArgs)
2444 {
2445 if (level < lvl)
2446 {
2447 level = lvl;
2448 }
2449 }
2450 else
2451 {
2452 if (lvl < 1)
2453 {
2454 level = nxtlvl;
2455 }
2456 else if (lvl == nxtlvl)
2457 {
2458 level = lvl + 1;
2459 }
2460 else
2461 {
2462 level = lvl;
2463 }
2464 }
2465
2466 if (op1->gtCostEx != 0)
2467 {
2468 costEx += op1->gtCostEx;
2469 costEx += (callArgsInRegs || !isListCallArgs) ? 0 : IND_COST_EX;
2470 }
2471
2472 if (op1->gtCostSz != 0)
2473 {
2474 costSz += op1->gtCostSz;
2475#ifdef _TARGET_XARCH_
2476 if (callArgsInRegs) // push is smaller than mov to reg
2477#endif
2478 {
2479 costSz += 1;
2480 }
2481 }
2482
2483 list->SetCosts(costEx, costSz);
2484
2485 nxtlvl = level;
2486 }
2487
2488 return nxtlvl;
2489}
2490
2491//-----------------------------------------------------------------------------
2492// gtWalkOp: Traverse and mark an address expression
2493//
2494// Arguments:
2495// op1WB - An out parameter which is either the address expression, or one
2496// of its operands.
2497// op2WB - An out parameter which starts as either null or one of the operands
2498// of the address expression.
2499// base - The base address of the addressing mode, or null if 'constOnly' is false
2500// constOnly - True if we will only traverse into ADDs with constant op2.
2501//
2502// This routine is a helper routine for gtSetEvalOrder() and is used to identify the
2503// base and index nodes, which will be validated against those identified by
2504// genCreateAddrMode().
2505// It also marks the ADD nodes involved in the address expression with the
2506// GTF_ADDRMODE_NO_CSE flag which prevents them from being considered for CSE's.
2507//
2508// Its two output parameters are modified under the following conditions:
2509//
2510// It is called once with the original address expression as 'op1WB', and
2511// with 'constOnly' set to false. On this first invocation, *op1WB is always
2512// an ADD node, and it will consider the operands of the ADD even if its op2 is
2513// not a constant. However, when it encounters a non-constant or the base in the
2514// op2 position, it stops iterating. That operand is returned in the 'op2WB' out
2515// parameter, and will be considered on the third invocation of this method if
2516// it is an ADD.
2517//
2518// It is called the second time with the two operands of the original expression, in
2519// the original order, and the third time in reverse order. For these invocations
2520// 'constOnly' is true, so it will only traverse cascaded ADD nodes if they have a
2521// constant op2.
2522//
2523// The result, after three invocations, is that the values of the two out parameters
2524// correspond to the base and index in some fashion. This method doesn't attempt
2525// to determine or validate the scale or offset, if any.
2526//
2527// Assumptions (presumed to be ensured by genCreateAddrMode()):
2528// If an ADD has a constant operand, it is in the op2 position.
2529//
2530// Notes:
2531// This method, and its invocation sequence, are quite confusing, and since they
2532// were not originally well-documented, this specification is a possibly-imperfect
2533// reconstruction.
2534// The motivation for the handling of the NOP case is unclear.
2535// Note that 'op2WB' is only modified in the initial (!constOnly) case,
2536// or if a NOP is encountered in the op1 position.
2537//
2538void Compiler::gtWalkOp(GenTree** op1WB, GenTree** op2WB, GenTree* base, bool constOnly)
2539{
2540 GenTree* op1 = *op1WB;
2541 GenTree* op2 = *op2WB;
2542
2543 op1 = op1->gtEffectiveVal();
2544
2545 // Now we look for op1's with non-overflow GT_ADDs [of constants]
2546 while ((op1->gtOper == GT_ADD) && (!op1->gtOverflow()) && (!constOnly || (op1->gtOp.gtOp2->IsCnsIntOrI())))
2547 {
2548 // mark it with GTF_ADDRMODE_NO_CSE
2549 op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
2550
2551 if (!constOnly)
2552 {
2553 op2 = op1->gtOp.gtOp2;
2554 }
2555 op1 = op1->gtOp.gtOp1;
2556
2557 // If op1 is a GT_NOP then swap op1 and op2.
2558 // (Why? Also, presumably op2 is not a GT_NOP in this case?)
2559 if (op1->gtOper == GT_NOP)
2560 {
2561 GenTree* tmp;
2562
2563 tmp = op1;
2564 op1 = op2;
2565 op2 = tmp;
2566 }
2567
2568 if (!constOnly && ((op2 == base) || (!op2->IsCnsIntOrI())))
2569 {
2570 break;
2571 }
2572
2573 op1 = op1->gtEffectiveVal();
2574 }
2575
2576 *op1WB = op1;
2577 *op2WB = op2;
2578}
2579
2580#ifdef DEBUG
2581/*****************************************************************************
2582 * This is a workaround. It is to help implement an assert in gtSetEvalOrder() that the values
2583 * gtWalkOp() leaves in op1 and op2 correspond with the values of adr, idx, mul, and cns
2584 * that are returned by genCreateAddrMode(). It's essentially impossible to determine
2585 * what gtWalkOp() *should* return for all possible trees. This simply loosens one assert
2586 * to handle the following case:
2587
2588 indir int
2589 const(h) int 4 field
2590 + byref
2591 lclVar byref V00 this <-- op2
2592 comma byref <-- adr (base)
2593 indir byte
2594 lclVar byref V00 this
2595 + byref
2596 const int 2 <-- mul == 4
2597 << int <-- op1
2598 lclVar int V01 arg1 <-- idx
2599
2600 * Here, we are planning to generate the address mode [edx+4*eax], where eax = idx and edx = the GT_COMMA expression.
2601 * To check adr equivalence with op2, we need to walk down the GT_ADD tree just like gtWalkOp() does.
2602 */
2603GenTree* Compiler::gtWalkOpEffectiveVal(GenTree* op)
2604{
2605 for (;;)
2606 {
2607 op = op->gtEffectiveVal();
2608
2609 if ((op->gtOper != GT_ADD) || op->gtOverflow() || !op->gtOp.gtOp2->IsCnsIntOrI())
2610 {
2611 break;
2612 }
2613
2614 op = op->gtOp.gtOp1;
2615 }
2616
2617 return op;
2618}
2619#endif // DEBUG
2620
2621/*****************************************************************************
2622 *
2623 * Given a tree, set the gtCostEx and gtCostSz fields which
2624 * are used to measure the relative costs of the codegen of the tree
2625 *
2626 */
2627
2628void Compiler::gtPrepareCost(GenTree* tree)
2629{
2630 gtSetEvalOrder(tree);
2631}
2632
2633bool Compiler::gtIsLikelyRegVar(GenTree* tree)
2634{
2635 if (tree->gtOper != GT_LCL_VAR)
2636 {
2637 return false;
2638 }
2639
2640 assert(tree->gtLclVar.gtLclNum < lvaTableCnt);
2641 LclVarDsc* varDsc = lvaTable + tree->gtLclVar.gtLclNum;
2642
2643 if (varDsc->lvDoNotEnregister)
2644 {
2645 return false;
2646 }
2647
2648 // Be pessimistic if ref counts are not yet set up.
2649 //
2650 // Perhaps we should be optimistic though.
2651 // See notes in GitHub issue 18969.
2652 if (!lvaLocalVarRefCounted())
2653 {
2654 return false;
2655 }
2656
2657 if (varDsc->lvRefCntWtd() < (BB_UNITY_WEIGHT * 3))
2658 {
2659 return false;
2660 }
2661
2662#ifdef _TARGET_X86_
2663 if (varTypeIsFloating(tree->TypeGet()))
2664 return false;
2665 if (varTypeIsLong(tree->TypeGet()))
2666 return false;
2667#endif
2668
2669 return true;
2670}
2671
2672//------------------------------------------------------------------------
2673// gtCanSwapOrder: Returns true iff the secondNode can be swapped with firstNode.
2674//
2675// Arguments:
2676// firstNode - An operand of a tree that can have GTF_REVERSE_OPS set.
2677// secondNode - The other operand of the tree.
2678//
2679// Return Value:
2680// Returns a boolean indicating whether it is safe to reverse the execution
2681// order of the two trees, considering any exception, global effects, or
2682// ordering constraints.
2683//
2684bool Compiler::gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode)
2685{
2686 // Relative of order of global / side effects can't be swapped.
2687
2688 bool canSwap = true;
2689
2690 if (optValnumCSE_phase)
2691 {
2692 canSwap = optCSE_canSwap(firstNode, secondNode);
2693 }
2694
2695 // We cannot swap in the presence of special side effects such as GT_CATCH_ARG.
2696
2697 if (canSwap && (firstNode->gtFlags & GTF_ORDER_SIDEEFF))
2698 {
2699 canSwap = false;
2700 }
2701
2702 // When strict side effect order is disabled we allow GTF_REVERSE_OPS to be set
2703 // when one or both sides contains a GTF_CALL or GTF_EXCEPT.
2704 // Currently only the C and C++ languages allow non strict side effect order.
2705
2706 unsigned strictEffects = GTF_GLOB_EFFECT;
2707
2708 if (canSwap && (firstNode->gtFlags & strictEffects))
2709 {
2710 // op1 has side efects that can't be reordered.
2711 // Check for some special cases where we still may be able to swap.
2712
2713 if (secondNode->gtFlags & strictEffects)
2714 {
2715 // op2 has also has non reorderable side effects - can't swap.
2716 canSwap = false;
2717 }
2718 else
2719 {
2720 // No side effects in op2 - we can swap iff op1 has no way of modifying op2,
2721 // i.e. through byref assignments or calls or op2 is a constant.
2722
2723 if (firstNode->gtFlags & strictEffects & GTF_PERSISTENT_SIDE_EFFECTS)
2724 {
2725 // We have to be conservative - can swap iff op2 is constant.
2726 if (!secondNode->OperIsConst())
2727 {
2728 canSwap = false;
2729 }
2730 }
2731 }
2732 }
2733 return canSwap;
2734}
2735
2736/*****************************************************************************
2737 *
2738 * Given a tree, figure out the order in which its sub-operands should be
2739 * evaluated. If the second operand of a binary operator is more expensive
2740 * than the first operand, then try to swap the operand trees. Updates the
2741 * GTF_REVERSE_OPS bit if necessary in this case.
2742 *
2743 * Returns the Sethi 'complexity' estimate for this tree (the higher
2744 * the number, the higher is the tree's resources requirement).
2745 *
2746 * This function sets:
2747 * 1. gtCostEx to the execution complexity estimate
2748 * 2. gtCostSz to the code size estimate
2749 * 3. Sometimes sets GTF_ADDRMODE_NO_CSE on nodes in the tree.
2750 * 4. DEBUG-only: clears GTF_DEBUG_NODE_MORPHED.
2751 */
2752
2753#ifdef _PREFAST_
2754#pragma warning(push)
2755#pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
2756#endif
2757unsigned Compiler::gtSetEvalOrder(GenTree* tree)
2758{
2759 assert(tree);
2760 assert(tree->gtOper != GT_STMT);
2761
2762#ifdef DEBUG
2763 /* Clear the GTF_DEBUG_NODE_MORPHED flag as well */
2764 tree->gtDebugFlags &= ~GTF_DEBUG_NODE_MORPHED;
2765#endif
2766
2767 /* Is this a FP value? */
2768
2769 bool isflt = varTypeIsFloating(tree->TypeGet());
2770
2771 /* Figure out what kind of a node we have */
2772
2773 const genTreeOps oper = tree->OperGet();
2774 const unsigned kind = tree->OperKind();
2775
2776 /* Assume no fixed registers will be trashed */
2777
2778 unsigned level;
2779 int costEx;
2780 int costSz;
2781
2782#ifdef DEBUG
2783 costEx = -1;
2784 costSz = -1;
2785#endif
2786
2787 /* Is this a constant or a leaf node? */
2788
2789 if (kind & (GTK_LEAF | GTK_CONST))
2790 {
2791 switch (oper)
2792 {
2793#ifdef _TARGET_ARM_
2794 case GT_CNS_LNG:
2795 costSz = 9;
2796 costEx = 4;
2797 goto COMMON_CNS;
2798
2799 case GT_CNS_STR:
2800 // Uses movw/movt
2801 costSz = 7;
2802 costEx = 3;
2803 goto COMMON_CNS;
2804
2805 case GT_CNS_INT:
2806 {
2807 // If the constant is a handle then it will need to have a relocation
2808 // applied to it.
2809 // Any constant that requires a reloc must use the movw/movt sequence
2810 //
2811 GenTreeIntConCommon* con = tree->AsIntConCommon();
2812
2813 if (con->ImmedValNeedsReloc(this) ||
2814 !codeGen->validImmForInstr(INS_mov, (target_ssize_t)tree->gtIntCon.gtIconVal))
2815 {
2816 // Uses movw/movt
2817 costSz = 7;
2818 costEx = 3;
2819 }
2820 else if (((unsigned)tree->gtIntCon.gtIconVal) <= 0x00ff)
2821 {
2822 // mov Rd, <const8>
2823 costSz = 1;
2824 costEx = 1;
2825 }
2826 else
2827 {
2828 // Uses movw/mvn
2829 costSz = 3;
2830 costEx = 1;
2831 }
2832 goto COMMON_CNS;
2833 }
2834
2835#elif defined _TARGET_XARCH_
2836
2837 case GT_CNS_LNG:
2838 costSz = 10;
2839 costEx = 3;
2840 goto COMMON_CNS;
2841
2842 case GT_CNS_STR:
2843 costSz = 4;
2844 costEx = 1;
2845 goto COMMON_CNS;
2846
2847 case GT_CNS_INT:
2848 {
2849 // If the constant is a handle then it will need to have a relocation
2850 // applied to it.
2851 //
2852 GenTreeIntConCommon* con = tree->AsIntConCommon();
2853
2854 bool iconNeedsReloc = con->ImmedValNeedsReloc(this);
2855
2856 if (!iconNeedsReloc && con->FitsInI8())
2857 {
2858 costSz = 1;
2859 costEx = 1;
2860 }
2861#if defined(_TARGET_AMD64_)
2862 else if (iconNeedsReloc || !con->FitsInI32())
2863 {
2864 costSz = 10;
2865 costEx = 3;
2866 }
2867#endif // _TARGET_AMD64_
2868 else
2869 {
2870 costSz = 4;
2871 costEx = 1;
2872 }
2873 goto COMMON_CNS;
2874 }
2875
2876#elif defined(_TARGET_ARM64_)
2877 case GT_CNS_LNG:
2878 case GT_CNS_STR:
2879 case GT_CNS_INT:
2880 // TODO-ARM64-NYI: Need cost estimates.
2881 costSz = 1;
2882 costEx = 1;
2883 goto COMMON_CNS;
2884
2885#else
2886 case GT_CNS_LNG:
2887 case GT_CNS_STR:
2888 case GT_CNS_INT:
2889#error "Unknown _TARGET_"
2890#endif
2891
2892 COMMON_CNS:
2893 /*
2894 Note that some code below depends on constants always getting
2895 moved to be the second operand of a binary operator. This is
2896 easily accomplished by giving constants a level of 0, which
2897 we do on the next line. If you ever decide to change this, be
2898 aware that unless you make other arrangements for integer
2899 constants to be moved, stuff will break.
2900 */
2901
2902 level = 0;
2903 break;
2904
2905 case GT_CNS_DBL:
2906 level = 0;
2907 /* We use fldz and fld1 to load 0.0 and 1.0, but all other */
2908 /* floating point constants are loaded using an indirection */
2909 if ((*((__int64*)&(tree->gtDblCon.gtDconVal)) == 0) ||
2910 (*((__int64*)&(tree->gtDblCon.gtDconVal)) == I64(0x3ff0000000000000)))
2911 {
2912 costEx = 1;
2913 costSz = 1;
2914 }
2915 else
2916 {
2917 costEx = IND_COST_EX;
2918 costSz = 4;
2919 }
2920 break;
2921
2922 case GT_LCL_VAR:
2923 level = 1;
2924 if (gtIsLikelyRegVar(tree))
2925 {
2926 costEx = 1;
2927 costSz = 1;
2928 /* Sign-extend and zero-extend are more expensive to load */
2929 if (lvaTable[tree->gtLclVar.gtLclNum].lvNormalizeOnLoad())
2930 {
2931 costEx += 1;
2932 costSz += 1;
2933 }
2934 }
2935 else
2936 {
2937 costEx = IND_COST_EX;
2938 costSz = 2;
2939 /* Sign-extend and zero-extend are more expensive to load */
2940 if (varTypeIsSmall(tree->TypeGet()))
2941 {
2942 costEx += 1;
2943 costSz += 1;
2944 }
2945 }
2946#if defined(_TARGET_AMD64_)
2947 // increase costSz for floating point locals
2948 if (isflt)
2949 {
2950 costSz += 1;
2951 if (!gtIsLikelyRegVar(tree))
2952 {
2953 costSz += 1;
2954 }
2955 }
2956#endif
2957 break;
2958
2959 case GT_CLS_VAR:
2960#ifdef _TARGET_ARM_
2961 // We generate movw/movt/ldr
2962 level = 1;
2963 costEx = 3 + IND_COST_EX; // 6
2964 costSz = 4 + 4 + 2; // 10
2965 break;
2966#endif
2967 case GT_LCL_FLD:
2968 level = 1;
2969 costEx = IND_COST_EX;
2970 costSz = 4;
2971 if (varTypeIsSmall(tree->TypeGet()))
2972 {
2973 costEx += 1;
2974 costSz += 1;
2975 }
2976 break;
2977
2978 case GT_PHI_ARG:
2979 case GT_ARGPLACE:
2980 level = 0;
2981 costEx = 0;
2982 costSz = 0;
2983 break;
2984
2985 default:
2986 level = 1;
2987 costEx = 1;
2988 costSz = 1;
2989 break;
2990 }
2991 goto DONE;
2992 }
2993
2994 /* Is it a 'simple' unary/binary operator? */
2995
2996 if (kind & GTK_SMPOP)
2997 {
2998 int lvlb; // preference for op2
2999 unsigned lvl2; // scratch variable
3000
3001 GenTree* op1 = tree->gtOp.gtOp1;
3002 GenTree* op2 = tree->gtGetOp2IfPresent();
3003
3004 costEx = 0;
3005 costSz = 0;
3006
3007 if (tree->OperIsAddrMode())
3008 {
3009 if (op1 == nullptr)
3010 {
3011 op1 = op2;
3012 op2 = nullptr;
3013 }
3014 }
3015
3016 /* Check for a nilary operator */
3017
3018 if (op1 == nullptr)
3019 {
3020 assert(op2 == nullptr);
3021
3022 level = 0;
3023
3024 goto DONE;
3025 }
3026
3027 /* Is this a unary operator? */
3028
3029 if (op2 == nullptr)
3030 {
3031 /* Process the operand of the operator */
3032
3033 /* Most Unary ops have costEx of 1 */
3034 costEx = 1;
3035 costSz = 1;
3036
3037 level = gtSetEvalOrder(op1);
3038
3039 /* Special handling for some operators */
3040
3041 switch (oper)
3042 {
3043 case GT_JTRUE:
3044 costEx = 2;
3045 costSz = 2;
3046 break;
3047
3048 case GT_SWITCH:
3049 costEx = 10;
3050 costSz = 5;
3051 break;
3052
3053 case GT_CAST:
3054#if defined(_TARGET_ARM_)
3055 costEx = 1;
3056 costSz = 1;
3057 if (isflt || varTypeIsFloating(op1->TypeGet()))
3058 {
3059 costEx = 3;
3060 costSz = 4;
3061 }
3062#elif defined(_TARGET_ARM64_)
3063 costEx = 1;
3064 costSz = 2;
3065 if (isflt || varTypeIsFloating(op1->TypeGet()))
3066 {
3067 costEx = 2;
3068 costSz = 4;
3069 }
3070#elif defined(_TARGET_XARCH_)
3071 costEx = 1;
3072 costSz = 2;
3073
3074 if (isflt || varTypeIsFloating(op1->TypeGet()))
3075 {
3076 /* cast involving floats always go through memory */
3077 costEx = IND_COST_EX * 2;
3078 costSz = 6;
3079 }
3080#else
3081#error "Unknown _TARGET_"
3082#endif
3083
3084 /* Overflow casts are a lot more expensive */
3085 if (tree->gtOverflow())
3086 {
3087 costEx += 6;
3088 costSz += 6;
3089 }
3090
3091 break;
3092
3093 case GT_LIST:
3094 case GT_FIELD_LIST:
3095 case GT_NOP:
3096 costEx = 0;
3097 costSz = 0;
3098 break;
3099
3100 case GT_INTRINSIC:
3101 // GT_INTRINSIC intrinsics Sin, Cos, Sqrt, Abs ... have higher costs.
3102 // TODO: tune these costs target specific as some of these are
3103 // target intrinsics and would cost less to generate code.
3104 switch (tree->gtIntrinsic.gtIntrinsicId)
3105 {
3106 default:
3107 assert(!"missing case for gtIntrinsicId");
3108 costEx = 12;
3109 costSz = 12;
3110 break;
3111
3112 case CORINFO_INTRINSIC_Sin:
3113 case CORINFO_INTRINSIC_Cos:
3114 case CORINFO_INTRINSIC_Sqrt:
3115 case CORINFO_INTRINSIC_Cbrt:
3116 case CORINFO_INTRINSIC_Cosh:
3117 case CORINFO_INTRINSIC_Sinh:
3118 case CORINFO_INTRINSIC_Tan:
3119 case CORINFO_INTRINSIC_Tanh:
3120 case CORINFO_INTRINSIC_Asin:
3121 case CORINFO_INTRINSIC_Asinh:
3122 case CORINFO_INTRINSIC_Acos:
3123 case CORINFO_INTRINSIC_Acosh:
3124 case CORINFO_INTRINSIC_Atan:
3125 case CORINFO_INTRINSIC_Atanh:
3126 case CORINFO_INTRINSIC_Atan2:
3127 case CORINFO_INTRINSIC_Log10:
3128 case CORINFO_INTRINSIC_Pow:
3129 case CORINFO_INTRINSIC_Exp:
3130 case CORINFO_INTRINSIC_Ceiling:
3131 case CORINFO_INTRINSIC_Floor:
3132 case CORINFO_INTRINSIC_Object_GetType:
3133 // Giving intrinsics a large fixed execution cost is because we'd like to CSE
3134 // them, even if they are implemented by calls. This is different from modeling
3135 // user calls since we never CSE user calls.
3136 costEx = 36;
3137 costSz = 4;
3138 break;
3139
3140 case CORINFO_INTRINSIC_Abs:
3141 costEx = 5;
3142 costSz = 15;
3143 break;
3144
3145 case CORINFO_INTRINSIC_Round:
3146 costEx = 3;
3147 costSz = 4;
3148 break;
3149 }
3150 level++;
3151 break;
3152
3153 case GT_NOT:
3154 case GT_NEG:
3155 // We need to ensure that -x is evaluated before x or else
3156 // we get burned while adjusting genFPstkLevel in x*-x where
3157 // the rhs x is the last use of the enregistered x.
3158 //
3159 // Even in the integer case we want to prefer to
3160 // evaluate the side without the GT_NEG node, all other things
3161 // being equal. Also a GT_NOT requires a scratch register
3162
3163 level++;
3164 break;
3165
3166 case GT_ADDR:
3167
3168 costEx = 0;
3169 costSz = 1;
3170
3171 // If we have a GT_ADDR of an GT_IND we can just copy the costs from indOp1
3172 if (op1->OperGet() == GT_IND)
3173 {
3174 GenTree* indOp1 = op1->gtOp.gtOp1;
3175 costEx = indOp1->gtCostEx;
3176 costSz = indOp1->gtCostSz;
3177 }
3178 break;
3179
3180 case GT_ARR_LENGTH:
3181 level++;
3182
3183 /* Array Len should be the same as an indirections, which have a costEx of IND_COST_EX */
3184 costEx = IND_COST_EX - 1;
3185 costSz = 2;
3186 break;
3187
3188 case GT_MKREFANY:
3189 case GT_OBJ:
3190 // We estimate the cost of a GT_OBJ or GT_MKREFANY to be two loads (GT_INDs)
3191 costEx = 2 * IND_COST_EX;
3192 costSz = 2 * 2;
3193 break;
3194
3195 case GT_BOX:
3196 // We estimate the cost of a GT_BOX to be two stores (GT_INDs)
3197 costEx = 2 * IND_COST_EX;
3198 costSz = 2 * 2;
3199 break;
3200
3201 case GT_BLK:
3202 case GT_IND:
3203
3204 /* An indirection should always have a non-zero level.
3205 * Only constant leaf nodes have level 0.
3206 */
3207
3208 if (level == 0)
3209 {
3210 level = 1;
3211 }
3212
3213 /* Indirections have a costEx of IND_COST_EX */
3214 costEx = IND_COST_EX;
3215 costSz = 2;
3216
3217 /* If we have to sign-extend or zero-extend, bump the cost */
3218 if (varTypeIsSmall(tree->TypeGet()))
3219 {
3220 costEx += 1;
3221 costSz += 1;
3222 }
3223
3224 if (isflt)
3225 {
3226 if (tree->TypeGet() == TYP_DOUBLE)
3227 {
3228 costEx += 1;
3229 }
3230#ifdef _TARGET_ARM_
3231 costSz += 2;
3232#endif // _TARGET_ARM_
3233 }
3234
3235 // Can we form an addressing mode with this indirection?
3236 // TODO-CQ: Consider changing this to op1->gtEffectiveVal() to take into account
3237 // addressing modes hidden under a comma node.
3238
3239 if (op1->gtOper == GT_ADD)
3240 {
3241 bool rev;
3242#if SCALED_ADDR_MODES
3243 unsigned mul;
3244#endif // SCALED_ADDR_MODES
3245 ssize_t cns;
3246 GenTree* base;
3247 GenTree* idx;
3248
3249 // See if we can form a complex addressing mode.
3250
3251 GenTree* addr = op1->gtEffectiveVal();
3252
3253 bool doAddrMode = true;
3254 // See if we can form a complex addressing mode.
3255 // Always use an addrMode for an array index indirection.
3256 // TODO-1stClassStructs: Always do this, but first make sure it's
3257 // done in Lowering as well.
3258 if ((tree->gtFlags & GTF_IND_ARR_INDEX) == 0)
3259 {
3260 if (tree->TypeGet() == TYP_STRUCT)
3261 {
3262 doAddrMode = false;
3263 }
3264 else if (varTypeIsStruct(tree))
3265 {
3266 // This is a heuristic attempting to match prior behavior when indirections
3267 // under a struct assignment would not be considered for addressing modes.
3268 if (compCurStmt != nullptr)
3269 {
3270 GenTree* expr = compCurStmt->gtStmt.gtStmtExpr;
3271 if ((expr->OperGet() == GT_ASG) &&
3272 ((expr->gtGetOp1() == tree) || (expr->gtGetOp2() == tree)))
3273 {
3274 doAddrMode = false;
3275 }
3276 }
3277 }
3278 }
3279 if ((doAddrMode) &&
3280 codeGen->genCreateAddrMode(addr, // address
3281 false, // fold
3282 &rev, // reverse ops
3283 &base, // base addr
3284 &idx, // index val
3285#if SCALED_ADDR_MODES
3286 &mul, // scaling
3287#endif // SCALED_ADDR_MODES
3288 &cns)) // displacement
3289 {
3290 // We can form a complex addressing mode, so mark each of the interior
3291 // nodes with GTF_ADDRMODE_NO_CSE and calculate a more accurate cost.
3292
3293 addr->gtFlags |= GTF_ADDRMODE_NO_CSE;
3294#ifdef _TARGET_XARCH_
3295 // addrmodeCount is the count of items that we used to form
3296 // an addressing mode. The maximum value is 4 when we have
3297 // all of these: { base, idx, cns, mul }
3298 //
3299 unsigned addrmodeCount = 0;
3300 if (base)
3301 {
3302 costEx += base->gtCostEx;
3303 costSz += base->gtCostSz;
3304 addrmodeCount++;
3305 }
3306
3307 if (idx)
3308 {
3309 costEx += idx->gtCostEx;
3310 costSz += idx->gtCostSz;
3311 addrmodeCount++;
3312 }
3313
3314 if (cns)
3315 {
3316 if (((signed char)cns) == ((int)cns))
3317 {
3318 costSz += 1;
3319 }
3320 else
3321 {
3322 costSz += 4;
3323 }
3324 addrmodeCount++;
3325 }
3326 if (mul)
3327 {
3328 addrmodeCount++;
3329 }
3330 // When we form a complex addressing mode we can reduced the costs
3331 // associated with the interior GT_ADD and GT_LSH nodes:
3332 //
3333 // GT_ADD -- reduce this interior GT_ADD by (-3,-3)
3334 // / \ --
3335 // GT_ADD 'cns' -- reduce this interior GT_ADD by (-2,-2)
3336 // / \ --
3337 // 'base' GT_LSL -- reduce this interior GT_LSL by (-1,-1)
3338 // / \ --
3339 // 'idx' 'mul'
3340 //
3341 if (addrmodeCount > 1)
3342 {
3343 // The number of interior GT_ADD and GT_LSL will always be one less than addrmodeCount
3344 //
3345 addrmodeCount--;
3346
3347 GenTree* tmp = addr;
3348 while (addrmodeCount > 0)
3349 {
3350 // decrement the gtCosts for the interior GT_ADD or GT_LSH node by the remaining
3351 // addrmodeCount
3352 tmp->SetCosts(tmp->gtCostEx - addrmodeCount, tmp->gtCostSz - addrmodeCount);
3353
3354 addrmodeCount--;
3355 if (addrmodeCount > 0)
3356 {
3357 GenTree* tmpOp1 = tmp->gtOp.gtOp1;
3358 GenTree* tmpOp2 = tmp->gtGetOp2();
3359 assert(tmpOp2 != nullptr);
3360
3361 if ((tmpOp1 != base) && (tmpOp1->OperGet() == GT_ADD))
3362 {
3363 tmp = tmpOp1;
3364 }
3365 else if (tmpOp2->OperGet() == GT_LSH)
3366 {
3367 tmp = tmpOp2;
3368 }
3369 else if (tmpOp1->OperGet() == GT_LSH)
3370 {
3371 tmp = tmpOp1;
3372 }
3373 else if (tmpOp2->OperGet() == GT_ADD)
3374 {
3375 tmp = tmpOp2;
3376 }
3377 else
3378 {
3379 // We can very rarely encounter a tree that has a GT_COMMA node
3380 // that is difficult to walk, so we just early out without decrementing.
3381 addrmodeCount = 0;
3382 }
3383 }
3384 }
3385 }
3386#elif defined _TARGET_ARM_
3387 if (base)
3388 {
3389 costEx += base->gtCostEx;
3390 costSz += base->gtCostSz;
3391 if ((base->gtOper == GT_LCL_VAR) && ((idx == NULL) || (cns == 0)))
3392 {
3393 costSz -= 1;
3394 }
3395 }
3396
3397 if (idx)
3398 {
3399 costEx += idx->gtCostEx;
3400 costSz += idx->gtCostSz;
3401 if (mul > 0)
3402 {
3403 costSz += 2;
3404 }
3405 }
3406
3407 if (cns)
3408 {
3409 if (cns >= 128) // small offsets fits into a 16-bit instruction
3410 {
3411 if (cns < 4096) // medium offsets require a 32-bit instruction
3412 {
3413 if (!isflt)
3414 costSz += 2;
3415 }
3416 else
3417 {
3418 costEx += 2; // Very large offsets require movw/movt instructions
3419 costSz += 8;
3420 }
3421 }
3422 }
3423#elif defined _TARGET_ARM64_
3424 if (base)
3425 {
3426 costEx += base->gtCostEx;
3427 costSz += base->gtCostSz;
3428 }
3429
3430 if (idx)
3431 {
3432 costEx += idx->gtCostEx;
3433 costSz += idx->gtCostSz;
3434 }
3435
3436 if (cns != 0)
3437 {
3438 if (cns >= (4096 * genTypeSize(tree->TypeGet())))
3439 {
3440 costEx += 1;
3441 costSz += 4;
3442 }
3443 }
3444#else
3445#error "Unknown _TARGET_"
3446#endif
3447
3448 assert(addr->gtOper == GT_ADD);
3449 assert(!addr->gtOverflow());
3450 assert(op2 == nullptr);
3451 assert(mul != 1);
3452
3453 // If we have an addressing mode, we have one of:
3454 // [base + cns]
3455 // [ idx * mul ] // mul >= 2, else we would use base instead of idx
3456 // [ idx * mul + cns] // mul >= 2, else we would use base instead of idx
3457 // [base + idx * mul ] // mul can be 0, 2, 4, or 8
3458 // [base + idx * mul + cns] // mul can be 0, 2, 4, or 8
3459 // Note that mul == 0 is semantically equivalent to mul == 1.
3460 // Note that cns can be zero.
3461 CLANG_FORMAT_COMMENT_ANCHOR;
3462
3463#if SCALED_ADDR_MODES
3464 assert((base != nullptr) || (idx != nullptr && mul >= 2));
3465#else
3466 assert(base != NULL);
3467#endif
3468
3469 INDEBUG(GenTree* op1Save = addr);
3470
3471 // Walk 'addr' identifying non-overflow ADDs that will be part of the address mode.
3472 // Note that we will be modifying 'op1' and 'op2' so that eventually they should
3473 // map to the base and index.
3474 op1 = addr;
3475 gtWalkOp(&op1, &op2, base, false);
3476
3477 // op1 and op2 are now descendents of the root GT_ADD of the addressing mode.
3478 assert(op1 != op1Save);
3479 assert(op2 != nullptr);
3480
3481 // Walk the operands again (the third operand is unused in this case).
3482 // This time we will only consider adds with constant op2's, since
3483 // we have already found either a non-ADD op1 or a non-constant op2.
3484 gtWalkOp(&op1, &op2, nullptr, true);
3485
3486#if defined(_TARGET_XARCH_)
3487 // For XARCH we will fold GT_ADDs in the op2 position into the addressing mode, so we call
3488 // gtWalkOp on both operands of the original GT_ADD.
3489 // This is not done for ARMARCH. Though the stated reason is that we don't try to create a
3490 // scaled index, in fact we actually do create them (even base + index*scale + offset).
3491
3492 // At this point, 'op2' may itself be an ADD of a constant that should be folded
3493 // into the addressing mode.
3494 // Walk op2 looking for non-overflow GT_ADDs of constants.
3495 gtWalkOp(&op2, &op1, nullptr, true);
3496#endif // defined(_TARGET_XARCH_)
3497
3498 // OK we are done walking the tree
3499 // Now assert that op1 and op2 correspond with base and idx
3500 // in one of the several acceptable ways.
3501
3502 // Note that sometimes op1/op2 is equal to idx/base
3503 // and other times op1/op2 is a GT_COMMA node with
3504 // an effective value that is idx/base
3505
3506 if (mul > 1)
3507 {
3508 if ((op1 != base) && (op1->gtOper == GT_LSH))
3509 {
3510 op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3511 if (op1->gtOp.gtOp1->gtOper == GT_MUL)
3512 {
3513 op1->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3514 }
3515 assert((base == nullptr) || (op2 == base) ||
3516 (op2->gtEffectiveVal() == base->gtEffectiveVal()) ||
3517 (gtWalkOpEffectiveVal(op2) == gtWalkOpEffectiveVal(base)));
3518 }
3519 else
3520 {
3521 assert(op2);
3522 assert(op2->gtOper == GT_LSH || op2->gtOper == GT_MUL);
3523 op2->gtFlags |= GTF_ADDRMODE_NO_CSE;
3524 // We may have eliminated multiple shifts and multiplies in the addressing mode,
3525 // so navigate down through them to get to "idx".
3526 GenTree* op2op1 = op2->gtOp.gtOp1;
3527 while ((op2op1->gtOper == GT_LSH || op2op1->gtOper == GT_MUL) && op2op1 != idx)
3528 {
3529 op2op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3530 op2op1 = op2op1->gtOp.gtOp1;
3531 }
3532 assert(op1->gtEffectiveVal() == base);
3533 assert(op2op1 == idx);
3534 }
3535 }
3536 else
3537 {
3538 assert(mul == 0);
3539
3540 if ((op1 == idx) || (op1->gtEffectiveVal() == idx))
3541 {
3542 if (idx != nullptr)
3543 {
3544 if ((op1->gtOper == GT_MUL) || (op1->gtOper == GT_LSH))
3545 {
3546 if ((op1->gtOp.gtOp1->gtOper == GT_NOP) ||
3547 (op1->gtOp.gtOp1->gtOper == GT_MUL &&
3548 op1->gtOp.gtOp1->gtOp.gtOp1->gtOper == GT_NOP))
3549 {
3550 op1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3551 if (op1->gtOp.gtOp1->gtOper == GT_MUL)
3552 {
3553 op1->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3554 }
3555 }
3556 }
3557 }
3558 assert((op2 == base) || (op2->gtEffectiveVal() == base));
3559 }
3560 else if ((op1 == base) || (op1->gtEffectiveVal() == base))
3561 {
3562 if (idx != nullptr)
3563 {
3564 assert(op2);
3565 if ((op2->gtOper == GT_MUL) || (op2->gtOper == GT_LSH))
3566 {
3567 if ((op2->gtOp.gtOp1->gtOper == GT_NOP) ||
3568 (op2->gtOp.gtOp1->gtOper == GT_MUL &&
3569 op2->gtOp.gtOp1->gtOp.gtOp1->gtOper == GT_NOP))
3570 {
3571 op2->gtFlags |= GTF_ADDRMODE_NO_CSE;
3572 if (op2->gtOp.gtOp1->gtOper == GT_MUL)
3573 {
3574 op2->gtOp.gtOp1->gtFlags |= GTF_ADDRMODE_NO_CSE;
3575 }
3576 }
3577 }
3578 assert((op2 == idx) || (op2->gtEffectiveVal() == idx));
3579 }
3580 }
3581 else
3582 {
3583 // op1 isn't base or idx. Is this possible? Or should there be an assert?
3584 }
3585 }
3586 goto DONE;
3587
3588 } // end if (genCreateAddrMode(...))
3589
3590 } // end if (op1->gtOper == GT_ADD)
3591 else if (gtIsLikelyRegVar(op1))
3592 {
3593 /* Indirection of an enregister LCL_VAR, don't increase costEx/costSz */
3594 goto DONE;
3595 }
3596#ifdef _TARGET_XARCH_
3597 else if (op1->IsCnsIntOrI())
3598 {
3599 // Indirection of a CNS_INT, subtract 1 from costEx
3600 // makes costEx 3 for x86 and 4 for amd64
3601 //
3602 costEx += (op1->gtCostEx - 1);
3603 costSz += op1->gtCostSz;
3604 goto DONE;
3605 }
3606#endif
3607 break;
3608
3609 default:
3610 break;
3611 }
3612 costEx += op1->gtCostEx;
3613 costSz += op1->gtCostSz;
3614 goto DONE;
3615 }
3616
3617 /* Binary operator - check for certain special cases */
3618
3619 lvlb = 0;
3620
3621 /* Default Binary ops have a cost of 1,1 */
3622 costEx = 1;
3623 costSz = 1;
3624
3625#ifdef _TARGET_ARM_
3626 if (isflt)
3627 {
3628 costSz += 2;
3629 }
3630#endif
3631#ifndef _TARGET_64BIT_
3632 if (varTypeIsLong(op1->TypeGet()))
3633 {
3634 /* Operations on longs are more expensive */
3635 costEx += 3;
3636 costSz += 3;
3637 }
3638#endif
3639 switch (oper)
3640 {
3641 case GT_MOD:
3642 case GT_UMOD:
3643
3644 /* Modulo by a power of 2 is easy */
3645
3646 if (op2->IsCnsIntOrI())
3647 {
3648 size_t ival = op2->gtIntConCommon.IconValue();
3649
3650 if (ival > 0 && ival == genFindLowestBit(ival))
3651 {
3652 break;
3653 }
3654 }
3655
3656 __fallthrough;
3657
3658 case GT_DIV:
3659 case GT_UDIV:
3660
3661 if (isflt)
3662 {
3663 /* fp division is very expensive to execute */
3664 costEx = 36; // TYP_DOUBLE
3665 costSz += 3;
3666 }
3667 else
3668 {
3669 /* integer division is also very expensive */
3670 costEx = 20;
3671 costSz += 2;
3672
3673 // Encourage the first operand to be evaluated (into EAX/EDX) first */
3674 lvlb -= 3;
3675 }
3676 break;
3677
3678 case GT_MUL:
3679
3680 if (isflt)
3681 {
3682 /* FP multiplication instructions are more expensive */
3683 costEx += 4;
3684 costSz += 3;
3685 }
3686 else
3687 {
3688 /* Integer multiplication instructions are more expensive */
3689 costEx += 3;
3690 costSz += 2;
3691
3692 if (tree->gtOverflow())
3693 {
3694 /* Overflow check are more expensive */
3695 costEx += 3;
3696 costSz += 3;
3697 }
3698
3699#ifdef _TARGET_X86_
3700 if ((tree->gtType == TYP_LONG) || tree->gtOverflow())
3701 {
3702 /* We use imulEAX for TYP_LONG and overflow multiplications */
3703 // Encourage the first operand to be evaluated (into EAX/EDX) first */
3704 lvlb -= 4;
3705
3706 /* The 64-bit imul instruction costs more */
3707 costEx += 4;
3708 }
3709#endif // _TARGET_X86_
3710 }
3711 break;
3712
3713 case GT_ADD:
3714 case GT_SUB:
3715 if (isflt)
3716 {
3717 /* FP instructions are a bit more expensive */
3718 costEx += 4;
3719 costSz += 3;
3720 break;
3721 }
3722
3723 /* Overflow check are more expensive */
3724 if (tree->gtOverflow())
3725 {
3726 costEx += 3;
3727 costSz += 3;
3728 }
3729 break;
3730
3731 case GT_COMMA:
3732
3733 /* Comma tosses the result of the left operand */
3734 gtSetEvalOrder(op1);
3735 level = gtSetEvalOrder(op2);
3736
3737 /* GT_COMMA cost is the sum of op1 and op2 costs */
3738 costEx = (op1->gtCostEx + op2->gtCostEx);
3739 costSz = (op1->gtCostSz + op2->gtCostSz);
3740
3741 goto DONE;
3742
3743 case GT_COLON:
3744
3745 level = gtSetEvalOrder(op1);
3746 lvl2 = gtSetEvalOrder(op2);
3747
3748 if (level < lvl2)
3749 {
3750 level = lvl2;
3751 }
3752 else if (level == lvl2)
3753 {
3754 level += 1;
3755 }
3756
3757 costEx = op1->gtCostEx + op2->gtCostEx;
3758 costSz = op1->gtCostSz + op2->gtCostSz;
3759
3760 goto DONE;
3761
3762 case GT_LIST:
3763 case GT_FIELD_LIST:
3764 {
3765 const bool isListCallArgs = false;
3766 const bool callArgsInRegs = false;
3767 return gtSetListOrder(tree, isListCallArgs, callArgsInRegs);
3768 }
3769
3770 case GT_ASG:
3771 /* Assignments need a bit of special handling */
3772 /* Process the target */
3773 level = gtSetEvalOrder(op1);
3774
3775 if (gtIsLikelyRegVar(op1))
3776 {
3777 assert(lvlb == 0);
3778 lvl2 = gtSetEvalOrder(op2);
3779
3780 /* Assignment to an enregistered LCL_VAR */
3781 costEx = op2->gtCostEx;
3782 costSz = max(3, op2->gtCostSz); // 3 is an estimate for a reg-reg assignment
3783 goto DONE_OP1_AFTER_COST;
3784 }
3785 goto DONE_OP1;
3786
3787 default:
3788 break;
3789 }
3790
3791 /* Process the sub-operands */
3792
3793 level = gtSetEvalOrder(op1);
3794 if (lvlb < 0)
3795 {
3796 level -= lvlb; // lvlb is negative, so this increases level
3797 lvlb = 0;
3798 }
3799
3800 DONE_OP1:
3801 assert(lvlb >= 0);
3802 lvl2 = gtSetEvalOrder(op2) + lvlb;
3803
3804 costEx += (op1->gtCostEx + op2->gtCostEx);
3805 costSz += (op1->gtCostSz + op2->gtCostSz);
3806
3807 DONE_OP1_AFTER_COST:
3808
3809 bool bReverseInAssignment = false;
3810 if (oper == GT_ASG)
3811 {
3812 GenTree* op1Val = op1;
3813
3814 // Skip over the GT_IND/GT_ADDR tree (if one exists)
3815 //
3816 if ((op1->gtOper == GT_IND) && (op1->gtOp.gtOp1->gtOper == GT_ADDR))
3817 {
3818 op1Val = op1->gtOp.gtOp1->gtOp.gtOp1;
3819 }
3820
3821 switch (op1Val->gtOper)
3822 {
3823 case GT_IND:
3824 case GT_BLK:
3825 case GT_OBJ:
3826 case GT_DYN_BLK:
3827
3828 // In an indirection, the destination address is evaluated prior to the source.
3829 // If we have any side effects on the target indirection,
3830 // we have to evaluate op1 first.
3831 // However, if the LHS is a lclVar address, SSA relies on using evaluation order for its
3832 // renaming, and therefore the RHS must be evaluated first.
3833 // If we have an assignment involving a lclVar address, the LHS may be marked as having
3834 // side-effects.
3835 // However the side-effects won't require that we evaluate the LHS address first:
3836 // - The GTF_GLOB_REF might have been conservatively set on a FIELD of a local.
3837 // - The local might be address-exposed, but that side-effect happens at the actual assignment (not
3838 // when its address is "evaluated") so it doesn't change the side effect to "evaluate" the address
3839 // after the RHS (note that in this case it won't be renamed by SSA anyway, but the reordering is
3840 // safe).
3841 //
3842 if (op1Val->AsIndir()->Addr()->IsLocalAddrExpr())
3843 {
3844 bReverseInAssignment = true;
3845 tree->gtFlags |= GTF_REVERSE_OPS;
3846 break;
3847 }
3848 if (op1Val->AsIndir()->Addr()->gtFlags & GTF_ALL_EFFECT)
3849 {
3850 break;
3851 }
3852
3853 // In case op2 assigns to a local var that is used in op1Val, we have to evaluate op1Val first.
3854 if (op2->gtFlags & GTF_ASG)
3855 {
3856 break;
3857 }
3858
3859 // If op2 is simple then evaluate op1 first
3860
3861 if (op2->OperKind() & GTK_LEAF)
3862 {
3863 break;
3864 }
3865
3866 // fall through and set GTF_REVERSE_OPS
3867
3868 case GT_LCL_VAR:
3869 case GT_LCL_FLD:
3870
3871 // We evaluate op2 before op1
3872 bReverseInAssignment = true;
3873 tree->gtFlags |= GTF_REVERSE_OPS;
3874 break;
3875
3876 default:
3877 break;
3878 }
3879 }
3880 else if (kind & GTK_RELOP)
3881 {
3882 /* Float compares remove both operands from the FP stack */
3883 /* Also FP comparison uses EAX for flags */
3884
3885 if (varTypeIsFloating(op1->TypeGet()))
3886 {
3887 level++;
3888 lvl2++;
3889 }
3890 if ((tree->gtFlags & GTF_RELOP_JMP_USED) == 0)
3891 {
3892 /* Using a setcc instruction is more expensive */
3893 costEx += 3;
3894 }
3895 }
3896
3897 /* Check for other interesting cases */
3898
3899 switch (oper)
3900 {
3901 case GT_LSH:
3902 case GT_RSH:
3903 case GT_RSZ:
3904 case GT_ROL:
3905 case GT_ROR:
3906 /* Variable sized shifts are more expensive and use REG_SHIFT */
3907
3908 if (!op2->IsCnsIntOrI())
3909 {
3910 costEx += 3;
3911#ifndef _TARGET_64BIT_
3912 // Variable sized LONG shifts require the use of a helper call
3913 //
3914 if (tree->gtType == TYP_LONG)
3915 {
3916 level += 5;
3917 lvl2 += 5;
3918 costEx += 3 * IND_COST_EX;
3919 costSz += 4;
3920 }
3921#endif // !_TARGET_64BIT_
3922 }
3923 break;
3924
3925 case GT_INTRINSIC:
3926
3927 switch (tree->gtIntrinsic.gtIntrinsicId)
3928 {
3929 case CORINFO_INTRINSIC_Atan2:
3930 case CORINFO_INTRINSIC_Pow:
3931 // These math intrinsics are actually implemented by user calls.
3932 // Increase the Sethi 'complexity' by two to reflect the argument
3933 // register requirement.
3934 level += 2;
3935 break;
3936 default:
3937 assert(!"Unknown binary GT_INTRINSIC operator");
3938 break;
3939 }
3940
3941 break;
3942
3943 default:
3944 break;
3945 }
3946
3947 /* We need to evalutate constants later as many places in codegen
3948 can't handle op1 being a constant. This is normally naturally
3949 enforced as constants have the least level of 0. However,
3950 sometimes we end up with a tree like "cns1 < nop(cns2)". In
3951 such cases, both sides have a level of 0. So encourage constants
3952 to be evaluated last in such cases */
3953
3954 if ((level == 0) && (level == lvl2) && (op1->OperKind() & GTK_CONST) &&
3955 (tree->OperIsCommutative() || tree->OperIsCompare()))
3956 {
3957 lvl2++;
3958 }
3959
3960 /* We try to swap operands if the second one is more expensive */
3961 bool tryToSwap;
3962 GenTree* opA;
3963 GenTree* opB;
3964
3965 if (tree->gtFlags & GTF_REVERSE_OPS)
3966 {
3967 opA = op2;
3968 opB = op1;
3969 }
3970 else
3971 {
3972 opA = op1;
3973 opB = op2;
3974 }
3975
3976 if (fgOrder == FGOrderLinear)
3977 {
3978 // Don't swap anything if we're in linear order; we're really just interested in the costs.
3979 tryToSwap = false;
3980 }
3981 else if (bReverseInAssignment)
3982 {
3983 // Assignments are special, we want the reverseops flags
3984 // so if possible it was set above.
3985 tryToSwap = false;
3986 }
3987 else if ((oper == GT_INTRINSIC) && IsIntrinsicImplementedByUserCall(tree->AsIntrinsic()->gtIntrinsicId))
3988 {
3989 // We do not swap operand execution order for intrinsics that are implemented by user calls
3990 // because of trickiness around ensuring the execution order does not change during rationalization.
3991 tryToSwap = false;
3992 }
3993 else
3994 {
3995 if (tree->gtFlags & GTF_REVERSE_OPS)
3996 {
3997 tryToSwap = (level > lvl2);
3998 }
3999 else
4000 {
4001 tryToSwap = (level < lvl2);
4002 }
4003
4004 // Try to force extra swapping when in the stress mode:
4005 if (compStressCompile(STRESS_REVERSE_FLAG, 60) && ((tree->gtFlags & GTF_REVERSE_OPS) == 0) &&
4006 ((op2->OperKind() & GTK_CONST) == 0))
4007 {
4008 tryToSwap = true;
4009 }
4010 }
4011
4012 if (tryToSwap)
4013 {
4014 bool canSwap = gtCanSwapOrder(opA, opB);
4015
4016 if (canSwap)
4017 {
4018 /* Can we swap the order by commuting the operands? */
4019
4020 switch (oper)
4021 {
4022 case GT_EQ:
4023 case GT_NE:
4024 case GT_LT:
4025 case GT_LE:
4026 case GT_GE:
4027 case GT_GT:
4028 if (GenTree::SwapRelop(oper) != oper)
4029 {
4030 tree->SetOper(GenTree::SwapRelop(oper), GenTree::PRESERVE_VN);
4031 }
4032
4033 __fallthrough;
4034
4035 case GT_ADD:
4036 case GT_MUL:
4037
4038 case GT_OR:
4039 case GT_XOR:
4040 case GT_AND:
4041
4042 /* Swap the operands */
4043
4044 tree->gtOp.gtOp1 = op2;
4045 tree->gtOp.gtOp2 = op1;
4046 break;
4047
4048 case GT_QMARK:
4049 case GT_COLON:
4050 case GT_MKREFANY:
4051 break;
4052
4053 case GT_LIST:
4054 case GT_FIELD_LIST:
4055 break;
4056
4057 default:
4058
4059 /* Mark the operand's evaluation order to be swapped */
4060 if (tree->gtFlags & GTF_REVERSE_OPS)
4061 {
4062 tree->gtFlags &= ~GTF_REVERSE_OPS;
4063 }
4064 else
4065 {
4066 tree->gtFlags |= GTF_REVERSE_OPS;
4067 }
4068
4069 break;
4070 }
4071 }
4072 }
4073
4074 /* Swap the level counts */
4075 if (tree->gtFlags & GTF_REVERSE_OPS)
4076 {
4077 unsigned tmpl;
4078
4079 tmpl = level;
4080 level = lvl2;
4081 lvl2 = tmpl;
4082 }
4083
4084 /* Compute the sethi number for this binary operator */
4085
4086 if (level < 1)
4087 {
4088 level = lvl2;
4089 }
4090 else if (level == lvl2)
4091 {
4092 level += 1;
4093 }
4094
4095 goto DONE;
4096 }
4097
4098 /* See what kind of a special operator we have here */
4099
4100 switch (oper)
4101 {
4102 unsigned lvl2; // Scratch variable
4103
4104 case GT_CALL:
4105
4106 assert(tree->gtFlags & GTF_CALL);
4107
4108 level = 0;
4109 costEx = 5;
4110 costSz = 2;
4111
4112 /* Evaluate the 'this' argument, if present */
4113
4114 if (tree->gtCall.gtCallObjp)
4115 {
4116 GenTree* thisVal = tree->gtCall.gtCallObjp;
4117
4118 lvl2 = gtSetEvalOrder(thisVal);
4119 if (level < lvl2)
4120 {
4121 level = lvl2;
4122 }
4123 costEx += thisVal->gtCostEx;
4124 costSz += thisVal->gtCostSz + 1;
4125 }
4126
4127 /* Evaluate the arguments, right to left */
4128
4129 if (tree->gtCall.gtCallArgs)
4130 {
4131 const bool isListCallArgs = true;
4132 const bool callArgsInRegs = false;
4133 lvl2 = gtSetListOrder(tree->gtCall.gtCallArgs, isListCallArgs, callArgsInRegs);
4134 if (level < lvl2)
4135 {
4136 level = lvl2;
4137 }
4138 costEx += tree->gtCall.gtCallArgs->gtCostEx;
4139 costSz += tree->gtCall.gtCallArgs->gtCostSz;
4140 }
4141
4142 /* Evaluate the temp register arguments list
4143 * This is a "hidden" list and its only purpose is to
4144 * extend the life of temps until we make the call */
4145
4146 if (tree->gtCall.gtCallLateArgs)
4147 {
4148 const bool isListCallArgs = true;
4149 const bool callArgsInRegs = true;
4150 lvl2 = gtSetListOrder(tree->gtCall.gtCallLateArgs, isListCallArgs, callArgsInRegs);
4151 if (level < lvl2)
4152 {
4153 level = lvl2;
4154 }
4155 costEx += tree->gtCall.gtCallLateArgs->gtCostEx;
4156 costSz += tree->gtCall.gtCallLateArgs->gtCostSz;
4157 }
4158
4159 if (tree->gtCall.gtCallType == CT_INDIRECT)
4160 {
4161 // pinvoke-calli cookie is a constant, or constant indirection
4162 assert(tree->gtCall.gtCallCookie == nullptr || tree->gtCall.gtCallCookie->gtOper == GT_CNS_INT ||
4163 tree->gtCall.gtCallCookie->gtOper == GT_IND);
4164
4165 GenTree* indirect = tree->gtCall.gtCallAddr;
4166
4167 lvl2 = gtSetEvalOrder(indirect);
4168 if (level < lvl2)
4169 {
4170 level = lvl2;
4171 }
4172 costEx += indirect->gtCostEx + IND_COST_EX;
4173 costSz += indirect->gtCostSz;
4174 }
4175 else
4176 {
4177#ifdef _TARGET_ARM_
4178 if (tree->gtCall.IsVirtualStub())
4179 {
4180 // We generate movw/movt/ldr
4181 costEx += (1 + IND_COST_EX);
4182 costSz += 8;
4183 if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT)
4184 {
4185 // Must use R12 for the ldr target -- REG_JUMP_THUNK_PARAM
4186 costSz += 2;
4187 }
4188 }
4189 else if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
4190 {
4191 costEx += 2;
4192 costSz += 6;
4193 }
4194 costSz += 2;
4195#endif
4196#ifdef _TARGET_XARCH_
4197 costSz += 3;
4198#endif
4199 }
4200
4201 level += 1;
4202
4203 /* Virtual calls are a bit more expensive */
4204 if (tree->gtCall.IsVirtual())
4205 {
4206 costEx += 2 * IND_COST_EX;
4207 costSz += 2;
4208 }
4209
4210 level += 5;
4211 costEx += 3 * IND_COST_EX;
4212 break;
4213
4214 case GT_ARR_ELEM:
4215
4216 level = gtSetEvalOrder(tree->gtArrElem.gtArrObj);
4217 costEx = tree->gtArrElem.gtArrObj->gtCostEx;
4218 costSz = tree->gtArrElem.gtArrObj->gtCostSz;
4219
4220 unsigned dim;
4221 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
4222 {
4223 lvl2 = gtSetEvalOrder(tree->gtArrElem.gtArrInds[dim]);
4224 if (level < lvl2)
4225 {
4226 level = lvl2;
4227 }
4228 costEx += tree->gtArrElem.gtArrInds[dim]->gtCostEx;
4229 costSz += tree->gtArrElem.gtArrInds[dim]->gtCostSz;
4230 }
4231
4232 level += tree->gtArrElem.gtArrRank;
4233 costEx += 2 + (tree->gtArrElem.gtArrRank * (IND_COST_EX + 1));
4234 costSz += 2 + (tree->gtArrElem.gtArrRank * 2);
4235 break;
4236
4237 case GT_ARR_OFFSET:
4238 level = gtSetEvalOrder(tree->gtArrOffs.gtOffset);
4239 costEx = tree->gtArrOffs.gtOffset->gtCostEx;
4240 costSz = tree->gtArrOffs.gtOffset->gtCostSz;
4241 lvl2 = gtSetEvalOrder(tree->gtArrOffs.gtIndex);
4242 level = max(level, lvl2);
4243 costEx += tree->gtArrOffs.gtIndex->gtCostEx;
4244 costSz += tree->gtArrOffs.gtIndex->gtCostSz;
4245 lvl2 = gtSetEvalOrder(tree->gtArrOffs.gtArrObj);
4246 level = max(level, lvl2);
4247 costEx += tree->gtArrOffs.gtArrObj->gtCostEx;
4248 costSz += tree->gtArrOffs.gtArrObj->gtCostSz;
4249 break;
4250
4251 case GT_CMPXCHG:
4252
4253 level = gtSetEvalOrder(tree->gtCmpXchg.gtOpLocation);
4254 costSz = tree->gtCmpXchg.gtOpLocation->gtCostSz;
4255
4256 lvl2 = gtSetEvalOrder(tree->gtCmpXchg.gtOpValue);
4257 if (level < lvl2)
4258 {
4259 level = lvl2;
4260 }
4261 costSz += tree->gtCmpXchg.gtOpValue->gtCostSz;
4262
4263 lvl2 = gtSetEvalOrder(tree->gtCmpXchg.gtOpComparand);
4264 if (level < lvl2)
4265 {
4266 level = lvl2;
4267 }
4268 costSz += tree->gtCmpXchg.gtOpComparand->gtCostSz;
4269
4270 costEx = MAX_COST; // Seriously, what could be more expensive than lock cmpxchg?
4271 costSz += 5; // size of lock cmpxchg [reg+C], reg
4272 break;
4273
4274 case GT_ARR_BOUNDS_CHECK:
4275#ifdef FEATURE_SIMD
4276 case GT_SIMD_CHK:
4277#endif // FEATURE_SIMD
4278#ifdef FEATURE_HW_INTRINSICS
4279 case GT_HW_INTRINSIC_CHK:
4280#endif // FEATURE_HW_INTRINSICS
4281
4282 costEx = 4; // cmp reg,reg and jae throw (not taken)
4283 costSz = 7; // jump to cold section
4284
4285 level = gtSetEvalOrder(tree->gtBoundsChk.gtIndex);
4286 costEx += tree->gtBoundsChk.gtIndex->gtCostEx;
4287 costSz += tree->gtBoundsChk.gtIndex->gtCostSz;
4288
4289 lvl2 = gtSetEvalOrder(tree->gtBoundsChk.gtArrLen);
4290 if (level < lvl2)
4291 {
4292 level = lvl2;
4293 }
4294 costEx += tree->gtBoundsChk.gtArrLen->gtCostEx;
4295 costSz += tree->gtBoundsChk.gtArrLen->gtCostSz;
4296
4297 break;
4298
4299 case GT_STORE_DYN_BLK:
4300 case GT_DYN_BLK:
4301 {
4302 costEx = 0;
4303 costSz = 0;
4304 level = 0;
4305 if (oper == GT_STORE_DYN_BLK)
4306 {
4307 lvl2 = gtSetEvalOrder(tree->gtDynBlk.Data());
4308 level = max(level, lvl2);
4309 costEx += tree->gtDynBlk.Data()->gtCostEx;
4310 costSz += tree->gtDynBlk.Data()->gtCostSz;
4311 }
4312 lvl2 = gtSetEvalOrder(tree->gtDynBlk.Addr());
4313 level = max(level, lvl2);
4314 costEx = tree->gtDynBlk.Addr()->gtCostEx;
4315 costSz = tree->gtDynBlk.Addr()->gtCostSz;
4316 unsigned sizeLevel = gtSetEvalOrder(tree->gtDynBlk.gtDynamicSize);
4317
4318 // Determine whether the size node should be evaluated first.
4319 // We would like to do this if the sizeLevel is larger than the current level,
4320 // but we have to ensure that we obey ordering constraints.
4321 if (tree->AsDynBlk()->gtEvalSizeFirst != (level < sizeLevel))
4322 {
4323 bool canChange = true;
4324
4325 GenTree* sizeNode = tree->AsDynBlk()->gtDynamicSize;
4326 GenTree* dst = tree->AsDynBlk()->Addr();
4327 GenTree* src = tree->AsDynBlk()->Data();
4328
4329 if (tree->AsDynBlk()->gtEvalSizeFirst)
4330 {
4331 canChange = gtCanSwapOrder(sizeNode, dst);
4332 if (canChange && (src != nullptr))
4333 {
4334 canChange = gtCanSwapOrder(sizeNode, src);
4335 }
4336 }
4337 else
4338 {
4339 canChange = gtCanSwapOrder(dst, sizeNode);
4340 if (canChange && (src != nullptr))
4341 {
4342 gtCanSwapOrder(src, sizeNode);
4343 }
4344 }
4345 if (canChange)
4346 {
4347 tree->AsDynBlk()->gtEvalSizeFirst = (level < sizeLevel);
4348 }
4349 }
4350 level = max(level, sizeLevel);
4351 costEx += tree->gtDynBlk.gtDynamicSize->gtCostEx;
4352 costSz += tree->gtDynBlk.gtDynamicSize->gtCostSz;
4353 }
4354 break;
4355
4356 case GT_INDEX_ADDR:
4357 costEx = 6; // cmp reg,reg; jae throw; mov reg, [addrmode] (not taken)
4358 costSz = 9; // jump to cold section
4359
4360 level = gtSetEvalOrder(tree->AsIndexAddr()->Index());
4361 costEx += tree->AsIndexAddr()->Index()->gtCostEx;
4362 costSz += tree->AsIndexAddr()->Index()->gtCostSz;
4363
4364 lvl2 = gtSetEvalOrder(tree->AsIndexAddr()->Arr());
4365 if (level < lvl2)
4366 {
4367 level = lvl2;
4368 }
4369 costEx += tree->AsIndexAddr()->Arr()->gtCostEx;
4370 costSz += tree->AsIndexAddr()->Arr()->gtCostSz;
4371 break;
4372
4373 default:
4374#ifdef DEBUG
4375 if (verbose)
4376 {
4377 printf("unexpected operator in this tree:\n");
4378 gtDispTree(tree);
4379 }
4380#endif
4381 NO_WAY("unexpected operator");
4382 }
4383
4384DONE:
4385
4386#ifdef FEATURE_HW_INTRINSICS
4387 if ((oper == GT_HWIntrinsic) && (tree->gtGetOp1() == nullptr))
4388 {
4389 // We can have nullary HWIntrinsic nodes, and we must have non-zero cost.
4390 costEx = 1;
4391 costSz = 1;
4392 }
4393#endif // FEATURE_HW_INTRINSICS
4394
4395 // Some path through this function must have set the costs.
4396 assert(costEx != -1);
4397 assert(costSz != -1);
4398
4399 tree->SetCosts(costEx, costSz);
4400
4401 return level;
4402}
4403#ifdef _PREFAST_
4404#pragma warning(pop)
4405#endif
4406
4407/*****************************************************************************
4408 *
4409 * If the given tree is an integer constant that can be used
4410 * in a scaled index address mode as a multiplier (e.g. "[4*index]"), then return
4411 * the scale factor: 2, 4, or 8. Otherwise, return 0. Note that we never return 1,
4412 * to match the behavior of GetScaleIndexShf().
4413 */
4414
4415unsigned GenTree::GetScaleIndexMul()
4416{
4417 if (IsCnsIntOrI() && jitIsScaleIndexMul(gtIntConCommon.IconValue()) && gtIntConCommon.IconValue() != 1)
4418 {
4419 return (unsigned)gtIntConCommon.IconValue();
4420 }
4421
4422 return 0;
4423}
4424
4425/*****************************************************************************
4426 *
4427 * If the given tree is the right-hand side of a left shift (that is,
4428 * 'y' in the tree 'x' << 'y'), and it is an integer constant that can be used
4429 * in a scaled index address mode as a multiplier (e.g. "[4*index]"), then return
4430 * the scale factor: 2, 4, or 8. Otherwise, return 0.
4431 */
4432
4433unsigned GenTree::GetScaleIndexShf()
4434{
4435 if (IsCnsIntOrI() && jitIsScaleIndexShift(gtIntConCommon.IconValue()))
4436 {
4437 return (unsigned)(1 << gtIntConCommon.IconValue());
4438 }
4439
4440 return 0;
4441}
4442
4443/*****************************************************************************
4444 *
4445 * If the given tree is a scaled index (i.e. "op * 4" or "op << 2"), returns
4446 * the multiplier: 2, 4, or 8; otherwise returns 0. Note that "1" is never
4447 * returned.
4448 */
4449
4450unsigned GenTree::GetScaledIndex()
4451{
4452 // with (!opts.OptEnabled(CLFLG_CONSTANTFOLD) we can have
4453 // CNS_INT * CNS_INT
4454 //
4455 if (gtOp.gtOp1->IsCnsIntOrI())
4456 {
4457 return 0;
4458 }
4459
4460 switch (gtOper)
4461 {
4462 case GT_MUL:
4463 return gtOp.gtOp2->GetScaleIndexMul();
4464
4465 case GT_LSH:
4466 return gtOp.gtOp2->GetScaleIndexShf();
4467
4468 default:
4469 assert(!"GenTree::GetScaledIndex() called with illegal gtOper");
4470 break;
4471 }
4472
4473 return 0;
4474}
4475
4476/*****************************************************************************
4477 *
4478 * Returns true if "addr" is a GT_ADD node, at least one of whose arguments is an integer (<= 32 bit)
4479 * constant. If it returns true, it sets "*offset" to (one of the) constant value(s), and
4480 * "*addr" to the other argument.
4481 */
4482
4483bool GenTree::IsAddWithI32Const(GenTree** addr, int* offset)
4484{
4485 if (OperGet() == GT_ADD)
4486 {
4487 if (gtOp.gtOp1->IsIntCnsFitsInI32())
4488 {
4489 *offset = (int)gtOp.gtOp1->gtIntCon.gtIconVal;
4490 *addr = gtOp.gtOp2;
4491 return true;
4492 }
4493 else if (gtOp.gtOp2->IsIntCnsFitsInI32())
4494 {
4495 *offset = (int)gtOp.gtOp2->gtIntCon.gtIconVal;
4496 *addr = gtOp.gtOp1;
4497 return true;
4498 }
4499 }
4500 // Otherwise...
4501 return false;
4502}
4503
4504//------------------------------------------------------------------------
4505// gtGetChildPointer: If 'parent' is the parent of this node, return the pointer
4506// to the child node so that it can be modified; otherwise, return nullptr.
4507//
4508// Arguments:
4509// parent - The possible parent of this node
4510//
4511// Return Value:
4512// If "child" is a child of "parent", returns a pointer to the child node in the parent
4513// (i.e. a pointer to a GenTree pointer).
4514// Otherwise, returns nullptr.
4515//
4516// Assumptions:
4517// 'parent' must be non-null
4518//
4519// Notes:
4520// When FEATURE_MULTIREG_ARGS is defined we can get here with GT_OBJ tree.
4521// This happens when we have a struct that is passed in multiple registers.
4522//
4523// Also note that when UNIX_AMD64_ABI is defined the GT_LDOBJ
4524// later gets converted to a GT_FIELD_LIST with two GT_LCL_FLDs in Lower/LowerXArch.
4525//
4526
4527GenTree** GenTree::gtGetChildPointer(GenTree* parent) const
4528
4529{
4530 switch (parent->OperGet())
4531 {
4532 default:
4533 if (!parent->OperIsSimple())
4534 {
4535 return nullptr;
4536 }
4537 if (this == parent->gtOp.gtOp1)
4538 {
4539 return &(parent->gtOp.gtOp1);
4540 }
4541 if (this == parent->gtOp.gtOp2)
4542 {
4543 return &(parent->gtOp.gtOp2);
4544 }
4545 break;
4546
4547 case GT_CMPXCHG:
4548 if (this == parent->gtCmpXchg.gtOpLocation)
4549 {
4550 return &(parent->gtCmpXchg.gtOpLocation);
4551 }
4552 if (this == parent->gtCmpXchg.gtOpValue)
4553 {
4554 return &(parent->gtCmpXchg.gtOpValue);
4555 }
4556 if (this == parent->gtCmpXchg.gtOpComparand)
4557 {
4558 return &(parent->gtCmpXchg.gtOpComparand);
4559 }
4560 break;
4561
4562 case GT_ARR_BOUNDS_CHECK:
4563#ifdef FEATURE_SIMD
4564 case GT_SIMD_CHK:
4565#endif // FEATURE_SIMD
4566#ifdef FEATURE_HW_INTRINSICS
4567 case GT_HW_INTRINSIC_CHK:
4568#endif // FEATURE_HW_INTRINSICS
4569 if (this == parent->gtBoundsChk.gtIndex)
4570 {
4571 return &(parent->gtBoundsChk.gtIndex);
4572 }
4573 if (this == parent->gtBoundsChk.gtArrLen)
4574 {
4575 return &(parent->gtBoundsChk.gtArrLen);
4576 }
4577 if (this == parent->gtBoundsChk.gtIndRngFailBB)
4578 {
4579 return &(parent->gtBoundsChk.gtIndRngFailBB);
4580 }
4581 break;
4582
4583 case GT_ARR_ELEM:
4584 if (this == parent->gtArrElem.gtArrObj)
4585 {
4586 return &(parent->gtArrElem.gtArrObj);
4587 }
4588 for (int i = 0; i < GT_ARR_MAX_RANK; i++)
4589 {
4590 if (this == parent->gtArrElem.gtArrInds[i])
4591 {
4592 return &(parent->gtArrElem.gtArrInds[i]);
4593 }
4594 }
4595 break;
4596
4597 case GT_ARR_OFFSET:
4598 if (this == parent->gtArrOffs.gtOffset)
4599 {
4600 return &(parent->gtArrOffs.gtOffset);
4601 }
4602 if (this == parent->gtArrOffs.gtIndex)
4603 {
4604 return &(parent->gtArrOffs.gtIndex);
4605 }
4606 if (this == parent->gtArrOffs.gtArrObj)
4607 {
4608 return &(parent->gtArrOffs.gtArrObj);
4609 }
4610 break;
4611
4612 case GT_STORE_DYN_BLK:
4613 case GT_DYN_BLK:
4614 if (this == parent->gtDynBlk.gtOp1)
4615 {
4616 return &(parent->gtDynBlk.gtOp1);
4617 }
4618 if (this == parent->gtDynBlk.gtOp2)
4619 {
4620 return &(parent->gtDynBlk.gtOp2);
4621 }
4622 if (this == parent->gtDynBlk.gtDynamicSize)
4623 {
4624 return &(parent->gtDynBlk.gtDynamicSize);
4625 }
4626 break;
4627
4628 case GT_FIELD:
4629 if (this == parent->AsField()->gtFldObj)
4630 {
4631 return &(parent->AsField()->gtFldObj);
4632 }
4633 break;
4634
4635 case GT_RET_EXPR:
4636 if (this == parent->gtRetExpr.gtInlineCandidate)
4637 {
4638 return &(parent->gtRetExpr.gtInlineCandidate);
4639 }
4640 break;
4641
4642 case GT_CALL:
4643 {
4644 GenTreeCall* call = parent->AsCall();
4645
4646 if (this == call->gtCallObjp)
4647 {
4648 return &(call->gtCallObjp);
4649 }
4650 if (this == call->gtCallArgs)
4651 {
4652 return reinterpret_cast<GenTree**>(&(call->gtCallArgs));
4653 }
4654 if (this == call->gtCallLateArgs)
4655 {
4656 return reinterpret_cast<GenTree**>(&(call->gtCallLateArgs));
4657 }
4658 if (this == call->gtControlExpr)
4659 {
4660 return &(call->gtControlExpr);
4661 }
4662 if (call->gtCallType == CT_INDIRECT)
4663 {
4664 if (this == call->gtCallCookie)
4665 {
4666 return &(call->gtCallCookie);
4667 }
4668 if (this == call->gtCallAddr)
4669 {
4670 return &(call->gtCallAddr);
4671 }
4672 }
4673 }
4674 break;
4675
4676 case GT_STMT:
4677 noway_assert(!"Illegal node for gtGetChildPointer()");
4678 unreached();
4679 }
4680
4681 return nullptr;
4682}
4683
4684bool GenTree::TryGetUse(GenTree* def, GenTree*** use)
4685{
4686 assert(def != nullptr);
4687 assert(use != nullptr);
4688
4689 switch (OperGet())
4690 {
4691 // Leaf nodes
4692 case GT_LCL_VAR:
4693 case GT_LCL_FLD:
4694 case GT_LCL_VAR_ADDR:
4695 case GT_LCL_FLD_ADDR:
4696 case GT_CATCH_ARG:
4697 case GT_LABEL:
4698 case GT_FTN_ADDR:
4699 case GT_RET_EXPR:
4700 case GT_CNS_INT:
4701 case GT_CNS_LNG:
4702 case GT_CNS_DBL:
4703 case GT_CNS_STR:
4704 case GT_MEMORYBARRIER:
4705 case GT_JMP:
4706 case GT_JCC:
4707 case GT_SETCC:
4708 case GT_NO_OP:
4709 case GT_START_NONGC:
4710 case GT_PROF_HOOK:
4711#if !FEATURE_EH_FUNCLETS
4712 case GT_END_LFIN:
4713#endif // !FEATURE_EH_FUNCLETS
4714 case GT_PHI_ARG:
4715 case GT_JMPTABLE:
4716 case GT_CLS_VAR:
4717 case GT_CLS_VAR_ADDR:
4718 case GT_ARGPLACE:
4719 case GT_PHYSREG:
4720 case GT_EMITNOP:
4721 case GT_PINVOKE_PROLOG:
4722 case GT_PINVOKE_EPILOG:
4723 case GT_IL_OFFSET:
4724 return false;
4725
4726 // Standard unary operators
4727 case GT_STORE_LCL_VAR:
4728 case GT_STORE_LCL_FLD:
4729 case GT_NOT:
4730 case GT_NEG:
4731 case GT_COPY:
4732 case GT_RELOAD:
4733 case GT_ARR_LENGTH:
4734 case GT_CAST:
4735 case GT_BITCAST:
4736 case GT_CKFINITE:
4737 case GT_LCLHEAP:
4738 case GT_ADDR:
4739 case GT_IND:
4740 case GT_OBJ:
4741 case GT_BLK:
4742 case GT_BOX:
4743 case GT_ALLOCOBJ:
4744 case GT_RUNTIMELOOKUP:
4745 case GT_INIT_VAL:
4746 case GT_JTRUE:
4747 case GT_SWITCH:
4748 case GT_NULLCHECK:
4749 case GT_PUTARG_REG:
4750 case GT_PUTARG_STK:
4751 case GT_RETURNTRAP:
4752 case GT_NOP:
4753 case GT_RETURN:
4754 case GT_RETFILT:
4755 case GT_BSWAP:
4756 case GT_BSWAP16:
4757 if (def == this->AsUnOp()->gtOp1)
4758 {
4759 *use = &this->AsUnOp()->gtOp1;
4760 return true;
4761 }
4762 return false;
4763
4764 // Variadic nodes
4765 case GT_PHI:
4766 assert(this->AsUnOp()->gtOp1 != nullptr);
4767 return this->AsUnOp()->gtOp1->TryGetUseList(def, use);
4768
4769 case GT_FIELD_LIST:
4770 return TryGetUseList(def, use);
4771
4772#if FEATURE_ARG_SPLIT
4773 case GT_PUTARG_SPLIT:
4774 if (this->AsUnOp()->gtOp1->gtOper == GT_FIELD_LIST)
4775 {
4776 return this->AsUnOp()->gtOp1->TryGetUseList(def, use);
4777 }
4778 if (def == this->AsUnOp()->gtOp1)
4779 {
4780 *use = &this->AsUnOp()->gtOp1;
4781 return true;
4782 }
4783 return false;
4784#endif // FEATURE_ARG_SPLIT
4785
4786#ifdef FEATURE_SIMD
4787 case GT_SIMD:
4788 if (this->AsSIMD()->gtSIMDIntrinsicID == SIMDIntrinsicInitN)
4789 {
4790 assert(this->AsSIMD()->gtOp1 != nullptr);
4791 return this->AsSIMD()->gtOp1->TryGetUseList(def, use);
4792 }
4793
4794 return TryGetUseBinOp(def, use);
4795#endif // FEATURE_SIMD
4796
4797#ifdef FEATURE_HW_INTRINSICS
4798 case GT_HWIntrinsic:
4799 if ((this->AsHWIntrinsic()->gtOp1 != nullptr) && this->AsHWIntrinsic()->gtOp1->OperIsList())
4800 {
4801 return this->AsHWIntrinsic()->gtOp1->TryGetUseList(def, use);
4802 }
4803
4804 return TryGetUseBinOp(def, use);
4805#endif // FEATURE_HW_INTRINSICS
4806
4807 // Special nodes
4808 case GT_CMPXCHG:
4809 {
4810 GenTreeCmpXchg* const cmpXchg = this->AsCmpXchg();
4811 if (def == cmpXchg->gtOpLocation)
4812 {
4813 *use = &cmpXchg->gtOpLocation;
4814 return true;
4815 }
4816 if (def == cmpXchg->gtOpValue)
4817 {
4818 *use = &cmpXchg->gtOpValue;
4819 return true;
4820 }
4821 if (def == cmpXchg->gtOpComparand)
4822 {
4823 *use = &cmpXchg->gtOpComparand;
4824 return true;
4825 }
4826 return false;
4827 }
4828
4829 case GT_ARR_BOUNDS_CHECK:
4830#ifdef FEATURE_SIMD
4831 case GT_SIMD_CHK:
4832#endif // FEATURE_SIMD
4833#ifdef FEATURE_HW_INTRINSICS
4834 case GT_HW_INTRINSIC_CHK:
4835#endif // FEATURE_HW_INTRINSICS
4836 {
4837 GenTreeBoundsChk* const boundsChk = this->AsBoundsChk();
4838 if (def == boundsChk->gtIndex)
4839 {
4840 *use = &boundsChk->gtIndex;
4841 return true;
4842 }
4843 if (def == boundsChk->gtArrLen)
4844 {
4845 *use = &boundsChk->gtArrLen;
4846 return true;
4847 }
4848 return false;
4849 }
4850
4851 case GT_FIELD:
4852 if (def == this->AsField()->gtFldObj)
4853 {
4854 *use = &this->AsField()->gtFldObj;
4855 return true;
4856 }
4857 return false;
4858
4859 case GT_STMT:
4860 if (def == this->AsStmt()->gtStmtExpr)
4861 {
4862 *use = &this->AsStmt()->gtStmtExpr;
4863 return true;
4864 }
4865 return false;
4866
4867 case GT_ARR_ELEM:
4868 {
4869 GenTreeArrElem* const arrElem = this->AsArrElem();
4870 if (def == arrElem->gtArrObj)
4871 {
4872 *use = &arrElem->gtArrObj;
4873 return true;
4874 }
4875 for (unsigned i = 0; i < arrElem->gtArrRank; i++)
4876 {
4877 if (def == arrElem->gtArrInds[i])
4878 {
4879 *use = &arrElem->gtArrInds[i];
4880 return true;
4881 }
4882 }
4883 return false;
4884 }
4885
4886 case GT_ARR_OFFSET:
4887 {
4888 GenTreeArrOffs* const arrOffs = this->AsArrOffs();
4889 if (def == arrOffs->gtOffset)
4890 {
4891 *use = &arrOffs->gtOffset;
4892 return true;
4893 }
4894 if (def == arrOffs->gtIndex)
4895 {
4896 *use = &arrOffs->gtIndex;
4897 return true;
4898 }
4899 if (def == arrOffs->gtArrObj)
4900 {
4901 *use = &arrOffs->gtArrObj;
4902 return true;
4903 }
4904 return false;
4905 }
4906
4907 case GT_DYN_BLK:
4908 {
4909 GenTreeDynBlk* const dynBlock = this->AsDynBlk();
4910 if (def == dynBlock->gtOp1)
4911 {
4912 *use = &dynBlock->gtOp1;
4913 return true;
4914 }
4915 if (def == dynBlock->gtDynamicSize)
4916 {
4917 *use = &dynBlock->gtDynamicSize;
4918 return true;
4919 }
4920 return false;
4921 }
4922
4923 case GT_STORE_DYN_BLK:
4924 {
4925 GenTreeDynBlk* const dynBlock = this->AsDynBlk();
4926 if (def == dynBlock->gtOp1)
4927 {
4928 *use = &dynBlock->gtOp1;
4929 return true;
4930 }
4931 if (def == dynBlock->gtOp2)
4932 {
4933 *use = &dynBlock->gtOp2;
4934 return true;
4935 }
4936 if (def == dynBlock->gtDynamicSize)
4937 {
4938 *use = &dynBlock->gtDynamicSize;
4939 return true;
4940 }
4941 return false;
4942 }
4943
4944 case GT_CALL:
4945 {
4946 GenTreeCall* const call = this->AsCall();
4947 if (def == call->gtCallObjp)
4948 {
4949 *use = &call->gtCallObjp;
4950 return true;
4951 }
4952 if (def == call->gtControlExpr)
4953 {
4954 *use = &call->gtControlExpr;
4955 return true;
4956 }
4957 if (call->gtCallType == CT_INDIRECT)
4958 {
4959 if (def == call->gtCallCookie)
4960 {
4961 *use = &call->gtCallCookie;
4962 return true;
4963 }
4964 if (def == call->gtCallAddr)
4965 {
4966 *use = &call->gtCallAddr;
4967 return true;
4968 }
4969 }
4970 if ((call->gtCallArgs != nullptr) && call->gtCallArgs->TryGetUseList(def, use))
4971 {
4972 return true;
4973 }
4974
4975 return (call->gtCallLateArgs != nullptr) && call->gtCallLateArgs->TryGetUseList(def, use);
4976 }
4977
4978 // Binary nodes
4979 default:
4980 assert(this->OperIsBinary());
4981 return TryGetUseBinOp(def, use);
4982 }
4983}
4984
4985bool GenTree::TryGetUseList(GenTree* def, GenTree*** use)
4986{
4987 assert(def != nullptr);
4988 assert(use != nullptr);
4989
4990 for (GenTreeArgList* node = this->AsArgList(); node != nullptr; node = node->Rest())
4991 {
4992 if (def == node->gtOp1)
4993 {
4994 *use = &node->gtOp1;
4995 return true;
4996 }
4997 }
4998 return false;
4999}
5000
5001bool GenTree::TryGetUseBinOp(GenTree* def, GenTree*** use)
5002{
5003 assert(def != nullptr);
5004 assert(use != nullptr);
5005 assert(this->OperIsBinary());
5006
5007 GenTreeOp* const binOp = this->AsOp();
5008 if (def == binOp->gtOp1)
5009 {
5010 *use = &binOp->gtOp1;
5011 return true;
5012 }
5013 if (def == binOp->gtOp2)
5014 {
5015 *use = &binOp->gtOp2;
5016 return true;
5017 }
5018 return false;
5019}
5020
5021//------------------------------------------------------------------------
5022// GenTree::ReplaceOperand:
5023// Replace a given operand to this node with a new operand. If the
5024// current node is a call node, this will also udpate the call
5025// argument table if necessary.
5026//
5027// Arguments:
5028// useEdge - the use edge that points to the operand to be replaced.
5029// replacement - the replacement node.
5030//
5031void GenTree::ReplaceOperand(GenTree** useEdge, GenTree* replacement)
5032{
5033 assert(useEdge != nullptr);
5034 assert(replacement != nullptr);
5035 assert(TryGetUse(*useEdge, &useEdge));
5036
5037 if (OperGet() == GT_CALL)
5038 {
5039 AsCall()->ReplaceCallOperand(useEdge, replacement);
5040 }
5041 else
5042 {
5043 *useEdge = replacement;
5044 }
5045}
5046
5047//------------------------------------------------------------------------
5048// gtGetParent: Get the parent of this node, and optionally capture the
5049// pointer to the child so that it can be modified.
5050//
5051// Arguments:
5052
5053// parentChildPointer - A pointer to a GenTree** (yes, that's three
5054// levels, i.e. GenTree ***), which if non-null,
5055// will be set to point to the field in the parent
5056// that points to this node.
5057//
5058// Return value - The parent of this node.
5059//
5060// Notes:
5061//
5062// This requires that the execution order must be defined (i.e. gtSetEvalOrder() has been called).
5063// To enable the child to be replaced, it accepts an argument, parentChildPointer that, if non-null,
5064// will be set to point to the child pointer in the parent that points to this node.
5065
5066GenTree* GenTree::gtGetParent(GenTree*** parentChildPtrPtr) const
5067{
5068 // Find the parent node; it must be after this node in the execution order.
5069 GenTree** parentChildPtr = nullptr;
5070 GenTree* parent;
5071 for (parent = gtNext; parent != nullptr; parent = parent->gtNext)
5072 {
5073 parentChildPtr = gtGetChildPointer(parent);
5074 if (parentChildPtr != nullptr)
5075 {
5076 break;
5077 }
5078 }
5079 if (parentChildPtrPtr != nullptr)
5080 {
5081 *parentChildPtrPtr = parentChildPtr;
5082 }
5083 return parent;
5084}
5085
5086//------------------------------------------------------------------------------
5087// OperRequiresAsgFlag : Check whether the operation requires GTF_ASG flag regardless
5088// of the children's flags.
5089//
5090
5091bool GenTree::OperRequiresAsgFlag()
5092{
5093 if (OperIs(GT_ASG) || OperIs(GT_XADD, GT_XCHG, GT_LOCKADD, GT_CMPXCHG, GT_MEMORYBARRIER))
5094 {
5095 return true;
5096 }
5097#ifdef FEATURE_HW_INTRINSICS
5098 if (gtOper == GT_HWIntrinsic)
5099 {
5100 GenTreeHWIntrinsic* hwIntrinsicNode = this->AsHWIntrinsic();
5101 if (hwIntrinsicNode->OperIsMemoryStore())
5102 {
5103 // A MemoryStore operation is an assignment
5104 return true;
5105 }
5106 }
5107#endif // FEATURE_HW_INTRINSICS
5108 return false;
5109}
5110
5111//------------------------------------------------------------------------------
5112// OperRequiresCallFlag : Check whether the operation requires GTF_CALL flag regardless
5113// of the children's flags.
5114//
5115
5116bool GenTree::OperRequiresCallFlag(Compiler* comp)
5117{
5118 switch (gtOper)
5119 {
5120 case GT_CALL:
5121 return true;
5122
5123 case GT_INTRINSIC:
5124 return comp->IsIntrinsicImplementedByUserCall(this->AsIntrinsic()->gtIntrinsicId);
5125
5126#if FEATURE_FIXED_OUT_ARGS && !defined(_TARGET_64BIT_)
5127 case GT_LSH:
5128 case GT_RSH:
5129 case GT_RSZ:
5130
5131 // Variable shifts of a long end up being helper calls, so mark the tree as such in morph.
5132 // This is potentially too conservative, since they'll get treated as having side effects.
5133 // It is important to mark them as calls so if they are part of an argument list,
5134 // they will get sorted and processed properly (for example, it is important to handle
5135 // all nested calls before putting struct arguments in the argument registers). We
5136 // could mark the trees just before argument processing, but it would require a full
5137 // tree walk of the argument tree, so we just do it when morphing, instead, even though we'll
5138 // mark non-argument trees (that will still get converted to calls, anyway).
5139 return (this->TypeGet() == TYP_LONG) && (gtGetOp2()->OperGet() != GT_CNS_INT);
5140#endif // FEATURE_FIXED_OUT_ARGS && !_TARGET_64BIT_
5141
5142 default:
5143 return false;
5144 }
5145}
5146
5147//------------------------------------------------------------------------------
5148// OperIsImplicitIndir : Check whether the operation contains an implicit
5149// indirection.
5150// Arguments:
5151// this - a GenTree node
5152//
5153// Return Value:
5154// True if the given node contains an implicit indirection
5155//
5156// Note that for the GT_HWIntrinsic node we have to examine the
5157// details of the node to determine its result.
5158//
5159
5160bool GenTree::OperIsImplicitIndir() const
5161{
5162 switch (gtOper)
5163 {
5164 case GT_LOCKADD:
5165 case GT_XADD:
5166 case GT_XCHG:
5167 case GT_CMPXCHG:
5168 case GT_BLK:
5169 case GT_OBJ:
5170 case GT_DYN_BLK:
5171 case GT_STORE_BLK:
5172 case GT_STORE_OBJ:
5173 case GT_STORE_DYN_BLK:
5174 case GT_BOX:
5175 case GT_ARR_INDEX:
5176 case GT_ARR_ELEM:
5177 case GT_ARR_OFFSET:
5178 return true;
5179#ifdef FEATURE_HW_INTRINSICS
5180 case GT_HWIntrinsic:
5181 {
5182 GenTreeHWIntrinsic* hwIntrinsicNode = (const_cast<GenTree*>(this))->AsHWIntrinsic();
5183 return hwIntrinsicNode->OperIsMemoryLoadOrStore();
5184 }
5185#endif // FEATURE_HW_INTRINSICS
5186 default:
5187 return false;
5188 }
5189}
5190
5191//------------------------------------------------------------------------------
5192// OperMayThrow : Check whether the operation may throw.
5193//
5194//
5195// Arguments:
5196// comp - Compiler instance
5197//
5198// Return Value:
5199// True if the given operator may cause an exception
5200
5201bool GenTree::OperMayThrow(Compiler* comp)
5202{
5203 GenTree* op;
5204
5205 switch (gtOper)
5206 {
5207 case GT_MOD:
5208 case GT_DIV:
5209 case GT_UMOD:
5210 case GT_UDIV:
5211
5212 /* Division with a non-zero, non-minus-one constant does not throw an exception */
5213
5214 op = gtOp.gtOp2;
5215
5216 if (varTypeIsFloating(op->TypeGet()))
5217 {
5218 return false; // Floating point division does not throw.
5219 }
5220
5221 // For integers only division by 0 or by -1 can throw
5222 if (op->IsIntegralConst() && !op->IsIntegralConst(0) && !op->IsIntegralConst(-1))
5223 {
5224 return false;
5225 }
5226 return true;
5227
5228 case GT_INTRINSIC:
5229 // If this is an intrinsic that represents the object.GetType(), it can throw an NullReferenceException.
5230 // Report it as may throw.
5231 // Note: Some of the rest of the existing intrinsics could potentially throw an exception (for example
5232 // the array and string element access ones). They are handled differently than the GetType intrinsic
5233 // and are not marked with GTF_EXCEPT. If these are revisited at some point to be marked as
5234 // GTF_EXCEPT,
5235 // the code below might need to be specialized to handle them properly.
5236 if ((this->gtFlags & GTF_EXCEPT) != 0)
5237 {
5238 return true;
5239 }
5240
5241 break;
5242
5243 case GT_CALL:
5244
5245 CorInfoHelpFunc helper;
5246 helper = comp->eeGetHelperNum(this->AsCall()->gtCallMethHnd);
5247 return ((helper == CORINFO_HELP_UNDEF) || !comp->s_helperCallProperties.NoThrow(helper));
5248
5249 case GT_IND:
5250 case GT_BLK:
5251 case GT_OBJ:
5252 case GT_DYN_BLK:
5253 case GT_STORE_BLK:
5254 case GT_NULLCHECK:
5255 return (((this->gtFlags & GTF_IND_NONFAULTING) == 0) && comp->fgAddrCouldBeNull(this->AsIndir()->Addr()));
5256
5257 case GT_ARR_LENGTH:
5258 return (((this->gtFlags & GTF_IND_NONFAULTING) == 0) &&
5259 comp->fgAddrCouldBeNull(this->AsArrLen()->ArrRef()));
5260
5261 case GT_ARR_ELEM:
5262 return comp->fgAddrCouldBeNull(this->gtArrElem.gtArrObj);
5263
5264 case GT_ARR_BOUNDS_CHECK:
5265 case GT_ARR_INDEX:
5266 case GT_ARR_OFFSET:
5267 case GT_LCLHEAP:
5268 case GT_CKFINITE:
5269#ifdef FEATURE_SIMD
5270 case GT_SIMD_CHK:
5271#endif // FEATURE_SIMD
5272#ifdef FEATURE_HW_INTRINSICS
5273 case GT_HW_INTRINSIC_CHK:
5274#endif // FEATURE_HW_INTRINSICS
5275 case GT_INDEX_ADDR:
5276 return true;
5277
5278#ifdef FEATURE_HW_INTRINSICS
5279 case GT_HWIntrinsic:
5280 {
5281 GenTreeHWIntrinsic* hwIntrinsicNode = this->AsHWIntrinsic();
5282 assert(hwIntrinsicNode != nullptr);
5283 if (hwIntrinsicNode->OperIsMemoryLoadOrStore())
5284 {
5285 // This operation contains an implicit indirection
5286 // it could throw a null reference exception.
5287 //
5288 return true;
5289 }
5290 }
5291#endif // FEATURE_HW_INTRINSICS
5292
5293 default:
5294 break;
5295 }
5296
5297 /* Overflow arithmetic operations also throw exceptions */
5298
5299 if (gtOverflowEx())
5300 {
5301 return true;
5302 }
5303
5304 return false;
5305}
5306
5307#if DEBUGGABLE_GENTREE
5308// static
5309GenTree::VtablePtr GenTree::s_vtablesForOpers[] = {nullptr};
5310GenTree::VtablePtr GenTree::s_vtableForOp = nullptr;
5311
5312GenTree::VtablePtr GenTree::GetVtableForOper(genTreeOps oper)
5313{
5314 noway_assert(oper < GT_COUNT);
5315
5316 // First, check a cache.
5317
5318 if (s_vtablesForOpers[oper] != nullptr)
5319 {
5320 return s_vtablesForOpers[oper];
5321 }
5322
5323 // Otherwise, look up the correct vtable entry. Note that we want the most derived GenTree subtype
5324 // for an oper. E.g., GT_LCL_VAR is defined in GTSTRUCT_3 as GenTreeLclVar and in GTSTRUCT_N as
5325 // GenTreeLclVarCommon. We want the GenTreeLclVar vtable, since nothing should actually be
5326 // instantiated as a GenTreeLclVarCommon.
5327
5328 VtablePtr res = nullptr;
5329 switch (oper)
5330 {
5331
5332// clang-format off
5333
5334#define GTSTRUCT_0(nm, tag) /*handle explicitly*/
5335#define GTSTRUCT_1(nm, tag) \
5336 case tag: \
5337 { \
5338 GenTree##nm gt; \
5339 res = *reinterpret_cast<VtablePtr*>(&gt); \
5340 } \
5341 break;
5342#define GTSTRUCT_2(nm, tag, tag2) \
5343 case tag: \
5344 case tag2: \
5345 { \
5346 GenTree##nm gt; \
5347 res = *reinterpret_cast<VtablePtr*>(&gt); \
5348 } \
5349 break;
5350#define GTSTRUCT_3(nm, tag, tag2, tag3) \
5351 case tag: \
5352 case tag2: \
5353 case tag3: \
5354 { \
5355 GenTree##nm gt; \
5356 res = *reinterpret_cast<VtablePtr*>(&gt); \
5357 } \
5358 break;
5359#define GTSTRUCT_4(nm, tag, tag2, tag3, tag4) \
5360 case tag: \
5361 case tag2: \
5362 case tag3: \
5363 case tag4: \
5364 { \
5365 GenTree##nm gt; \
5366 res = *reinterpret_cast<VtablePtr*>(&gt); \
5367 } \
5368 break;
5369#define GTSTRUCT_N(nm, ...) /*handle explicitly*/
5370#define GTSTRUCT_2_SPECIAL(nm, tag, tag2) /*handle explicitly*/
5371#define GTSTRUCT_3_SPECIAL(nm, tag, tag2, tag3) /*handle explicitly*/
5372#include "gtstructs.h"
5373
5374 // clang-format on
5375
5376 // Handle the special cases.
5377 // The following opers are in GTSTRUCT_N but no other place (namely, no subtypes).
5378
5379 case GT_STORE_BLK:
5380 case GT_BLK:
5381 {
5382 GenTreeBlk gt;
5383 res = *reinterpret_cast<VtablePtr*>(&gt);
5384 }
5385 break;
5386
5387 case GT_IND:
5388 case GT_NULLCHECK:
5389 {
5390 GenTreeIndir gt;
5391 res = *reinterpret_cast<VtablePtr*>(&gt);
5392 }
5393 break;
5394
5395 // Handle GT_LIST (but not GT_FIELD_LIST, which is also in a GTSTRUCT_1).
5396
5397 case GT_LIST:
5398 {
5399 GenTreeArgList gt;
5400 res = *reinterpret_cast<VtablePtr*>(&gt);
5401 }
5402 break;
5403
5404 // We don't need to handle GTSTRUCT_N for LclVarCommon, since all those allowed opers are specified
5405 // in their proper subtype. Similarly for GenTreeIndir.
5406
5407 default:
5408 {
5409 // Should be unary or binary op.
5410 if (s_vtableForOp == nullptr)
5411 {
5412 unsigned opKind = OperKind(oper);
5413 assert(!IsExOp(opKind));
5414 assert(OperIsSimple(oper) || OperIsLeaf(oper));
5415 // Need to provide non-null operands.
5416 GenTreeIntCon dummyOp(TYP_INT, 0);
5417 GenTreeOp gt(oper, TYP_INT, &dummyOp, ((opKind & GTK_UNOP) ? nullptr : &dummyOp));
5418 s_vtableForOp = *reinterpret_cast<VtablePtr*>(&gt);
5419 }
5420 res = s_vtableForOp;
5421 break;
5422 }
5423 }
5424 s_vtablesForOpers[oper] = res;
5425 return res;
5426}
5427
5428void GenTree::SetVtableForOper(genTreeOps oper)
5429{
5430 *reinterpret_cast<VtablePtr*>(this) = GetVtableForOper(oper);
5431}
5432#endif // DEBUGGABLE_GENTREE
5433
5434GenTree* Compiler::gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, GenTree* op2)
5435{
5436 assert(op1 != nullptr);
5437 assert(op2 != nullptr);
5438
5439 // We should not be allocating nodes that extend GenTreeOp with this;
5440 // should call the appropriate constructor for the extended type.
5441 assert(!GenTree::IsExOp(GenTree::OperKind(oper)));
5442
5443 GenTree* node = new (this, oper) GenTreeOp(oper, type, op1, op2);
5444
5445 return node;
5446}
5447
5448GenTree* Compiler::gtNewQmarkNode(var_types type, GenTree* cond, GenTree* colon)
5449{
5450 compQmarkUsed = true;
5451 cond->gtFlags |= GTF_RELOP_QMARK;
5452 GenTree* result = new (this, GT_QMARK) GenTreeQmark(type, cond, colon, this);
5453#ifdef DEBUG
5454 if (compQmarkRationalized)
5455 {
5456 fgCheckQmarkAllowedForm(result);
5457 }
5458#endif
5459 return result;
5460}
5461
5462GenTreeQmark::GenTreeQmark(var_types type, GenTree* cond, GenTree* colonOp, Compiler* comp)
5463 : GenTreeOp(GT_QMARK, type, cond, colonOp)
5464{
5465 // These must follow a specific form.
5466 assert(cond != nullptr && cond->TypeGet() == TYP_INT);
5467 assert(colonOp != nullptr && colonOp->OperGet() == GT_COLON);
5468}
5469
5470GenTreeIntCon* Compiler::gtNewIconNode(ssize_t value, var_types type)
5471{
5472 return new (this, GT_CNS_INT) GenTreeIntCon(type, value);
5473}
5474
5475// return a new node representing the value in a physical register
5476GenTree* Compiler::gtNewPhysRegNode(regNumber reg, var_types type)
5477{
5478 assert(genIsValidIntReg(reg) || (reg == REG_SPBASE));
5479 GenTree* result = new (this, GT_PHYSREG) GenTreePhysReg(reg, type);
5480 return result;
5481}
5482
5483GenTree* Compiler::gtNewJmpTableNode()
5484{
5485 GenTree* node = new (this, GT_JMPTABLE) GenTreeJumpTable(TYP_INT);
5486 node->gtJumpTable.gtJumpTableAddr = 0;
5487 return node;
5488}
5489
5490/*****************************************************************************
5491 *
5492 * Converts an annotated token into an icon flags (so that we will later be
5493 * able to tell the type of the handle that will be embedded in the icon
5494 * node)
5495 */
5496
5497unsigned Compiler::gtTokenToIconFlags(unsigned token)
5498{
5499 unsigned flags = 0;
5500
5501 switch (TypeFromToken(token))
5502 {
5503 case mdtTypeRef:
5504 case mdtTypeDef:
5505 case mdtTypeSpec:
5506 flags = GTF_ICON_CLASS_HDL;
5507 break;
5508
5509 case mdtMethodDef:
5510 flags = GTF_ICON_METHOD_HDL;
5511 break;
5512
5513 case mdtFieldDef:
5514 flags = GTF_ICON_FIELD_HDL;
5515 break;
5516
5517 default:
5518 flags = GTF_ICON_TOKEN_HDL;
5519 break;
5520 }
5521
5522 return flags;
5523}
5524
5525//-----------------------------------------------------------------------------------------
5526// gtNewIndOfIconHandleNode: Creates an indirection GenTree node of a constant handle
5527//
5528// Arguments:
5529// indType - The type returned by the indirection node
5530// addr - The constant address to read from
5531// iconFlags - The GTF_ICON flag value that specifies the kind of handle that we have
5532// isInvariant - The indNode should also be marked as invariant
5533//
5534// Return Value:
5535// Returns a GT_IND node representing value at the address provided by 'value'
5536//
5537// Notes:
5538// The GT_IND node is marked as non-faulting
5539// If the indType is GT_REF we also mark the indNode as GTF_GLOB_REF
5540//
5541
5542GenTree* Compiler::gtNewIndOfIconHandleNode(var_types indType, size_t addr, unsigned iconFlags, bool isInvariant)
5543{
5544 GenTree* addrNode = gtNewIconHandleNode(addr, iconFlags);
5545 GenTree* indNode = gtNewOperNode(GT_IND, indType, addrNode);
5546
5547 // This indirection won't cause an exception.
5548 //
5549 indNode->gtFlags |= GTF_IND_NONFAULTING;
5550
5551 // String Literal handles are indirections that return a TYP_REF.
5552 // They are pointers into the GC heap and they are not invariant
5553 // as the address is a reportable GC-root and as such it can be
5554 // modified during a GC collection
5555 //
5556 if (indType == TYP_REF)
5557 {
5558 // This indirection points into the gloabal heap
5559 indNode->gtFlags |= GTF_GLOB_REF;
5560 }
5561 if (isInvariant)
5562 {
5563 // This indirection also is invariant.
5564 indNode->gtFlags |= GTF_IND_INVARIANT;
5565 }
5566 return indNode;
5567}
5568
5569/*****************************************************************************
5570 *
5571 * Allocates a integer constant entry that represents a HANDLE to something.
5572 * It may not be allowed to embed HANDLEs directly into the JITed code (for eg,
5573 * as arguments to JIT helpers). Get a corresponding value that can be embedded.
5574 * If the handle needs to be accessed via an indirection, pValue points to it.
5575 */
5576
5577GenTree* Compiler::gtNewIconEmbHndNode(void* value, void* pValue, unsigned iconFlags, void* compileTimeHandle)
5578{
5579 GenTree* iconNode;
5580 GenTree* handleNode;
5581
5582 if (value != nullptr)
5583 {
5584 // When 'value' is non-null, pValue is required to be null
5585 assert(pValue == nullptr);
5586
5587 // use 'value' to construct an integer constant node
5588 iconNode = gtNewIconHandleNode((size_t)value, iconFlags);
5589
5590 // 'value' is the handle
5591 handleNode = iconNode;
5592 }
5593 else
5594 {
5595 // When 'value' is null, pValue is required to be non-null
5596 assert(pValue != nullptr);
5597
5598 // use 'pValue' to construct an integer constant node
5599 iconNode = gtNewIconHandleNode((size_t)pValue, iconFlags);
5600
5601 // 'pValue' is an address of a location that contains the handle
5602
5603 // construct the indirection of 'pValue'
5604 handleNode = gtNewOperNode(GT_IND, TYP_I_IMPL, iconNode);
5605
5606 // This indirection won't cause an exception.
5607 handleNode->gtFlags |= GTF_IND_NONFAULTING;
5608#if 0
5609 // It should also be invariant, but marking it as such leads to bad diffs.
5610
5611 // This indirection also is invariant.
5612 handleNode->gtFlags |= GTF_IND_INVARIANT;
5613#endif
5614 }
5615
5616 iconNode->gtIntCon.gtCompileTimeHandle = (size_t)compileTimeHandle;
5617
5618 return handleNode;
5619}
5620
5621/*****************************************************************************/
5622GenTree* Compiler::gtNewStringLiteralNode(InfoAccessType iat, void* pValue)
5623{
5624 GenTree* tree = nullptr;
5625
5626 switch (iat)
5627 {
5628 case IAT_VALUE: // constructStringLiteral in CoreRT case can return IAT_VALUE
5629 tree = gtNewIconEmbHndNode(pValue, nullptr, GTF_ICON_STR_HDL, nullptr);
5630 tree->gtType = TYP_REF;
5631 tree = gtNewOperNode(GT_NOP, TYP_REF, tree); // prevents constant folding
5632 break;
5633
5634 case IAT_PVALUE: // The value needs to be accessed via an indirection
5635 // Create an indirection
5636 tree = gtNewIndOfIconHandleNode(TYP_REF, (size_t)pValue, GTF_ICON_STR_HDL, false);
5637 break;
5638
5639 case IAT_PPVALUE: // The value needs to be accessed via a double indirection
5640 // Create the first indirection
5641 tree = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)pValue, GTF_ICON_PSTR_HDL, true);
5642
5643 // Create the second indirection
5644 tree = gtNewOperNode(GT_IND, TYP_REF, tree);
5645 // This indirection won't cause an exception.
5646 tree->gtFlags |= GTF_IND_NONFAULTING;
5647 // This indirection points into the gloabal heap (it is String Object)
5648 tree->gtFlags |= GTF_GLOB_REF;
5649 break;
5650
5651 default:
5652 noway_assert(!"Unexpected InfoAccessType");
5653 }
5654
5655 return tree;
5656}
5657
5658/*****************************************************************************/
5659
5660GenTree* Compiler::gtNewLconNode(__int64 value)
5661{
5662#ifdef _TARGET_64BIT_
5663 GenTree* node = new (this, GT_CNS_INT) GenTreeIntCon(TYP_LONG, value);
5664#else
5665 GenTree* node = new (this, GT_CNS_LNG) GenTreeLngCon(value);
5666#endif
5667
5668 return node;
5669}
5670
5671GenTree* Compiler::gtNewDconNode(double value)
5672{
5673 GenTree* node = new (this, GT_CNS_DBL) GenTreeDblCon(value);
5674
5675 return node;
5676}
5677
5678GenTree* Compiler::gtNewSconNode(int CPX, CORINFO_MODULE_HANDLE scpHandle)
5679{
5680
5681#if SMALL_TREE_NODES
5682
5683 /* 'GT_CNS_STR' nodes later get transformed into 'GT_CALL' */
5684
5685 assert(GenTree::s_gtNodeSizes[GT_CALL] > GenTree::s_gtNodeSizes[GT_CNS_STR]);
5686
5687 GenTree* node = new (this, GT_CALL) GenTreeStrCon(CPX, scpHandle DEBUGARG(/*largeNode*/ true));
5688#else
5689 GenTree* node = new (this, GT_CNS_STR) GenTreeStrCon(CPX, scpHandle DEBUGARG(/*largeNode*/ true));
5690#endif
5691
5692 return node;
5693}
5694
5695GenTree* Compiler::gtNewZeroConNode(var_types type)
5696{
5697 GenTree* zero;
5698 switch (type)
5699 {
5700 case TYP_INT:
5701 zero = gtNewIconNode(0);
5702 break;
5703
5704 case TYP_BYREF:
5705 __fallthrough;
5706
5707 case TYP_REF:
5708 zero = gtNewIconNode(0);
5709 zero->gtType = type;
5710 break;
5711
5712 case TYP_LONG:
5713 zero = gtNewLconNode(0);
5714 break;
5715
5716 case TYP_FLOAT:
5717 zero = gtNewDconNode(0.0);
5718 zero->gtType = type;
5719 break;
5720
5721 case TYP_DOUBLE:
5722 zero = gtNewDconNode(0.0);
5723 break;
5724
5725 default:
5726 noway_assert(!"Bad type in gtNewZeroConNode");
5727 zero = nullptr;
5728 break;
5729 }
5730 return zero;
5731}
5732
5733GenTree* Compiler::gtNewOneConNode(var_types type)
5734{
5735 GenTree* one;
5736 switch (type)
5737 {
5738 case TYP_INT:
5739 case TYP_UINT:
5740 one = gtNewIconNode(1);
5741 break;
5742
5743 case TYP_LONG:
5744 case TYP_ULONG:
5745 one = gtNewLconNode(1);
5746 break;
5747
5748 case TYP_FLOAT:
5749 case TYP_DOUBLE:
5750 one = gtNewDconNode(1.0);
5751 one->gtType = type;
5752 break;
5753
5754 default:
5755 noway_assert(!"Bad type in gtNewOneConNode");
5756 one = nullptr;
5757 break;
5758 }
5759 return one;
5760}
5761
5762#ifdef FEATURE_SIMD
5763//---------------------------------------------------------------------
5764// gtNewSIMDVectorZero: create a GT_SIMD node for Vector<T>.Zero
5765//
5766// Arguments:
5767// simdType - simd vector type
5768// baseType - element type of vector
5769// size - size of vector in bytes
5770GenTree* Compiler::gtNewSIMDVectorZero(var_types simdType, var_types baseType, unsigned size)
5771{
5772 baseType = genActualType(baseType);
5773 GenTree* initVal = gtNewZeroConNode(baseType);
5774 initVal->gtType = baseType;
5775 return gtNewSIMDNode(simdType, initVal, nullptr, SIMDIntrinsicInit, baseType, size);
5776}
5777
5778//---------------------------------------------------------------------
5779// gtNewSIMDVectorOne: create a GT_SIMD node for Vector<T>.One
5780//
5781// Arguments:
5782// simdType - simd vector type
5783// baseType - element type of vector
5784// size - size of vector in bytes
5785GenTree* Compiler::gtNewSIMDVectorOne(var_types simdType, var_types baseType, unsigned size)
5786{
5787 GenTree* initVal;
5788 if (varTypeIsSmallInt(baseType))
5789 {
5790 unsigned baseSize = genTypeSize(baseType);
5791 int val;
5792 if (baseSize == 1)
5793 {
5794 val = 0x01010101;
5795 }
5796 else
5797 {
5798 val = 0x00010001;
5799 }
5800 initVal = gtNewIconNode(val);
5801 }
5802 else
5803 {
5804 initVal = gtNewOneConNode(baseType);
5805 }
5806
5807 baseType = genActualType(baseType);
5808 initVal->gtType = baseType;
5809 return gtNewSIMDNode(simdType, initVal, nullptr, SIMDIntrinsicInit, baseType, size);
5810}
5811#endif // FEATURE_SIMD
5812
5813GenTreeCall* Compiler::gtNewIndCallNode(GenTree* addr, var_types type, GenTreeArgList* args, IL_OFFSETX ilOffset)
5814{
5815 return gtNewCallNode(CT_INDIRECT, (CORINFO_METHOD_HANDLE)addr, type, args, ilOffset);
5816}
5817
5818GenTreeCall* Compiler::gtNewCallNode(
5819 gtCallTypes callType, CORINFO_METHOD_HANDLE callHnd, var_types type, GenTreeArgList* args, IL_OFFSETX ilOffset)
5820{
5821 GenTreeCall* node = new (this, GT_CALL) GenTreeCall(genActualType(type));
5822
5823 node->gtFlags |= (GTF_CALL | GTF_GLOB_REF);
5824 if (args)
5825 {
5826 node->gtFlags |= (args->gtFlags & GTF_ALL_EFFECT);
5827 }
5828 node->gtCallType = callType;
5829 node->gtCallMethHnd = callHnd;
5830 node->gtCallArgs = args;
5831 node->gtCallObjp = nullptr;
5832 node->fgArgInfo = nullptr;
5833 node->callSig = nullptr;
5834 node->gtRetClsHnd = nullptr;
5835 node->gtControlExpr = nullptr;
5836 node->gtCallMoreFlags = 0;
5837
5838 if (callType == CT_INDIRECT)
5839 {
5840 node->gtCallCookie = nullptr;
5841 }
5842 else
5843 {
5844 node->gtInlineCandidateInfo = nullptr;
5845 }
5846 node->gtCallLateArgs = nullptr;
5847 node->gtReturnType = type;
5848
5849#ifdef FEATURE_READYTORUN_COMPILER
5850 node->gtEntryPoint.addr = nullptr;
5851 node->gtEntryPoint.accessType = IAT_VALUE;
5852#endif
5853
5854#if defined(DEBUG) || defined(INLINE_DATA)
5855 // These get updated after call node is built.
5856 node->gtInlineObservation = InlineObservation::CALLEE_UNUSED_INITIAL;
5857 node->gtRawILOffset = BAD_IL_OFFSET;
5858#endif
5859
5860 // Spec: Managed Retval sequence points needs to be generated while generating debug info for debuggable code.
5861 //
5862 // Implementation note: if not generating MRV info genCallSite2ILOffsetMap will be NULL and
5863 // codegen will pass BAD_IL_OFFSET as IL offset of a call node to emitter, which will cause emitter
5864 // not to emit IP mapping entry.
5865 if (opts.compDbgCode && opts.compDbgInfo)
5866 {
5867 // Managed Retval - IL offset of the call. This offset is used to emit a
5868 // CALL_INSTRUCTION type sequence point while emitting corresponding native call.
5869 //
5870 // TODO-Cleanup:
5871 // a) (Opt) We need not store this offset if the method doesn't return a
5872 // value. Rather it can be made BAD_IL_OFFSET to prevent a sequence
5873 // point being emitted.
5874 //
5875 // b) (Opt) Add new sequence points only if requested by debugger through
5876 // a new boundary type - ICorDebugInfo::BoundaryTypes
5877 if (genCallSite2ILOffsetMap == nullptr)
5878 {
5879 genCallSite2ILOffsetMap = new (getAllocator()) CallSiteILOffsetTable(getAllocator());
5880 }
5881
5882 // Make sure that there are no duplicate entries for a given call node
5883 assert(!genCallSite2ILOffsetMap->Lookup(node));
5884 genCallSite2ILOffsetMap->Set(node, ilOffset);
5885 }
5886
5887 // Initialize gtOtherRegs
5888 node->ClearOtherRegs();
5889
5890 // Initialize spill flags of gtOtherRegs
5891 node->ClearOtherRegFlags();
5892
5893#if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
5894 // Initialize the multi-reg long return info if necessary
5895 if (varTypeIsLong(node))
5896 {
5897 // The return type will remain as the incoming long type
5898 node->gtReturnType = node->gtType;
5899
5900 // Initialize Return type descriptor of call node
5901 ReturnTypeDesc* retTypeDesc = node->GetReturnTypeDesc();
5902 retTypeDesc->InitializeLongReturnType(this);
5903
5904 // must be a long returned in two registers
5905 assert(retTypeDesc->GetReturnRegCount() == 2);
5906 }
5907#endif // defined(_TARGET_X86_) || defined(_TARGET_ARM_)
5908
5909 return node;
5910}
5911
5912GenTree* Compiler::gtNewLclvNode(unsigned lnum, var_types type, IL_OFFSETX ILoffs)
5913{
5914 // We need to ensure that all struct values are normalized.
5915 // It might be nice to assert this in general, but we have assignments of int to long.
5916 if (varTypeIsStruct(type))
5917 {
5918 // Make an exception for implicit by-ref parameters during global morph, since
5919 // their lvType has been updated to byref but their appearances have not yet all
5920 // been rewritten and so may have struct type still.
5921 assert(type == lvaTable[lnum].lvType ||
5922 (lvaIsImplicitByRefLocal(lnum) && fgGlobalMorph && (lvaTable[lnum].lvType == TYP_BYREF)));
5923 }
5924 GenTree* node = new (this, GT_LCL_VAR) GenTreeLclVar(type, lnum, ILoffs);
5925
5926 /* Cannot have this assert because the inliner uses this function
5927 * to add temporaries */
5928
5929 // assert(lnum < lvaCount);
5930
5931 return node;
5932}
5933
5934GenTree* Compiler::gtNewLclLNode(unsigned lnum, var_types type, IL_OFFSETX ILoffs)
5935{
5936 // We need to ensure that all struct values are normalized.
5937 // It might be nice to assert this in general, but we have assignments of int to long.
5938 if (varTypeIsStruct(type))
5939 {
5940 // Make an exception for implicit by-ref parameters during global morph, since
5941 // their lvType has been updated to byref but their appearances have not yet all
5942 // been rewritten and so may have struct type still.
5943 assert(type == lvaTable[lnum].lvType ||
5944 (lvaIsImplicitByRefLocal(lnum) && fgGlobalMorph && (lvaTable[lnum].lvType == TYP_BYREF)));
5945 }
5946#if SMALL_TREE_NODES
5947 /* This local variable node may later get transformed into a large node */
5948
5949 // assert(GenTree::s_gtNodeSizes[GT_CALL] > GenTree::s_gtNodeSizes[GT_LCL_VAR]);
5950
5951 GenTree* node = new (this, GT_CALL) GenTreeLclVar(type, lnum, ILoffs DEBUGARG(/*largeNode*/ true));
5952#else
5953 GenTree* node = new (this, GT_LCL_VAR) GenTreeLclVar(type, lnum, ILoffs DEBUGARG(/*largeNode*/ true));
5954#endif
5955
5956 return node;
5957}
5958
5959GenTreeLclFld* Compiler::gtNewLclFldNode(unsigned lnum, var_types type, unsigned offset)
5960{
5961 GenTreeLclFld* node = new (this, GT_LCL_FLD) GenTreeLclFld(type, lnum, offset);
5962
5963 /* Cannot have this assert because the inliner uses this function
5964 * to add temporaries */
5965
5966 // assert(lnum < lvaCount);
5967
5968 node->gtFieldSeq = FieldSeqStore::NotAField();
5969 return node;
5970}
5971
5972GenTree* Compiler::gtNewInlineCandidateReturnExpr(GenTree* inlineCandidate, var_types type)
5973
5974{
5975 assert(GenTree::s_gtNodeSizes[GT_RET_EXPR] == TREE_NODE_SZ_LARGE);
5976
5977 GenTree* node = new (this, GT_RET_EXPR) GenTreeRetExpr(type);
5978
5979 node->gtRetExpr.gtInlineCandidate = inlineCandidate;
5980
5981 if (varTypeIsStruct(inlineCandidate) && !inlineCandidate->OperIsBlkOp())
5982 {
5983 node->gtRetExpr.gtRetClsHnd = gtGetStructHandle(inlineCandidate);
5984 }
5985
5986 // GT_RET_EXPR node eventually might be bashed back to GT_CALL (when inlining is aborted for example).
5987 // Therefore it should carry the GTF_CALL flag so that all the rules about spilling can apply to it as well.
5988 // For example, impImportLeave or CEE_POP need to spill GT_RET_EXPR before empty the evaluation stack.
5989 node->gtFlags |= GTF_CALL;
5990
5991 return node;
5992}
5993
5994GenTreeArgList* Compiler::gtNewListNode(GenTree* op1, GenTreeArgList* op2)
5995{
5996 assert((op1 != nullptr) && (op1->OperGet() != GT_LIST));
5997
5998 return new (this, GT_LIST) GenTreeArgList(op1, op2);
5999}
6000
6001/*****************************************************************************
6002 *
6003 * Create a list out of one value.
6004 */
6005
6006GenTreeArgList* Compiler::gtNewArgList(GenTree* arg)
6007{
6008 return new (this, GT_LIST) GenTreeArgList(arg);
6009}
6010
6011/*****************************************************************************
6012 *
6013 * Create a list out of the two values.
6014 */
6015
6016GenTreeArgList* Compiler::gtNewArgList(GenTree* arg1, GenTree* arg2)
6017{
6018 return new (this, GT_LIST) GenTreeArgList(arg1, gtNewArgList(arg2));
6019}
6020
6021/*****************************************************************************
6022 *
6023 * Create a list out of the three values.
6024 */
6025
6026GenTreeArgList* Compiler::gtNewArgList(GenTree* arg1, GenTree* arg2, GenTree* arg3)
6027{
6028 return new (this, GT_LIST) GenTreeArgList(arg1, gtNewArgList(arg2, arg3));
6029}
6030
6031/*****************************************************************************
6032 *
6033 * Create a list out of the three values.
6034 */
6035
6036GenTreeArgList* Compiler::gtNewArgList(GenTree* arg1, GenTree* arg2, GenTree* arg3, GenTree* arg4)
6037{
6038 return new (this, GT_LIST) GenTreeArgList(arg1, gtNewArgList(arg2, arg3, arg4));
6039}
6040
6041/*****************************************************************************
6042 *
6043 * Given a GT_CALL node, access the fgArgInfo and find the entry
6044 * that has the matching argNum and return the fgArgTableEntryPtr
6045 */
6046
6047fgArgTabEntry* Compiler::gtArgEntryByArgNum(GenTreeCall* call, unsigned argNum)
6048{
6049 fgArgInfo* argInfo = call->fgArgInfo;
6050 noway_assert(argInfo != nullptr);
6051 return argInfo->GetArgEntry(argNum);
6052}
6053
6054/*****************************************************************************
6055 *
6056 * Given a GT_CALL node, access the fgArgInfo and find the entry
6057 * that has the matching node and return the fgArgTableEntryPtr
6058 */
6059
6060fgArgTabEntry* Compiler::gtArgEntryByNode(GenTreeCall* call, GenTree* node)
6061{
6062 fgArgInfo* argInfo = call->fgArgInfo;
6063 noway_assert(argInfo != nullptr);
6064
6065 unsigned argCount = argInfo->ArgCount();
6066 fgArgTabEntry** argTable = argInfo->ArgTable();
6067 fgArgTabEntry* curArgTabEntry = nullptr;
6068
6069 for (unsigned i = 0; i < argCount; i++)
6070 {
6071 curArgTabEntry = argTable[i];
6072
6073 if (curArgTabEntry->node == node)
6074 {
6075 return curArgTabEntry;
6076 }
6077 else if (curArgTabEntry->parent != nullptr)
6078 {
6079 assert(curArgTabEntry->parent->OperIsList());
6080 if (curArgTabEntry->parent->Current() == node)
6081 {
6082 return curArgTabEntry;
6083 }
6084 }
6085 else // (curArgTabEntry->parent == NULL)
6086 {
6087 if (call->gtCallObjp == node)
6088 {
6089 return curArgTabEntry;
6090 }
6091 }
6092 }
6093 noway_assert(!"gtArgEntryByNode: node not found");
6094 return nullptr;
6095}
6096
6097/*****************************************************************************
6098 *
6099 * Find and return the entry with the given "lateArgInx". Requires that one is found
6100 * (asserts this).
6101 */
6102fgArgTabEntry* Compiler::gtArgEntryByLateArgIndex(GenTreeCall* call, unsigned lateArgInx)
6103{
6104 fgArgInfo* argInfo = call->fgArgInfo;
6105 noway_assert(argInfo != nullptr);
6106 assert(lateArgInx != UINT_MAX);
6107
6108 unsigned argCount = argInfo->ArgCount();
6109 fgArgTabEntry** argTable = argInfo->ArgTable();
6110 fgArgTabEntry* curArgTabEntry = nullptr;
6111
6112 for (unsigned i = 0; i < argCount; i++)
6113 {
6114 curArgTabEntry = argTable[i];
6115 if (curArgTabEntry->isLateArg() && curArgTabEntry->lateArgInx == lateArgInx)
6116 {
6117 return curArgTabEntry;
6118 }
6119 }
6120 noway_assert(!"gtArgEntryByNode: node not found");
6121 return nullptr;
6122}
6123
6124//------------------------------------------------------------------------
6125// gtArgNodeByLateArgInx: Given a call instruction, find the argument with the given
6126// late arg index (i.e. the given position in the gtCallLateArgs list).
6127// Arguments:
6128// call - the call node
6129// lateArgInx - the index into the late args list
6130//
6131// Return value:
6132// The late argument node.
6133//
6134GenTree* Compiler::gtArgNodeByLateArgInx(GenTreeCall* call, unsigned lateArgInx)
6135{
6136 GenTree* argx = nullptr;
6137 unsigned regIndex = 0;
6138
6139 for (GenTreeArgList *list = call->gtCall.gtCallLateArgs; list != nullptr; regIndex++, list = list->Rest())
6140 {
6141 argx = list->Current();
6142 assert(!argx->IsArgPlaceHolderNode()); // No placeholder nodes are in gtCallLateArgs;
6143 if (regIndex == lateArgInx)
6144 {
6145 break;
6146 }
6147 }
6148 noway_assert(argx != nullptr);
6149 return argx;
6150}
6151
6152/*****************************************************************************
6153 *
6154 * Given an fgArgTabEntry*, return true if it is the 'this' pointer argument.
6155 */
6156bool Compiler::gtArgIsThisPtr(fgArgTabEntry* argEntry)
6157{
6158 return (argEntry->parent == nullptr);
6159}
6160
6161/*****************************************************************************
6162 *
6163 * Create a node that will assign 'src' to 'dst'.
6164 */
6165
6166GenTree* Compiler::gtNewAssignNode(GenTree* dst, GenTree* src)
6167{
6168 /* Mark the target as being assigned */
6169
6170 if ((dst->gtOper == GT_LCL_VAR) || (dst->OperGet() == GT_LCL_FLD))
6171 {
6172 dst->gtFlags |= GTF_VAR_DEF;
6173 if (dst->IsPartialLclFld(this))
6174 {
6175 // We treat these partial writes as combined uses and defs.
6176 dst->gtFlags |= GTF_VAR_USEASG;
6177 }
6178 }
6179 dst->gtFlags |= GTF_DONT_CSE;
6180
6181 /* Create the assignment node */
6182
6183 GenTree* asg = gtNewOperNode(GT_ASG, dst->TypeGet(), dst, src);
6184
6185 /* Mark the expression as containing an assignment */
6186
6187 asg->gtFlags |= GTF_ASG;
6188
6189 return asg;
6190}
6191
6192//------------------------------------------------------------------------
6193// gtNewObjNode: Creates a new Obj node.
6194//
6195// Arguments:
6196// structHnd - The class handle of the struct type.
6197// addr - The address of the struct.
6198//
6199// Return Value:
6200// Returns a node representing the struct value at the given address.
6201//
6202// Assumptions:
6203// Any entry and exit conditions, such as required preconditions of
6204// data structures, memory to be freed by caller, etc.
6205//
6206// Notes:
6207// It will currently return a GT_OBJ node for any struct type, but may
6208// return a GT_IND or a non-indirection for a scalar type.
6209// The node will not yet have its GC info initialized. This is because
6210// we may not need this info if this is an r-value.
6211
6212GenTree* Compiler::gtNewObjNode(CORINFO_CLASS_HANDLE structHnd, GenTree* addr)
6213{
6214 var_types nodeType = impNormStructType(structHnd);
6215 assert(varTypeIsStruct(nodeType));
6216 unsigned size = info.compCompHnd->getClassSize(structHnd);
6217
6218 // It would be convenient to set the GC info at this time, but we don't actually require
6219 // it unless this is going to be a destination.
6220 if (!varTypeIsStruct(nodeType))
6221 {
6222 if ((addr->gtOper == GT_ADDR) && (addr->gtGetOp1()->TypeGet() == nodeType))
6223 {
6224 return addr->gtGetOp1();
6225 }
6226 else
6227 {
6228 return gtNewOperNode(GT_IND, nodeType, addr);
6229 }
6230 }
6231 GenTreeBlk* newBlkOrObjNode = new (this, GT_OBJ) GenTreeObj(nodeType, addr, structHnd, size);
6232
6233 // An Obj is not a global reference, if it is known to be a local struct.
6234 if ((addr->gtFlags & GTF_GLOB_REF) == 0)
6235 {
6236 GenTreeLclVarCommon* lclNode = addr->IsLocalAddrExpr();
6237 if (lclNode != nullptr)
6238 {
6239 newBlkOrObjNode->gtFlags |= GTF_IND_NONFAULTING;
6240 if (!lvaIsImplicitByRefLocal(lclNode->gtLclNum))
6241 {
6242 newBlkOrObjNode->gtFlags &= ~GTF_GLOB_REF;
6243 }
6244 }
6245 }
6246 return newBlkOrObjNode;
6247}
6248
6249//------------------------------------------------------------------------
6250// gtSetObjGcInfo: Set the GC info on an object node
6251//
6252// Arguments:
6253// objNode - The object node of interest
6254
6255void Compiler::gtSetObjGcInfo(GenTreeObj* objNode)
6256{
6257 CORINFO_CLASS_HANDLE structHnd = objNode->gtClass;
6258 var_types nodeType = objNode->TypeGet();
6259 unsigned size = objNode->gtBlkSize;
6260 unsigned slots = 0;
6261 unsigned gcPtrCount = 0;
6262 BYTE* gcPtrs = nullptr;
6263
6264 assert(varTypeIsStruct(nodeType));
6265 assert(size == info.compCompHnd->getClassSize(structHnd));
6266 assert(nodeType == impNormStructType(structHnd));
6267
6268 if (nodeType == TYP_STRUCT)
6269 {
6270 if (size >= TARGET_POINTER_SIZE)
6271 {
6272 // Get the GC fields info
6273 var_types simdBaseType; // Dummy argument
6274 slots = roundUp(size, TARGET_POINTER_SIZE) / TARGET_POINTER_SIZE;
6275 gcPtrs = new (this, CMK_ASTNode) BYTE[slots];
6276 nodeType = impNormStructType(structHnd, gcPtrs, &gcPtrCount, &simdBaseType);
6277 }
6278 }
6279 objNode->SetGCInfo(gcPtrs, gcPtrCount, slots);
6280 assert(objNode->gtType == nodeType);
6281}
6282
6283//------------------------------------------------------------------------
6284// gtNewStructVal: Return a node that represents a struct value
6285//
6286// Arguments:
6287// structHnd - The class for the struct
6288// addr - The address of the struct
6289//
6290// Return Value:
6291// A block, object or local node that represents the struct value pointed to by 'addr'.
6292
6293GenTree* Compiler::gtNewStructVal(CORINFO_CLASS_HANDLE structHnd, GenTree* addr)
6294{
6295 if (addr->gtOper == GT_ADDR)
6296 {
6297 GenTree* val = addr->gtGetOp1();
6298 if (val->OperGet() == GT_LCL_VAR)
6299 {
6300 unsigned lclNum = addr->gtGetOp1()->AsLclVarCommon()->gtLclNum;
6301 LclVarDsc* varDsc = &(lvaTable[lclNum]);
6302 if (varTypeIsStruct(varDsc) && (varDsc->lvVerTypeInfo.GetClassHandle() == structHnd) &&
6303 !lvaIsImplicitByRefLocal(lclNum))
6304 {
6305 return addr->gtGetOp1();
6306 }
6307 }
6308 }
6309 return gtNewObjNode(structHnd, addr);
6310}
6311
6312//------------------------------------------------------------------------
6313// gtNewBlockVal: Return a node that represents a possibly untyped block value
6314//
6315// Arguments:
6316// addr - The address of the block
6317// size - The size of the block
6318//
6319// Return Value:
6320// A block, object or local node that represents the block value pointed to by 'addr'.
6321
6322GenTree* Compiler::gtNewBlockVal(GenTree* addr, unsigned size)
6323{
6324 // By default we treat this as an opaque struct type with known size.
6325 var_types blkType = TYP_STRUCT;
6326 if ((addr->gtOper == GT_ADDR) && (addr->gtGetOp1()->OperGet() == GT_LCL_VAR))
6327 {
6328 GenTree* val = addr->gtGetOp1();
6329#if FEATURE_SIMD
6330 if (varTypeIsSIMD(val))
6331 {
6332 if (genTypeSize(val->TypeGet()) == size)
6333 {
6334 blkType = val->TypeGet();
6335 return addr->gtGetOp1();
6336 }
6337 }
6338 else
6339#endif // FEATURE_SIMD
6340 if (val->TypeGet() == TYP_STRUCT)
6341 {
6342 GenTreeLclVarCommon* lcl = addr->gtGetOp1()->AsLclVarCommon();
6343 LclVarDsc* varDsc = &(lvaTable[lcl->gtLclNum]);
6344 if ((varDsc->TypeGet() == TYP_STRUCT) && (varDsc->lvExactSize == size))
6345 {
6346 return addr->gtGetOp1();
6347 }
6348 }
6349 }
6350 return new (this, GT_BLK) GenTreeBlk(GT_BLK, blkType, addr, size);
6351}
6352
6353// Creates a new assignment node for a CpObj.
6354// Parameters (exactly the same as MSIL CpObj):
6355//
6356// dstAddr - The target to copy the struct to
6357// srcAddr - The source to copy the struct from
6358// structHnd - A class token that represents the type of object being copied. May be null
6359// if FEATURE_SIMD is enabled and the source has a SIMD type.
6360// isVolatile - Is this marked as volatile memory?
6361
6362GenTree* Compiler::gtNewCpObjNode(GenTree* dstAddr, GenTree* srcAddr, CORINFO_CLASS_HANDLE structHnd, bool isVolatile)
6363{
6364 GenTree* lhs = gtNewStructVal(structHnd, dstAddr);
6365 GenTree* src = nullptr;
6366 unsigned size;
6367
6368 if (lhs->OperIsBlk())
6369 {
6370 size = lhs->AsBlk()->gtBlkSize;
6371 if (lhs->OperGet() == GT_OBJ)
6372 {
6373 gtSetObjGcInfo(lhs->AsObj());
6374 }
6375 }
6376 else
6377 {
6378 size = genTypeSize(lhs->gtType);
6379 }
6380
6381 if (srcAddr->OperGet() == GT_ADDR)
6382 {
6383 src = srcAddr->gtOp.gtOp1;
6384 }
6385 else
6386 {
6387 src = gtNewOperNode(GT_IND, lhs->TypeGet(), srcAddr);
6388 }
6389
6390 GenTree* result = gtNewBlkOpNode(lhs, src, size, isVolatile, true);
6391 return result;
6392}
6393
6394//------------------------------------------------------------------------
6395// FixupInitBlkValue: Fixup the init value for an initBlk operation
6396//
6397// Arguments:
6398// asgType - The type of assignment that the initBlk is being transformed into
6399//
6400// Return Value:
6401// Modifies the constant value on this node to be the appropriate "fill"
6402// value for the initblk.
6403//
6404// Notes:
6405// The initBlk MSIL instruction takes a byte value, which must be
6406// extended to the size of the assignment when an initBlk is transformed
6407// to an assignment of a primitive type.
6408// This performs the appropriate extension.
6409
6410void GenTreeIntCon::FixupInitBlkValue(var_types asgType)
6411{
6412 assert(varTypeIsIntegralOrI(asgType));
6413 unsigned size = genTypeSize(asgType);
6414 if (size > 1)
6415 {
6416 size_t cns = gtIconVal;
6417 cns = cns & 0xFF;
6418 cns |= cns << 8;
6419 if (size >= 4)
6420 {
6421 cns |= cns << 16;
6422#ifdef _TARGET_64BIT_
6423 if (size == 8)
6424 {
6425 cns |= cns << 32;
6426 }
6427#endif // _TARGET_64BIT_
6428
6429 // Make the type match for evaluation types.
6430 gtType = asgType;
6431
6432 // if we are initializing a GC type the value being assigned must be zero (null).
6433 assert(!varTypeIsGC(asgType) || (cns == 0));
6434 }
6435
6436 gtIconVal = cns;
6437 }
6438}
6439
6440//
6441//------------------------------------------------------------------------
6442// gtBlockOpInit: Initializes a BlkOp GenTree
6443//
6444// Arguments:
6445// result - an assignment node that is to be initialized.
6446// dst - the target (destination) we want to either initialize or copy to.
6447// src - the init value for InitBlk or the source struct for CpBlk/CpObj.
6448// isVolatile - specifies whether this node is a volatile memory operation.
6449//
6450// Assumptions:
6451// 'result' is an assignment that is newly constructed.
6452// If 'dst' is TYP_STRUCT, then it must be a block node or lclVar.
6453//
6454// Notes:
6455// This procedure centralizes all the logic to both enforce proper structure and
6456// to properly construct any InitBlk/CpBlk node.
6457
6458void Compiler::gtBlockOpInit(GenTree* result, GenTree* dst, GenTree* srcOrFillVal, bool isVolatile)
6459{
6460 if (!result->OperIsBlkOp())
6461 {
6462 assert(dst->TypeGet() != TYP_STRUCT);
6463 return;
6464 }
6465#ifdef DEBUG
6466 // If the copy involves GC pointers, the caller must have already set
6467 // the node additional members (gtGcPtrs, gtGcPtrCount, gtSlots) on the dst.
6468 if ((dst->gtOper == GT_OBJ) && dst->AsBlk()->HasGCPtr())
6469 {
6470 GenTreeObj* objNode = dst->AsObj();
6471 assert(objNode->gtGcPtrs != nullptr);
6472 assert(!IsUninitialized(objNode->gtGcPtrs));
6473 assert(!IsUninitialized(objNode->gtGcPtrCount));
6474 assert(!IsUninitialized(objNode->gtSlots) && objNode->gtSlots > 0);
6475
6476 for (unsigned i = 0; i < objNode->gtGcPtrCount; ++i)
6477 {
6478 CorInfoGCType t = (CorInfoGCType)objNode->gtGcPtrs[i];
6479 switch (t)
6480 {
6481 case TYPE_GC_NONE:
6482 case TYPE_GC_REF:
6483 case TYPE_GC_BYREF:
6484 case TYPE_GC_OTHER:
6485 break;
6486 default:
6487 unreached();
6488 }
6489 }
6490 }
6491#endif // DEBUG
6492
6493 /* In the case of CpBlk, we want to avoid generating
6494 * nodes where the source and destination are the same
6495 * because of two reasons, first, is useless, second
6496 * it introduces issues in liveness and also copying
6497 * memory from an overlapping memory location is
6498 * undefined both as per the ECMA standard and also
6499 * the memcpy semantics specify that.
6500 *
6501 * NOTE: In this case we'll only detect the case for addr of a local
6502 * and a local itself, any other complex expressions won't be
6503 * caught.
6504 *
6505 * TODO-Cleanup: though having this logic is goodness (i.e. avoids self-assignment
6506 * of struct vars very early), it was added because fgInterBlockLocalVarLiveness()
6507 * isn't handling self-assignment of struct variables correctly. This issue may not
6508 * surface if struct promotion is ON (which is the case on x86/arm). But still the
6509 * fundamental issue exists that needs to be addressed.
6510 */
6511 if (result->OperIsCopyBlkOp())
6512 {
6513 GenTree* currSrc = srcOrFillVal;
6514 GenTree* currDst = dst;
6515
6516 if (currSrc->OperIsBlk() && (currSrc->AsBlk()->Addr()->OperGet() == GT_ADDR))
6517 {
6518 currSrc = currSrc->AsBlk()->Addr()->gtGetOp1();
6519 }
6520 if (currDst->OperIsBlk() && (currDst->AsBlk()->Addr()->OperGet() == GT_ADDR))
6521 {
6522 currDst = currDst->AsBlk()->Addr()->gtGetOp1();
6523 }
6524
6525 if (currSrc->OperGet() == GT_LCL_VAR && currDst->OperGet() == GT_LCL_VAR &&
6526 currSrc->gtLclVarCommon.gtLclNum == currDst->gtLclVarCommon.gtLclNum)
6527 {
6528 // Make this a NOP
6529 // TODO-Cleanup: probably doesn't matter, but could do this earlier and avoid creating a GT_ASG
6530 result->gtBashToNOP();
6531 return;
6532 }
6533 }
6534
6535 // Propagate all effect flags from children
6536 result->gtFlags |= dst->gtFlags & GTF_ALL_EFFECT;
6537 result->gtFlags |= result->gtOp.gtOp2->gtFlags & GTF_ALL_EFFECT;
6538
6539 result->gtFlags |= (dst->gtFlags & GTF_EXCEPT) | (srcOrFillVal->gtFlags & GTF_EXCEPT);
6540
6541 if (isVolatile)
6542 {
6543 result->gtFlags |= GTF_BLK_VOLATILE;
6544 }
6545
6546#ifdef FEATURE_SIMD
6547 if (result->OperIsCopyBlkOp() && varTypeIsSIMD(srcOrFillVal))
6548 {
6549 // If the source is a GT_SIMD node of SIMD type, then the dst lclvar struct
6550 // should be labeled as simd intrinsic related struct.
6551 // This is done so that the morpher can transform any field accesses into
6552 // intrinsics, thus avoiding conflicting access methods (fields vs. whole-register).
6553
6554 GenTree* src = srcOrFillVal;
6555 if (src->OperIsIndir() && (src->AsIndir()->Addr()->OperGet() == GT_ADDR))
6556 {
6557 src = src->AsIndir()->Addr()->gtGetOp1();
6558 }
6559#ifdef FEATURE_HW_INTRINSICS
6560 if ((src->OperGet() == GT_SIMD) || (src->OperGet() == GT_HWIntrinsic))
6561#else
6562 if (src->OperGet() == GT_SIMD)
6563#endif // FEATURE_HW_INTRINSICS
6564 {
6565 if (dst->OperIsBlk() && (dst->AsIndir()->Addr()->OperGet() == GT_ADDR))
6566 {
6567 dst = dst->AsIndir()->Addr()->gtGetOp1();
6568 }
6569
6570 if (dst->OperIsLocal() && varTypeIsStruct(dst))
6571 {
6572 setLclRelatedToSIMDIntrinsic(dst);
6573 }
6574 }
6575 }
6576#endif // FEATURE_SIMD
6577}
6578
6579//------------------------------------------------------------------------
6580// gtNewBlkOpNode: Creates a GenTree for a block (struct) assignment.
6581//
6582// Arguments:
6583// dst - Destination or target to copy to / initialize the buffer.
6584// srcOrFillVall - the size of the buffer to copy/initialize or zero, in the case of CpObj.
6585// size - The size of the buffer or a class token (in the case of CpObj).
6586// isVolatile - Whether this is a volatile memory operation or not.
6587// isCopyBlock - True if this is a block copy (rather than a block init).
6588//
6589// Return Value:
6590// Returns the newly constructed and initialized block operation.
6591//
6592// Notes:
6593// If size is zero, the dst must be a GT_OBJ with the class handle.
6594// 'dst' must be a block node or lclVar.
6595//
6596GenTree* Compiler::gtNewBlkOpNode(GenTree* dst, GenTree* srcOrFillVal, unsigned size, bool isVolatile, bool isCopyBlock)
6597{
6598 assert(dst->OperIsBlk() || dst->OperIsLocal());
6599 if (isCopyBlock)
6600 {
6601 srcOrFillVal->gtFlags |= GTF_DONT_CSE;
6602 if (srcOrFillVal->OperIsIndir() && (srcOrFillVal->gtGetOp1()->gtOper == GT_ADDR))
6603 {
6604 srcOrFillVal = srcOrFillVal->gtGetOp1()->gtGetOp1();
6605 }
6606 }
6607 else
6608 {
6609 // InitBlk
6610 assert(varTypeIsIntegral(srcOrFillVal));
6611 if (varTypeIsStruct(dst))
6612 {
6613 if (!srcOrFillVal->IsIntegralConst(0))
6614 {
6615 srcOrFillVal = gtNewOperNode(GT_INIT_VAL, TYP_INT, srcOrFillVal);
6616 }
6617 }
6618 }
6619
6620 GenTree* result = gtNewAssignNode(dst, srcOrFillVal);
6621 gtBlockOpInit(result, dst, srcOrFillVal, isVolatile);
6622 return result;
6623}
6624
6625//------------------------------------------------------------------------
6626// gtNewPutArgReg: Creates a new PutArgReg node.
6627//
6628// Arguments:
6629// type - The actual type of the argument
6630// arg - The argument node
6631// argReg - The register that the argument will be passed in
6632//
6633// Return Value:
6634// Returns the newly created PutArgReg node.
6635//
6636// Notes:
6637// The node is generated as GenTreeMultiRegOp on RyuJIT/armel, GenTreeOp on all the other archs.
6638//
6639GenTree* Compiler::gtNewPutArgReg(var_types type, GenTree* arg, regNumber argReg)
6640{
6641 assert(arg != nullptr);
6642
6643 GenTree* node = nullptr;
6644#if defined(_TARGET_ARM_)
6645 // A PUTARG_REG could be a MultiRegOp on arm since we could move a double register to two int registers.
6646 node = new (this, GT_PUTARG_REG) GenTreeMultiRegOp(GT_PUTARG_REG, type, arg, nullptr);
6647 if (type == TYP_LONG)
6648 {
6649 node->AsMultiRegOp()->gtOtherReg = REG_NEXT(argReg);
6650 }
6651#else
6652 node = gtNewOperNode(GT_PUTARG_REG, type, arg);
6653#endif
6654 node->gtRegNum = argReg;
6655
6656 return node;
6657}
6658
6659//------------------------------------------------------------------------
6660// gtNewBitCastNode: Creates a new BitCast node.
6661//
6662// Arguments:
6663// type - The actual type of the argument
6664// arg - The argument node
6665// argReg - The register that the argument will be passed in
6666//
6667// Return Value:
6668// Returns the newly created BitCast node.
6669//
6670// Notes:
6671// The node is generated as GenTreeMultiRegOp on RyuJIT/arm, as GenTreeOp on all the other archs.
6672//
6673GenTree* Compiler::gtNewBitCastNode(var_types type, GenTree* arg)
6674{
6675 assert(arg != nullptr);
6676
6677 GenTree* node = nullptr;
6678#if defined(_TARGET_ARM_)
6679 // A BITCAST could be a MultiRegOp on arm since we could move a double register to two int registers.
6680 node = new (this, GT_BITCAST) GenTreeMultiRegOp(GT_BITCAST, type, arg, nullptr);
6681#else
6682 node = gtNewOperNode(GT_BITCAST, type, arg);
6683#endif
6684
6685 return node;
6686}
6687
6688//------------------------------------------------------------------------
6689// gtNewAllocObjNode: Helper to create an object allocation node.
6690//
6691// Arguments:
6692// pResolvedToken - Resolved token for the object being allocated
6693// useParent - true iff the token represents a child of the object's class
6694//
6695// Return Value:
6696// Returns GT_ALLOCOBJ node that will be later morphed into an
6697// allocation helper call or local variable allocation on the stack.
6698
6699GenTreeAllocObj* Compiler::gtNewAllocObjNode(CORINFO_RESOLVED_TOKEN* pResolvedToken, BOOL useParent)
6700{
6701 const BOOL mustRestoreHandle = TRUE;
6702 BOOL* const pRuntimeLookup = nullptr;
6703 bool usingReadyToRunHelper = false;
6704 CorInfoHelpFunc helper = CORINFO_HELP_UNDEF;
6705 GenTree* opHandle = impTokenToHandle(pResolvedToken, pRuntimeLookup, mustRestoreHandle, useParent);
6706
6707#ifdef FEATURE_READYTORUN_COMPILER
6708 CORINFO_CONST_LOOKUP lookup = {};
6709
6710 if (opts.IsReadyToRun())
6711 {
6712 helper = CORINFO_HELP_READYTORUN_NEW;
6713 CORINFO_LOOKUP_KIND* const pGenericLookupKind = nullptr;
6714 usingReadyToRunHelper =
6715 info.compCompHnd->getReadyToRunHelper(pResolvedToken, pGenericLookupKind, helper, &lookup);
6716 }
6717#endif
6718
6719 if (!usingReadyToRunHelper)
6720 {
6721 if (opHandle == nullptr)
6722 {
6723 // We must be backing out of an inline.
6724 assert(compDonotInline());
6725 return nullptr;
6726 }
6727 }
6728
6729 bool helperHasSideEffects;
6730 CorInfoHelpFunc helperTemp =
6731 info.compCompHnd->getNewHelper(pResolvedToken, info.compMethodHnd, &helperHasSideEffects);
6732
6733 if (!usingReadyToRunHelper)
6734 {
6735 helper = helperTemp;
6736 }
6737
6738 // TODO: ReadyToRun: When generic dictionary lookups are necessary, replace the lookup call
6739 // and the newfast call with a single call to a dynamic R2R cell that will:
6740 // 1) Load the context
6741 // 2) Perform the generic dictionary lookup and caching, and generate the appropriate stub
6742 // 3) Allocate and return the new object for boxing
6743 // Reason: performance (today, we'll always use the slow helper for the R2R generics case)
6744
6745 GenTreeAllocObj* allocObj =
6746 gtNewAllocObjNode(helper, helperHasSideEffects, pResolvedToken->hClass, TYP_REF, opHandle);
6747
6748#ifdef FEATURE_READYTORUN_COMPILER
6749 if (usingReadyToRunHelper)
6750 {
6751 allocObj->gtEntryPoint = lookup;
6752 }
6753#endif
6754
6755 return allocObj;
6756}
6757
6758/*****************************************************************************
6759 *
6760 * Clones the given tree value and returns a copy of the given tree.
6761 * If 'complexOK' is false, the cloning is only done provided the tree
6762 * is not too complex (whatever that may mean);
6763 * If 'complexOK' is true, we try slightly harder to clone the tree.
6764 * In either case, NULL is returned if the tree cannot be cloned
6765 *
6766 * Note that there is the function gtCloneExpr() which does a more
6767 * complete job if you can't handle this function failing.
6768 */
6769
6770GenTree* Compiler::gtClone(GenTree* tree, bool complexOK)
6771{
6772 GenTree* copy;
6773
6774 switch (tree->gtOper)
6775 {
6776 case GT_CNS_INT:
6777
6778#if defined(LATE_DISASM)
6779 if (tree->IsIconHandle())
6780 {
6781 copy = gtNewIconHandleNode(tree->gtIntCon.gtIconVal, tree->gtFlags, tree->gtIntCon.gtFieldSeq);
6782 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6783 copy->gtType = tree->gtType;
6784 }
6785 else
6786#endif
6787 {
6788 copy = new (this, GT_CNS_INT)
6789 GenTreeIntCon(tree->gtType, tree->gtIntCon.gtIconVal, tree->gtIntCon.gtFieldSeq);
6790 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6791 }
6792 break;
6793
6794 case GT_CNS_LNG:
6795 copy = gtNewLconNode(tree->gtLngCon.gtLconVal);
6796 break;
6797
6798 case GT_LCL_VAR:
6799 // Remember that the LclVar node has been cloned. The flag will be set
6800 // on 'copy' as well.
6801 tree->gtFlags |= GTF_VAR_CLONED;
6802 copy = gtNewLclvNode(tree->gtLclVarCommon.gtLclNum, tree->gtType, tree->gtLclVar.gtLclILoffs);
6803 break;
6804
6805 case GT_LCL_FLD:
6806 case GT_LCL_FLD_ADDR:
6807 // Remember that the LclVar node has been cloned. The flag will be set
6808 // on 'copy' as well.
6809 tree->gtFlags |= GTF_VAR_CLONED;
6810 copy = new (this, tree->gtOper)
6811 GenTreeLclFld(tree->gtOper, tree->TypeGet(), tree->gtLclFld.gtLclNum, tree->gtLclFld.gtLclOffs);
6812 copy->gtLclFld.gtFieldSeq = tree->gtLclFld.gtFieldSeq;
6813 break;
6814
6815 case GT_CLS_VAR:
6816 copy = new (this, GT_CLS_VAR)
6817 GenTreeClsVar(tree->gtType, tree->gtClsVar.gtClsVarHnd, tree->gtClsVar.gtFieldSeq);
6818 break;
6819
6820 default:
6821 if (!complexOK)
6822 {
6823 return nullptr;
6824 }
6825
6826 if (tree->gtOper == GT_FIELD)
6827 {
6828 GenTree* objp;
6829
6830 // copied from line 9850
6831
6832 objp = nullptr;
6833 if (tree->gtField.gtFldObj)
6834 {
6835 objp = gtClone(tree->gtField.gtFldObj, false);
6836 if (!objp)
6837 {
6838 return objp;
6839 }
6840 }
6841
6842 copy = gtNewFieldRef(tree->TypeGet(), tree->gtField.gtFldHnd, objp, tree->gtField.gtFldOffset);
6843 copy->gtField.gtFldMayOverlap = tree->gtField.gtFldMayOverlap;
6844#ifdef FEATURE_READYTORUN_COMPILER
6845 copy->gtField.gtFieldLookup = tree->gtField.gtFieldLookup;
6846#endif
6847 }
6848 else if (tree->OperIs(GT_ADD, GT_SUB))
6849 {
6850 GenTree* op1 = tree->gtOp.gtOp1;
6851 GenTree* op2 = tree->gtOp.gtOp2;
6852
6853 if (op1->OperIsLeaf() && op2->OperIsLeaf())
6854 {
6855 op1 = gtClone(op1);
6856 if (op1 == nullptr)
6857 {
6858 return nullptr;
6859 }
6860 op2 = gtClone(op2);
6861 if (op2 == nullptr)
6862 {
6863 return nullptr;
6864 }
6865
6866 copy = gtNewOperNode(tree->OperGet(), tree->TypeGet(), op1, op2);
6867 }
6868 else
6869 {
6870 return nullptr;
6871 }
6872 }
6873 else if (tree->gtOper == GT_ADDR)
6874 {
6875 GenTree* op1 = gtClone(tree->gtOp.gtOp1);
6876 if (op1 == nullptr)
6877 {
6878 return nullptr;
6879 }
6880 copy = gtNewOperNode(GT_ADDR, tree->TypeGet(), op1);
6881 }
6882 else
6883 {
6884 return nullptr;
6885 }
6886
6887 break;
6888 }
6889
6890 copy->gtFlags |= tree->gtFlags & ~GTF_NODE_MASK;
6891#if defined(DEBUG)
6892 copy->gtDebugFlags |= tree->gtDebugFlags & ~GTF_DEBUG_NODE_MASK;
6893#endif // defined(DEBUG)
6894
6895 return copy;
6896}
6897
6898//------------------------------------------------------------------------
6899// gtCloneExpr: Create a copy of `tree`, adding flags `addFlags`, mapping
6900// local `varNum` to int constant `varVal` if it appears at
6901// the root, and mapping uses of local `deepVarNum` to constant
6902// `deepVarVal` if they occur beyond the root.
6903//
6904// Arguments:
6905// tree - GenTree to create a copy of
6906// addFlags - GTF_* flags to add to the copied tree nodes
6907// varNum - lclNum to replace at the root, or ~0 for no root replacement
6908// varVal - If replacing at root, replace local `varNum` with IntCns `varVal`
6909// deepVarNum - lclNum to replace uses of beyond the root, or ~0 for no replacement
6910// deepVarVal - If replacing beyond root, replace `deepVarNum` with IntCns `deepVarVal`
6911//
6912// Return Value:
6913// A copy of the given tree with the replacements and added flags specified.
6914//
6915// Notes:
6916// Top-level callers should generally call the overload that doesn't have
6917// the explicit `deepVarNum` and `deepVarVal` parameters; those are used in
6918// recursive invocations to avoid replacing defs.
6919
6920GenTree* Compiler::gtCloneExpr(
6921 GenTree* tree, unsigned addFlags, unsigned varNum, int varVal, unsigned deepVarNum, int deepVarVal)
6922{
6923 if (tree == nullptr)
6924 {
6925 return nullptr;
6926 }
6927
6928 /* Figure out what kind of a node we have */
6929
6930 genTreeOps oper = tree->OperGet();
6931 unsigned kind = tree->OperKind();
6932 GenTree* copy;
6933
6934 /* Is this a constant or leaf node? */
6935
6936 if (kind & (GTK_CONST | GTK_LEAF))
6937 {
6938 switch (oper)
6939 {
6940 case GT_CNS_INT:
6941
6942#if defined(LATE_DISASM)
6943 if (tree->IsIconHandle())
6944 {
6945 copy = gtNewIconHandleNode(tree->gtIntCon.gtIconVal, tree->gtFlags, tree->gtIntCon.gtFieldSeq);
6946 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6947 copy->gtType = tree->gtType;
6948 }
6949 else
6950#endif
6951 {
6952 copy = gtNewIconNode(tree->gtIntCon.gtIconVal, tree->gtType);
6953 copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
6954 copy->gtIntCon.gtFieldSeq = tree->gtIntCon.gtFieldSeq;
6955 }
6956 goto DONE;
6957
6958 case GT_CNS_LNG:
6959 copy = gtNewLconNode(tree->gtLngCon.gtLconVal);
6960 goto DONE;
6961
6962 case GT_CNS_DBL:
6963 copy = gtNewDconNode(tree->gtDblCon.gtDconVal);
6964 copy->gtType = tree->gtType; // keep the same type
6965 goto DONE;
6966
6967 case GT_CNS_STR:
6968 copy = gtNewSconNode(tree->gtStrCon.gtSconCPX, tree->gtStrCon.gtScpHnd);
6969 goto DONE;
6970
6971 case GT_LCL_VAR:
6972
6973 if (tree->gtLclVarCommon.gtLclNum == varNum)
6974 {
6975 copy = gtNewIconNode(varVal, tree->gtType);
6976 if (tree->gtFlags & GTF_VAR_ARR_INDEX)
6977 {
6978 copy->LabelIndex(this);
6979 }
6980 }
6981 else
6982 {
6983 // Remember that the LclVar node has been cloned. The flag will
6984 // be set on 'copy' as well.
6985 tree->gtFlags |= GTF_VAR_CLONED;
6986 copy = gtNewLclvNode(tree->gtLclVar.gtLclNum, tree->gtType, tree->gtLclVar.gtLclILoffs);
6987 copy->AsLclVarCommon()->SetSsaNum(tree->AsLclVarCommon()->GetSsaNum());
6988 }
6989 copy->gtFlags = tree->gtFlags;
6990 goto DONE;
6991
6992 case GT_LCL_FLD:
6993 if (tree->gtLclFld.gtLclNum == varNum)
6994 {
6995 IMPL_LIMITATION("replacing GT_LCL_FLD with a constant");
6996 }
6997 else
6998 {
6999 // Remember that the LclVar node has been cloned. The flag will
7000 // be set on 'copy' as well.
7001 tree->gtFlags |= GTF_VAR_CLONED;
7002 copy = new (this, GT_LCL_FLD)
7003 GenTreeLclFld(tree->TypeGet(), tree->gtLclFld.gtLclNum, tree->gtLclFld.gtLclOffs);
7004 copy->gtLclFld.gtFieldSeq = tree->gtLclFld.gtFieldSeq;
7005 copy->gtFlags = tree->gtFlags;
7006 }
7007 goto DONE;
7008
7009 case GT_CLS_VAR:
7010 copy = new (this, GT_CLS_VAR)
7011 GenTreeClsVar(tree->TypeGet(), tree->gtClsVar.gtClsVarHnd, tree->gtClsVar.gtFieldSeq);
7012 goto DONE;
7013
7014 case GT_RET_EXPR:
7015 // GT_RET_EXPR is unique node, that contains a link to a gtInlineCandidate node,
7016 // that is part of another statement. We cannot clone both here and cannot
7017 // create another GT_RET_EXPR that points to the same gtInlineCandidate.
7018 NO_WAY("Cloning of GT_RET_EXPR node not supported");
7019 goto DONE;
7020
7021 case GT_MEMORYBARRIER:
7022 copy = new (this, GT_MEMORYBARRIER) GenTree(GT_MEMORYBARRIER, TYP_VOID);
7023 goto DONE;
7024
7025 case GT_ARGPLACE:
7026 copy = gtNewArgPlaceHolderNode(tree->gtType, tree->gtArgPlace.gtArgPlaceClsHnd);
7027 goto DONE;
7028
7029 case GT_FTN_ADDR:
7030 copy = new (this, oper) GenTreeFptrVal(tree->gtType, tree->gtFptrVal.gtFptrMethod);
7031
7032#ifdef FEATURE_READYTORUN_COMPILER
7033 copy->gtFptrVal.gtEntryPoint = tree->gtFptrVal.gtEntryPoint;
7034#endif
7035 goto DONE;
7036
7037 case GT_CATCH_ARG:
7038 case GT_NO_OP:
7039 copy = new (this, oper) GenTree(oper, tree->gtType);
7040 goto DONE;
7041
7042#if !FEATURE_EH_FUNCLETS
7043 case GT_END_LFIN:
7044#endif // !FEATURE_EH_FUNCLETS
7045 case GT_JMP:
7046 copy = new (this, oper) GenTreeVal(oper, tree->gtType, tree->gtVal.gtVal1);
7047 goto DONE;
7048
7049 case GT_LABEL:
7050 copy = new (this, oper) GenTreeLabel(tree->gtLabel.gtLabBB);
7051 goto DONE;
7052
7053 default:
7054 NO_WAY("Cloning of node not supported");
7055 goto DONE;
7056 }
7057 }
7058
7059 /* Is it a 'simple' unary/binary operator? */
7060
7061 if (kind & GTK_SMPOP)
7062 {
7063 /* If necessary, make sure we allocate a "fat" tree node */
7064 CLANG_FORMAT_COMMENT_ANCHOR;
7065
7066#if SMALL_TREE_NODES
7067 switch (oper)
7068 {
7069 /* These nodes sometimes get bashed to "fat" ones */
7070
7071 case GT_MUL:
7072 case GT_DIV:
7073 case GT_MOD:
7074
7075 case GT_UDIV:
7076 case GT_UMOD:
7077
7078 // In the implementation of gtNewLargeOperNode you have
7079 // to give an oper that will create a small node,
7080 // otherwise it asserts.
7081 //
7082 if (GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL)
7083 {
7084 copy = gtNewLargeOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1,
7085 tree->OperIsBinary() ? tree->gtOp.gtOp2 : nullptr);
7086 }
7087 else // Always a large tree
7088 {
7089 if (tree->OperIsBinary())
7090 {
7091 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2);
7092 }
7093 else
7094 {
7095 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1);
7096 }
7097 }
7098 break;
7099
7100 case GT_CAST:
7101 copy =
7102 new (this, LargeOpOpcode()) GenTreeCast(tree->TypeGet(), tree->gtCast.CastOp(), tree->IsUnsigned(),
7103 tree->gtCast.gtCastType DEBUGARG(/*largeNode*/ TRUE));
7104 break;
7105
7106 // The nodes below this are not bashed, so they can be allocated at their individual sizes.
7107
7108 case GT_LIST:
7109 assert((tree->gtOp.gtOp2 == nullptr) || tree->gtOp.gtOp2->OperIsList());
7110 copy = new (this, GT_LIST) GenTreeArgList(tree->gtOp.gtOp1);
7111 copy->gtOp.gtOp2 = tree->gtOp.gtOp2;
7112 break;
7113
7114 case GT_FIELD_LIST:
7115 copy = new (this, GT_FIELD_LIST) GenTreeFieldList(tree->gtOp.gtOp1, tree->AsFieldList()->gtFieldOffset,
7116 tree->AsFieldList()->gtFieldType, nullptr);
7117 copy->gtOp.gtOp2 = tree->gtOp.gtOp2;
7118 copy->gtFlags = (copy->gtFlags & ~GTF_FIELD_LIST_HEAD) | (tree->gtFlags & GTF_FIELD_LIST_HEAD);
7119 break;
7120
7121 case GT_INDEX:
7122 {
7123 GenTreeIndex* asInd = tree->AsIndex();
7124 copy = new (this, GT_INDEX)
7125 GenTreeIndex(asInd->TypeGet(), asInd->Arr(), asInd->Index(), asInd->gtIndElemSize);
7126 copy->AsIndex()->gtStructElemClass = asInd->gtStructElemClass;
7127 }
7128 break;
7129
7130 case GT_INDEX_ADDR:
7131 {
7132 GenTreeIndexAddr* asIndAddr = tree->AsIndexAddr();
7133
7134 copy = new (this, GT_INDEX_ADDR)
7135 GenTreeIndexAddr(asIndAddr->Arr(), asIndAddr->Index(), asIndAddr->gtElemType,
7136 asIndAddr->gtStructElemClass, asIndAddr->gtElemSize, asIndAddr->gtLenOffset,
7137 asIndAddr->gtElemOffset);
7138 copy->AsIndexAddr()->gtIndRngFailBB = asIndAddr->gtIndRngFailBB;
7139 }
7140 break;
7141
7142 case GT_ALLOCOBJ:
7143 {
7144 GenTreeAllocObj* asAllocObj = tree->AsAllocObj();
7145 copy = new (this, GT_ALLOCOBJ)
7146 GenTreeAllocObj(tree->TypeGet(), asAllocObj->gtNewHelper, asAllocObj->gtHelperHasSideEffects,
7147 asAllocObj->gtAllocObjClsHnd, asAllocObj->gtOp1);
7148 }
7149 break;
7150
7151 case GT_RUNTIMELOOKUP:
7152 {
7153 GenTreeRuntimeLookup* asRuntimeLookup = tree->AsRuntimeLookup();
7154
7155 copy = new (this, GT_RUNTIMELOOKUP)
7156 GenTreeRuntimeLookup(asRuntimeLookup->gtHnd, asRuntimeLookup->gtHndType, asRuntimeLookup->gtOp1);
7157 }
7158 break;
7159
7160 case GT_ARR_LENGTH:
7161 copy = gtNewArrLen(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtArrLen.ArrLenOffset());
7162 break;
7163
7164 case GT_ARR_INDEX:
7165 copy = new (this, GT_ARR_INDEX)
7166 GenTreeArrIndex(tree->TypeGet(),
7167 gtCloneExpr(tree->gtArrIndex.ArrObj(), addFlags, deepVarNum, deepVarVal),
7168 gtCloneExpr(tree->gtArrIndex.IndexExpr(), addFlags, deepVarNum, deepVarVal),
7169 tree->gtArrIndex.gtCurrDim, tree->gtArrIndex.gtArrRank,
7170 tree->gtArrIndex.gtArrElemType);
7171 break;
7172
7173 case GT_QMARK:
7174 copy = new (this, GT_QMARK) GenTreeQmark(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2, this);
7175 break;
7176
7177 case GT_OBJ:
7178 copy = new (this, GT_OBJ)
7179 GenTreeObj(tree->TypeGet(), tree->gtOp.gtOp1, tree->AsObj()->gtClass, tree->gtBlk.gtBlkSize);
7180 copy->AsObj()->CopyGCInfo(tree->AsObj());
7181 copy->gtBlk.gtBlkOpGcUnsafe = tree->gtBlk.gtBlkOpGcUnsafe;
7182 break;
7183
7184 case GT_BLK:
7185 copy = new (this, GT_BLK) GenTreeBlk(GT_BLK, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtBlk.gtBlkSize);
7186 copy->gtBlk.gtBlkOpGcUnsafe = tree->gtBlk.gtBlkOpGcUnsafe;
7187 break;
7188
7189 case GT_DYN_BLK:
7190 copy = new (this, GT_DYN_BLK) GenTreeDynBlk(tree->gtOp.gtOp1, tree->gtDynBlk.gtDynamicSize);
7191 copy->gtBlk.gtBlkOpGcUnsafe = tree->gtBlk.gtBlkOpGcUnsafe;
7192 break;
7193
7194 case GT_BOX:
7195 copy = new (this, GT_BOX)
7196 GenTreeBox(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtBox.gtAsgStmtWhenInlinedBoxValue,
7197 tree->gtBox.gtCopyStmtWhenInlinedBoxValue);
7198 break;
7199
7200 case GT_INTRINSIC:
7201 copy = new (this, GT_INTRINSIC)
7202 GenTreeIntrinsic(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2,
7203 tree->gtIntrinsic.gtIntrinsicId, tree->gtIntrinsic.gtMethodHandle);
7204#ifdef FEATURE_READYTORUN_COMPILER
7205 copy->gtIntrinsic.gtEntryPoint = tree->gtIntrinsic.gtEntryPoint;
7206#endif
7207 break;
7208
7209 case GT_LEA:
7210 {
7211 GenTreeAddrMode* addrModeOp = tree->AsAddrMode();
7212 copy = new (this, GT_LEA)
7213 GenTreeAddrMode(addrModeOp->TypeGet(), addrModeOp->Base(), addrModeOp->Index(), addrModeOp->gtScale,
7214 static_cast<unsigned>(addrModeOp->Offset()));
7215 }
7216 break;
7217
7218 case GT_COPY:
7219 case GT_RELOAD:
7220 {
7221 copy = new (this, oper) GenTreeCopyOrReload(oper, tree->TypeGet(), tree->gtGetOp1());
7222 }
7223 break;
7224
7225#ifdef FEATURE_SIMD
7226 case GT_SIMD:
7227 {
7228 GenTreeSIMD* simdOp = tree->AsSIMD();
7229 copy = gtNewSIMDNode(simdOp->TypeGet(), simdOp->gtGetOp1(), simdOp->gtGetOp2IfPresent(),
7230 simdOp->gtSIMDIntrinsicID, simdOp->gtSIMDBaseType, simdOp->gtSIMDSize);
7231 }
7232 break;
7233#endif
7234
7235#ifdef FEATURE_HW_INTRINSICS
7236 case GT_HWIntrinsic:
7237 {
7238 GenTreeHWIntrinsic* hwintrinsicOp = tree->AsHWIntrinsic();
7239 copy = new (this, GT_HWIntrinsic)
7240 GenTreeHWIntrinsic(hwintrinsicOp->TypeGet(), hwintrinsicOp->gtGetOp1(),
7241 hwintrinsicOp->gtGetOp2IfPresent(), hwintrinsicOp->gtHWIntrinsicId,
7242 hwintrinsicOp->gtSIMDBaseType, hwintrinsicOp->gtSIMDSize);
7243 copy->AsHWIntrinsic()->gtIndexBaseType = hwintrinsicOp->gtIndexBaseType;
7244 }
7245 break;
7246#endif
7247
7248 default:
7249 assert(!GenTree::IsExOp(tree->OperKind()) && tree->OperIsSimple());
7250 // We're in the SimpleOp case, so it's always unary or binary.
7251 if (GenTree::OperIsUnary(tree->OperGet()))
7252 {
7253 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, /*doSimplifications*/ false);
7254 }
7255 else
7256 {
7257 assert(GenTree::OperIsBinary(tree->OperGet()));
7258 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2);
7259 }
7260 break;
7261 }
7262#else
7263 // We're in the SimpleOp case, so it's always unary or binary.
7264 copy = gtNewOperNode(oper, tree->TypeGet(), tree->gtOp.gtOp1, tree->gtOp.gtOp2);
7265#endif
7266
7267 // Some flags are conceptually part of the gtOper, and should be copied immediately.
7268 if (tree->gtOverflowEx())
7269 {
7270 copy->gtFlags |= GTF_OVERFLOW;
7271 }
7272
7273 if (tree->gtOp.gtOp1)
7274 {
7275 if (tree->gtOper == GT_ASG)
7276 {
7277 // Don't replace varNum if it appears as the LHS of an assign.
7278 copy->gtOp.gtOp1 = gtCloneExpr(tree->gtOp.gtOp1, addFlags, -1, 0, deepVarNum, deepVarVal);
7279 }
7280 else
7281 {
7282 copy->gtOp.gtOp1 = gtCloneExpr(tree->gtOp.gtOp1, addFlags, deepVarNum, deepVarVal);
7283 }
7284 }
7285
7286 if (tree->gtGetOp2IfPresent())
7287 {
7288 copy->gtOp.gtOp2 = gtCloneExpr(tree->gtOp.gtOp2, addFlags, deepVarNum, deepVarVal);
7289 }
7290
7291 /* Flags */
7292 addFlags |= tree->gtFlags;
7293
7294 // Copy any node annotations, if necessary.
7295 switch (tree->gtOper)
7296 {
7297 case GT_STOREIND:
7298 case GT_IND:
7299 case GT_OBJ:
7300 case GT_STORE_OBJ:
7301 {
7302 ArrayInfo arrInfo;
7303 if (!tree->AsIndir()->gtOp1->OperIs(GT_INDEX_ADDR) && TryGetArrayInfo(tree->AsIndir(), &arrInfo))
7304 {
7305 GetArrayInfoMap()->Set(copy, arrInfo);
7306 }
7307 }
7308 break;
7309
7310 default:
7311 break;
7312 }
7313
7314#ifdef DEBUG
7315 /* GTF_NODE_MASK should not be propagated from 'tree' to 'copy' */
7316 addFlags &= ~GTF_NODE_MASK;
7317#endif
7318
7319 // Effects flags propagate upwards.
7320 if (copy->gtOp.gtOp1 != nullptr)
7321 {
7322 copy->gtFlags |= (copy->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
7323 }
7324 if (copy->gtGetOp2IfPresent() != nullptr)
7325 {
7326 copy->gtFlags |= (copy->gtGetOp2()->gtFlags & GTF_ALL_EFFECT);
7327 }
7328
7329 goto DONE;
7330 }
7331
7332 /* See what kind of a special operator we have here */
7333
7334 switch (oper)
7335 {
7336 case GT_STMT:
7337 copy = gtCloneExpr(tree->gtStmt.gtStmtExpr, addFlags, deepVarNum, deepVarVal);
7338 copy = gtNewStmt(copy, tree->gtStmt.gtStmtILoffsx);
7339 goto DONE;
7340
7341 case GT_CALL:
7342
7343 // We can't safely clone calls that have GT_RET_EXPRs via gtCloneExpr.
7344 // You must use gtCloneCandidateCall for these calls (and then do appropriate other fixup)
7345 if (tree->gtCall.IsInlineCandidate() || tree->gtCall.IsGuardedDevirtualizationCandidate())
7346 {
7347 NO_WAY("Cloning of calls with associated GT_RET_EXPR nodes is not supported");
7348 }
7349
7350 copy = gtCloneExprCallHelper(tree->AsCall(), addFlags, deepVarNum, deepVarVal);
7351 break;
7352
7353 case GT_FIELD:
7354
7355 copy = gtNewFieldRef(tree->TypeGet(), tree->gtField.gtFldHnd, nullptr, tree->gtField.gtFldOffset);
7356
7357 copy->gtField.gtFldObj = tree->gtField.gtFldObj
7358 ? gtCloneExpr(tree->gtField.gtFldObj, addFlags, deepVarNum, deepVarVal)
7359 : nullptr;
7360 copy->gtField.gtFldMayOverlap = tree->gtField.gtFldMayOverlap;
7361#ifdef FEATURE_READYTORUN_COMPILER
7362 copy->gtField.gtFieldLookup = tree->gtField.gtFieldLookup;
7363#endif
7364
7365 break;
7366
7367 case GT_ARR_ELEM:
7368 {
7369 GenTree* inds[GT_ARR_MAX_RANK];
7370 for (unsigned dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
7371 {
7372 inds[dim] = gtCloneExpr(tree->gtArrElem.gtArrInds[dim], addFlags, deepVarNum, deepVarVal);
7373 }
7374 copy = new (this, GT_ARR_ELEM)
7375 GenTreeArrElem(tree->TypeGet(), gtCloneExpr(tree->gtArrElem.gtArrObj, addFlags, deepVarNum, deepVarVal),
7376 tree->gtArrElem.gtArrRank, tree->gtArrElem.gtArrElemSize, tree->gtArrElem.gtArrElemType,
7377 &inds[0]);
7378 }
7379 break;
7380
7381 case GT_ARR_OFFSET:
7382 {
7383 copy = new (this, GT_ARR_OFFSET)
7384 GenTreeArrOffs(tree->TypeGet(), gtCloneExpr(tree->gtArrOffs.gtOffset, addFlags, deepVarNum, deepVarVal),
7385 gtCloneExpr(tree->gtArrOffs.gtIndex, addFlags, deepVarNum, deepVarVal),
7386 gtCloneExpr(tree->gtArrOffs.gtArrObj, addFlags, deepVarNum, deepVarVal),
7387 tree->gtArrOffs.gtCurrDim, tree->gtArrOffs.gtArrRank, tree->gtArrOffs.gtArrElemType);
7388 }
7389 break;
7390
7391 case GT_CMPXCHG:
7392 copy = new (this, GT_CMPXCHG)
7393 GenTreeCmpXchg(tree->TypeGet(),
7394 gtCloneExpr(tree->gtCmpXchg.gtOpLocation, addFlags, deepVarNum, deepVarVal),
7395 gtCloneExpr(tree->gtCmpXchg.gtOpValue, addFlags, deepVarNum, deepVarVal),
7396 gtCloneExpr(tree->gtCmpXchg.gtOpComparand, addFlags, deepVarNum, deepVarVal));
7397 break;
7398
7399 case GT_ARR_BOUNDS_CHECK:
7400#ifdef FEATURE_SIMD
7401 case GT_SIMD_CHK:
7402#endif // FEATURE_SIMD
7403#ifdef FEATURE_HW_INTRINSICS
7404 case GT_HW_INTRINSIC_CHK:
7405#endif // FEATURE_HW_INTRINSICS
7406 copy = new (this, oper)
7407 GenTreeBoundsChk(oper, tree->TypeGet(),
7408 gtCloneExpr(tree->gtBoundsChk.gtIndex, addFlags, deepVarNum, deepVarVal),
7409 gtCloneExpr(tree->gtBoundsChk.gtArrLen, addFlags, deepVarNum, deepVarVal),
7410 tree->gtBoundsChk.gtThrowKind);
7411 copy->gtBoundsChk.gtIndRngFailBB = tree->gtBoundsChk.gtIndRngFailBB;
7412 break;
7413
7414 case GT_STORE_DYN_BLK:
7415 case GT_DYN_BLK:
7416 copy = new (this, oper)
7417 GenTreeDynBlk(gtCloneExpr(tree->gtDynBlk.Addr(), addFlags, deepVarNum, deepVarVal),
7418 gtCloneExpr(tree->gtDynBlk.gtDynamicSize, addFlags, deepVarNum, deepVarVal));
7419 break;
7420
7421 default:
7422#ifdef DEBUG
7423 gtDispTree(tree);
7424#endif
7425 NO_WAY("unexpected operator");
7426 }
7427
7428DONE:
7429
7430 // If it has a zero-offset field seq, copy annotation.
7431 if (tree->TypeGet() == TYP_BYREF)
7432 {
7433 FieldSeqNode* fldSeq = nullptr;
7434 if (GetZeroOffsetFieldMap()->Lookup(tree, &fldSeq))
7435 {
7436 GetZeroOffsetFieldMap()->Set(copy, fldSeq);
7437 }
7438 }
7439
7440 copy->gtVNPair = tree->gtVNPair; // A cloned tree gets the orginal's Value number pair
7441
7442 /* Compute the flags for the copied node. Note that we can do this only
7443 if we didnt gtFoldExpr(copy) */
7444
7445 if (copy->gtOper == oper)
7446 {
7447 addFlags |= tree->gtFlags;
7448
7449#ifdef DEBUG
7450 /* GTF_NODE_MASK should not be propagated from 'tree' to 'copy' */
7451 addFlags &= ~GTF_NODE_MASK;
7452#endif
7453 // Some other flags depend on the context of the expression, and should not be preserved.
7454 // For example, GTF_RELOP_QMARK:
7455 if (copy->OperKind() & GTK_RELOP)
7456 {
7457 addFlags &= ~GTF_RELOP_QMARK;
7458 }
7459 // On the other hand, if we're creating such a context, restore this flag.
7460 if (copy->OperGet() == GT_QMARK)
7461 {
7462 copy->gtOp.gtOp1->gtFlags |= GTF_RELOP_QMARK;
7463 }
7464
7465 copy->gtFlags |= addFlags;
7466
7467 // Update side effect flags since they may be different from the source side effect flags.
7468 // For example, we may have replaced some locals with constants and made indirections non-throwing.
7469 gtUpdateNodeSideEffects(copy);
7470 }
7471
7472 /* GTF_COLON_COND should be propagated from 'tree' to 'copy' */
7473 copy->gtFlags |= (tree->gtFlags & GTF_COLON_COND);
7474
7475#if defined(DEBUG)
7476 // Non-node debug flags should be propagated from 'tree' to 'copy'
7477 copy->gtDebugFlags |= (tree->gtDebugFlags & ~GTF_DEBUG_NODE_MASK);
7478#endif
7479
7480 /* Make sure to copy back fields that may have been initialized */
7481
7482 copy->CopyRawCosts(tree);
7483 copy->gtRsvdRegs = tree->gtRsvdRegs;
7484 copy->CopyReg(tree);
7485 return copy;
7486}
7487
7488//------------------------------------------------------------------------
7489// gtCloneExprCallHelper: clone a call tree
7490//
7491// Notes:
7492// Do not invoke this method directly, instead call either gtCloneExpr
7493// or gtCloneCandidateCall, as appropriate.
7494//
7495// Arguments:
7496// tree - the call to clone
7497// addFlags - GTF_* flags to add to the copied tree nodes
7498// deepVarNum - lclNum to replace uses of beyond the root, or BAD_VAR_NUM for no replacement
7499// deepVarVal - If replacing beyond root, replace `deepVarNum` with IntCns `deepVarVal`
7500//
7501// Returns:
7502// Cloned copy of call and all subtrees.
7503
7504GenTreeCall* Compiler::gtCloneExprCallHelper(GenTreeCall* tree, unsigned addFlags, unsigned deepVarNum, int deepVarVal)
7505{
7506 GenTreeCall* copy = new (this, GT_CALL) GenTreeCall(tree->TypeGet());
7507
7508 copy->gtCallObjp = tree->gtCallObjp ? gtCloneExpr(tree->gtCallObjp, addFlags, deepVarNum, deepVarVal) : nullptr;
7509 copy->gtCallArgs =
7510 tree->gtCallArgs ? gtCloneExpr(tree->gtCallArgs, addFlags, deepVarNum, deepVarVal)->AsArgList() : nullptr;
7511 copy->gtCallMoreFlags = tree->gtCallMoreFlags;
7512 copy->gtCallLateArgs = tree->gtCallLateArgs
7513 ? gtCloneExpr(tree->gtCallLateArgs, addFlags, deepVarNum, deepVarVal)->AsArgList()
7514 : nullptr;
7515
7516#if !FEATURE_FIXED_OUT_ARGS
7517 copy->regArgList = tree->regArgList;
7518 copy->regArgListCount = tree->regArgListCount;
7519#endif
7520
7521 // The call sig comes from the EE and doesn't change throughout the compilation process, meaning
7522 // we only really need one physical copy of it. Therefore a shallow pointer copy will suffice.
7523 // (Note that this still holds even if the tree we are cloning was created by an inlinee compiler,
7524 // because the inlinee still uses the inliner's memory allocator anyway.)
7525 copy->callSig = tree->callSig;
7526
7527 copy->gtCallType = tree->gtCallType;
7528 copy->gtReturnType = tree->gtReturnType;
7529 copy->gtControlExpr = tree->gtControlExpr;
7530
7531 /* Copy the union */
7532 if (tree->gtCallType == CT_INDIRECT)
7533 {
7534 copy->gtCallCookie =
7535 tree->gtCallCookie ? gtCloneExpr(tree->gtCallCookie, addFlags, deepVarNum, deepVarVal) : nullptr;
7536 copy->gtCallAddr = tree->gtCallAddr ? gtCloneExpr(tree->gtCallAddr, addFlags, deepVarNum, deepVarVal) : nullptr;
7537 }
7538 else if (tree->IsVirtualStub())
7539 {
7540 copy->gtCallMethHnd = tree->gtCallMethHnd;
7541 copy->gtStubCallStubAddr = tree->gtStubCallStubAddr;
7542 }
7543 else
7544 {
7545 copy->gtCallMethHnd = tree->gtCallMethHnd;
7546 copy->gtInlineCandidateInfo = nullptr;
7547 }
7548
7549 if (tree->fgArgInfo)
7550 {
7551 // Create and initialize the fgArgInfo for our copy of the call tree
7552 copy->fgArgInfo = new (this, CMK_Unknown) fgArgInfo(copy, tree);
7553 }
7554 else
7555 {
7556 copy->fgArgInfo = nullptr;
7557 }
7558
7559 copy->gtRetClsHnd = tree->gtRetClsHnd;
7560
7561#if FEATURE_MULTIREG_RET
7562 copy->gtReturnTypeDesc = tree->gtReturnTypeDesc;
7563#endif
7564
7565#ifdef FEATURE_READYTORUN_COMPILER
7566 copy->setEntryPoint(tree->gtEntryPoint);
7567#endif
7568
7569#if defined(DEBUG) || defined(INLINE_DATA)
7570 copy->gtInlineObservation = tree->gtInlineObservation;
7571 copy->gtRawILOffset = tree->gtCall.gtRawILOffset;
7572#endif
7573
7574 copy->CopyOtherRegFlags(tree);
7575
7576 return copy;
7577}
7578
7579//------------------------------------------------------------------------
7580// gtCloneCandidateCall: clone a call that is an inline or guarded
7581// devirtualization candidate (~ any call that can have a GT_RET_EXPR)
7582//
7583// Notes:
7584// If the call really is a candidate, the caller must take additional steps
7585// after cloning to re-establish candidate info and the relationship between
7586// the candidate and any associated GT_RET_EXPR.
7587//
7588// Arguments:
7589// call - the call to clone
7590//
7591// Returns:
7592// Cloned copy of call and all subtrees.
7593
7594GenTreeCall* Compiler::gtCloneCandidateCall(GenTreeCall* call)
7595{
7596 assert(call->IsInlineCandidate() || call->IsGuardedDevirtualizationCandidate());
7597
7598 GenTreeCall* result = gtCloneExprCallHelper(call);
7599
7600 // There is some common post-processing in gtCloneExpr that we reproduce
7601 // here, for the fields that make sense for candidate calls.
7602 result->gtFlags |= call->gtFlags;
7603
7604#if defined(DEBUG)
7605 result->gtDebugFlags |= (call->gtDebugFlags & ~GTF_DEBUG_NODE_MASK);
7606#endif
7607
7608 result->CopyReg(call);
7609
7610 return result;
7611}
7612
7613//------------------------------------------------------------------------
7614// gtReplaceTree: Replace a tree with a new tree.
7615//
7616// Arguments:
7617// stmt - The top-level root stmt of the tree being replaced.
7618// Must not be null.
7619// tree - The tree being replaced. Must not be null.
7620// replacementTree - The replacement tree. Must not be null.
7621//
7622// Return Value:
7623// The tree node that replaces the old tree.
7624//
7625// Assumptions:
7626// The sequencing of the stmt has been done.
7627//
7628// Notes:
7629// The caller must ensure that the original statement has been sequenced,
7630// and the side effect flags are updated on the statement nodes,
7631// but this method will sequence 'replacementTree', and insert it into the
7632// proper place in the statement sequence.
7633
7634GenTree* Compiler::gtReplaceTree(GenTree* stmt, GenTree* tree, GenTree* replacementTree)
7635{
7636 assert(fgStmtListThreaded);
7637 assert(tree != nullptr);
7638 assert(stmt != nullptr);
7639 assert(replacementTree != nullptr);
7640
7641 GenTree** treePtr = nullptr;
7642 GenTree* treeParent = tree->gtGetParent(&treePtr);
7643
7644 assert(treeParent != nullptr || tree == stmt->gtStmt.gtStmtExpr);
7645
7646 if (treePtr == nullptr)
7647 {
7648 // Replace the stmt expr and rebuild the linear order for "stmt".
7649 assert(treeParent == nullptr);
7650 assert(fgOrder != FGOrderLinear);
7651 stmt->gtStmt.gtStmtExpr = tree;
7652 fgSetStmtSeq(stmt);
7653 }
7654 else
7655 {
7656 assert(treeParent != nullptr);
7657
7658 // Check to see if the node to be replaced is a call argument and if so,
7659 // set `treeParent` to the call node.
7660 GenTree* cursor = treeParent;
7661 while ((cursor != nullptr) && (cursor->OperGet() == GT_LIST))
7662 {
7663 cursor = cursor->gtNext;
7664 }
7665
7666 if ((cursor != nullptr) && (cursor->OperGet() == GT_CALL))
7667 {
7668 treeParent = cursor;
7669 }
7670
7671#ifdef DEBUG
7672 GenTree** useEdge;
7673 assert(treeParent->TryGetUse(tree, &useEdge));
7674 assert(useEdge == treePtr);
7675#endif // DEBUG
7676
7677 GenTree* treeFirstNode = fgGetFirstNode(tree);
7678 GenTree* treeLastNode = tree;
7679 GenTree* treePrevNode = treeFirstNode->gtPrev;
7680 GenTree* treeNextNode = treeLastNode->gtNext;
7681
7682 treeParent->ReplaceOperand(treePtr, replacementTree);
7683
7684 // Build the linear order for "replacementTree".
7685 fgSetTreeSeq(replacementTree, treePrevNode);
7686
7687 // Restore linear-order Prev and Next for "replacementTree".
7688 if (treePrevNode != nullptr)
7689 {
7690 treeFirstNode = fgGetFirstNode(replacementTree);
7691 treeFirstNode->gtPrev = treePrevNode;
7692 treePrevNode->gtNext = treeFirstNode;
7693 }
7694 else
7695 {
7696 // Update the linear oder start of "stmt" if treeFirstNode
7697 // appears to have replaced the original first node.
7698 assert(treeFirstNode == stmt->gtStmt.gtStmtList);
7699 stmt->gtStmt.gtStmtList = fgGetFirstNode(replacementTree);
7700 }
7701
7702 if (treeNextNode != nullptr)
7703 {
7704 treeLastNode = replacementTree;
7705 treeLastNode->gtNext = treeNextNode;
7706 treeNextNode->gtPrev = treeLastNode;
7707 }
7708 }
7709
7710 return replacementTree;
7711}
7712
7713//------------------------------------------------------------------------
7714// gtUpdateSideEffects: Update the side effects of a tree and its ancestors
7715//
7716// Arguments:
7717// stmt - The tree's statement
7718// tree - Tree to update the side effects for
7719//
7720// Note: If tree's order hasn't been established, the method updates side effect
7721// flags on all statement's nodes.
7722
7723void Compiler::gtUpdateSideEffects(GenTree* stmt, GenTree* tree)
7724{
7725 if (fgStmtListThreaded)
7726 {
7727 gtUpdateTreeAncestorsSideEffects(tree);
7728 }
7729 else
7730 {
7731 gtUpdateStmtSideEffects(stmt);
7732 }
7733}
7734
7735//------------------------------------------------------------------------
7736// gtUpdateTreeAncestorsSideEffects: Update the side effects of a tree and its ancestors
7737// when statement order has been established.
7738//
7739// Arguments:
7740// tree - Tree to update the side effects for
7741
7742void Compiler::gtUpdateTreeAncestorsSideEffects(GenTree* tree)
7743{
7744 assert(fgStmtListThreaded);
7745 while (tree != nullptr)
7746 {
7747 gtUpdateNodeSideEffects(tree);
7748 tree = tree->gtGetParent(nullptr);
7749 }
7750}
7751
7752//------------------------------------------------------------------------
7753// gtUpdateStmtSideEffects: Update the side effects for statement tree nodes.
7754//
7755// Arguments:
7756// stmt - The statement to update side effects on
7757
7758void Compiler::gtUpdateStmtSideEffects(GenTree* stmt)
7759{
7760 fgWalkTree(&stmt->gtStmt.gtStmtExpr, fgUpdateSideEffectsPre, fgUpdateSideEffectsPost);
7761}
7762
7763//------------------------------------------------------------------------
7764// gtUpdateNodeOperSideEffects: Update the side effects based on the node operation.
7765//
7766// Arguments:
7767// tree - Tree to update the side effects on
7768//
7769// Notes:
7770// This method currently only updates GTF_EXCEPT, GTF_ASG, and GTF_CALL flags.
7771// The other side effect flags may remain unnecessarily (conservatively) set.
7772// The caller of this method is expected to update the flags based on the children's flags.
7773
7774void Compiler::gtUpdateNodeOperSideEffects(GenTree* tree)
7775{
7776 if (tree->OperMayThrow(this))
7777 {
7778 tree->gtFlags |= GTF_EXCEPT;
7779 }
7780 else
7781 {
7782 tree->gtFlags &= ~GTF_EXCEPT;
7783 if (tree->OperIsIndirOrArrLength())
7784 {
7785 tree->gtFlags |= GTF_IND_NONFAULTING;
7786 }
7787 }
7788
7789 if (tree->OperRequiresAsgFlag())
7790 {
7791 tree->gtFlags |= GTF_ASG;
7792 }
7793 else
7794 {
7795 tree->gtFlags &= ~GTF_ASG;
7796 }
7797
7798 if (tree->OperRequiresCallFlag(this))
7799 {
7800 tree->gtFlags |= GTF_CALL;
7801 }
7802 else
7803 {
7804 tree->gtFlags &= ~GTF_CALL;
7805 }
7806}
7807
7808//------------------------------------------------------------------------
7809// gtUpdateNodeSideEffects: Update the side effects based on the node operation and
7810// children's side efects.
7811//
7812// Arguments:
7813// tree - Tree to update the side effects on
7814//
7815// Notes:
7816// This method currently only updates GTF_EXCEPT and GTF_ASG flags. The other side effect
7817// flags may remain unnecessarily (conservatively) set.
7818
7819void Compiler::gtUpdateNodeSideEffects(GenTree* tree)
7820{
7821 gtUpdateNodeOperSideEffects(tree);
7822 unsigned nChildren = tree->NumChildren();
7823 for (unsigned childNum = 0; childNum < nChildren; childNum++)
7824 {
7825 GenTree* child = tree->GetChild(childNum);
7826 if (child != nullptr)
7827 {
7828 tree->gtFlags |= (child->gtFlags & GTF_ALL_EFFECT);
7829 }
7830 }
7831}
7832
7833//------------------------------------------------------------------------
7834// fgUpdateSideEffectsPre: Update the side effects based on the tree operation.
7835//
7836// Arguments:
7837// pTree - Pointer to the tree to update the side effects
7838// fgWalkPre - Walk data
7839//
7840// Notes:
7841// This method currently only updates GTF_EXCEPT and GTF_ASG flags. The other side effect
7842// flags may remain unnecessarily (conservatively) set.
7843
7844Compiler::fgWalkResult Compiler::fgUpdateSideEffectsPre(GenTree** pTree, fgWalkData* fgWalkPre)
7845{
7846 fgWalkPre->compiler->gtUpdateNodeOperSideEffects(*pTree);
7847
7848 return WALK_CONTINUE;
7849}
7850
7851//------------------------------------------------------------------------
7852// fgUpdateSideEffectsPost: Update the side effects of the parent based on the tree's flags.
7853//
7854// Arguments:
7855// pTree - Pointer to the tree
7856// fgWalkPost - Walk data
7857//
7858// Notes:
7859// The routine is used for updating the stale side effect flags for ancestor
7860// nodes starting from treeParent up to the top-level stmt expr.
7861
7862Compiler::fgWalkResult Compiler::fgUpdateSideEffectsPost(GenTree** pTree, fgWalkData* fgWalkPost)
7863{
7864 GenTree* tree = *pTree;
7865 GenTree* parent = fgWalkPost->parent;
7866 if (parent != nullptr)
7867 {
7868 parent->gtFlags |= (tree->gtFlags & GTF_ALL_EFFECT);
7869 }
7870 return WALK_CONTINUE;
7871}
7872
7873/*****************************************************************************
7874 *
7875 * Compares two trees and returns true when both trees are the same.
7876 * Instead of fully comparing the two trees this method can just return false.
7877 * Thus callers should not assume that the trees are different when false is returned.
7878 * Only when true is returned can the caller perform code optimizations.
7879 * The current implementation only compares a limited set of LEAF/CONST node
7880 * and returns false for all othere trees.
7881 */
7882bool Compiler::gtCompareTree(GenTree* op1, GenTree* op2)
7883{
7884 /* Make sure that both trees are of the same GT node kind */
7885 if (op1->OperGet() != op2->OperGet())
7886 {
7887 return false;
7888 }
7889
7890 /* Make sure that both trees are returning the same type */
7891 if (op1->gtType != op2->gtType)
7892 {
7893 return false;
7894 }
7895
7896 /* Figure out what kind of a node we have */
7897
7898 genTreeOps oper = op1->OperGet();
7899 unsigned kind = op1->OperKind();
7900
7901 /* Is this a constant or leaf node? */
7902
7903 if (kind & (GTK_CONST | GTK_LEAF))
7904 {
7905 switch (oper)
7906 {
7907 case GT_CNS_INT:
7908 if ((op1->gtIntCon.gtIconVal == op2->gtIntCon.gtIconVal) && GenTree::SameIconHandleFlag(op1, op2))
7909 {
7910 return true;
7911 }
7912 break;
7913
7914 case GT_CNS_LNG:
7915 if (op1->gtLngCon.gtLconVal == op2->gtLngCon.gtLconVal)
7916 {
7917 return true;
7918 }
7919 break;
7920
7921 case GT_CNS_STR:
7922 if (op1->gtStrCon.gtSconCPX == op2->gtStrCon.gtSconCPX)
7923 {
7924 return true;
7925 }
7926 break;
7927
7928 case GT_LCL_VAR:
7929 if (op1->gtLclVarCommon.gtLclNum == op2->gtLclVarCommon.gtLclNum)
7930 {
7931 return true;
7932 }
7933 break;
7934
7935 case GT_CLS_VAR:
7936 if (op1->gtClsVar.gtClsVarHnd == op2->gtClsVar.gtClsVarHnd)
7937 {
7938 return true;
7939 }
7940 break;
7941
7942 default:
7943 // we return false for these unhandled 'oper' kinds
7944 break;
7945 }
7946 }
7947 return false;
7948}
7949
7950GenTree* Compiler::gtGetThisArg(GenTreeCall* call)
7951{
7952 if (call->gtCallObjp != nullptr)
7953 {
7954 if (call->gtCallObjp->gtOper != GT_NOP && call->gtCallObjp->gtOper != GT_ASG)
7955 {
7956 if (!(call->gtCallObjp->gtFlags & GTF_LATE_ARG))
7957 {
7958 return call->gtCallObjp;
7959 }
7960 }
7961
7962 if (call->gtCallLateArgs)
7963 {
7964 regNumber thisReg = REG_ARG_0;
7965 unsigned argNum = 0;
7966 fgArgTabEntry* thisArgTabEntry = gtArgEntryByArgNum(call, argNum);
7967 GenTree* result = thisArgTabEntry->node;
7968
7969#if !FEATURE_FIXED_OUT_ARGS
7970 GenTree* lateArgs = call->gtCallLateArgs;
7971 regList list = call->regArgList;
7972 int index = 0;
7973 while (lateArgs != NULL)
7974 {
7975 assert(lateArgs->gtOper == GT_LIST);
7976 assert(index < call->regArgListCount);
7977 regNumber curArgReg = list[index];
7978 if (curArgReg == thisReg)
7979 {
7980 if (optAssertionPropagatedCurrentStmt)
7981 result = lateArgs->gtOp.gtOp1;
7982
7983 assert(result == lateArgs->gtOp.gtOp1);
7984 }
7985
7986 lateArgs = lateArgs->gtOp.gtOp2;
7987 index++;
7988 }
7989#endif
7990 return result;
7991 }
7992 }
7993 return nullptr;
7994}
7995
7996bool GenTree::gtSetFlags() const
7997{
7998 //
7999 // When FEATURE_SET_FLAGS (_TARGET_ARM_) is active the method returns true
8000 // when the gtFlags has the flag GTF_SET_FLAGS set
8001 // otherwise the architecture will be have instructions that typically set
8002 // the flags and this method will return true.
8003 //
8004 // Exceptions: GT_IND (load/store) is not allowed to set the flags
8005 // and on XARCH the GT_MUL/GT_DIV and all overflow instructions
8006 // do not set the condition flags
8007 //
8008 // Precondition we have a GTK_SMPOP
8009 //
8010 if (!varTypeIsIntegralOrI(TypeGet()) && (TypeGet() != TYP_VOID))
8011 {
8012 return false;
8013 }
8014
8015 if (((gtFlags & GTF_SET_FLAGS) != 0) && (gtOper != GT_IND))
8016 {
8017 // GTF_SET_FLAGS is not valid on GT_IND and is overlaid with GTF_NONFAULTING_IND
8018 return true;
8019 }
8020 else
8021 {
8022 return false;
8023 }
8024}
8025
8026bool GenTree::gtRequestSetFlags()
8027{
8028 bool result = false;
8029
8030#if FEATURE_SET_FLAGS
8031 // This method is a Nop unless FEATURE_SET_FLAGS is defined
8032
8033 // In order to set GTF_SET_FLAGS
8034 // we must have a GTK_SMPOP
8035 // and we have a integer or machine size type (not floating point or TYP_LONG on 32-bit)
8036 //
8037 if (!OperIsSimple())
8038 return false;
8039
8040 if (!varTypeIsIntegralOrI(TypeGet()))
8041 return false;
8042
8043 switch (gtOper)
8044 {
8045 case GT_IND:
8046 case GT_ARR_LENGTH:
8047 // These will turn into simple load from memory instructions
8048 // and we can't force the setting of the flags on load from memory
8049 break;
8050
8051 case GT_MUL:
8052 case GT_DIV:
8053 // These instructions don't set the flags (on x86/x64)
8054 //
8055 break;
8056
8057 default:
8058 // Otherwise we can set the flags for this gtOper
8059 // and codegen must set the condition flags.
8060 //
8061 gtFlags |= GTF_SET_FLAGS;
8062 result = true;
8063 break;
8064 }
8065#endif // FEATURE_SET_FLAGS
8066
8067 // Codegen for this tree must set the condition flags if
8068 // this method returns true.
8069 //
8070 return result;
8071}
8072
8073unsigned GenTree::NumChildren()
8074{
8075 if (OperIsConst() || OperIsLeaf())
8076 {
8077 return 0;
8078 }
8079 else if (OperIsUnary())
8080 {
8081 if (OperGet() == GT_NOP || OperGet() == GT_RETURN || OperGet() == GT_RETFILT)
8082 {
8083 if (gtOp.gtOp1 == nullptr)
8084 {
8085 return 0;
8086 }
8087 else
8088 {
8089 return 1;
8090 }
8091 }
8092 else
8093 {
8094 return 1;
8095 }
8096 }
8097 else if (OperIsBinary())
8098 {
8099 // All binary operators except LEA have at least one arg; the second arg may sometimes be null, however.
8100 if (OperGet() == GT_LEA)
8101 {
8102 unsigned childCount = 0;
8103 if (gtOp.gtOp1 != nullptr)
8104 {
8105 childCount++;
8106 }
8107 if (gtOp.gtOp2 != nullptr)
8108 {
8109 childCount++;
8110 }
8111 return childCount;
8112 }
8113#ifdef FEATURE_HW_INTRINSICS
8114 // GT_HWIntrinsic require special handling
8115 if (OperGet() == GT_HWIntrinsic)
8116 {
8117 if (gtOp.gtOp1 == nullptr)
8118 {
8119 return 0;
8120 }
8121 }
8122#endif
8123 assert(gtOp.gtOp1 != nullptr);
8124 if (gtOp.gtOp2 == nullptr)
8125 {
8126 return 1;
8127 }
8128 else
8129 {
8130 return 2;
8131 }
8132 }
8133 else
8134 {
8135 // Special
8136 switch (OperGet())
8137 {
8138 case GT_CMPXCHG:
8139 return 3;
8140
8141 case GT_ARR_BOUNDS_CHECK:
8142#ifdef FEATURE_SIMD
8143 case GT_SIMD_CHK:
8144#endif // FEATURE_SIMD
8145#ifdef FEATURE_HW_INTRINSICS
8146 case GT_HW_INTRINSIC_CHK:
8147#endif // FEATURE_HW_INTRINSICS
8148 return 2;
8149
8150 case GT_FIELD:
8151 case GT_STMT:
8152 return 1;
8153
8154 case GT_ARR_ELEM:
8155 return 1 + AsArrElem()->gtArrRank;
8156
8157 case GT_DYN_BLK:
8158 return 2;
8159
8160 case GT_ARR_OFFSET:
8161 case GT_STORE_DYN_BLK:
8162 return 3;
8163
8164 case GT_CALL:
8165 {
8166 GenTreeCall* call = AsCall();
8167 unsigned res = 0; // arg list(s) (including late args).
8168 if (call->gtCallObjp != nullptr)
8169 {
8170 res++; // Add objp?
8171 }
8172 if (call->gtCallArgs != nullptr)
8173 {
8174 res++; // Add args?
8175 }
8176 if (call->gtCallLateArgs != nullptr)
8177 {
8178 res++; // Add late args?
8179 }
8180 if (call->gtControlExpr != nullptr)
8181 {
8182 res++;
8183 }
8184
8185 if (call->gtCallType == CT_INDIRECT)
8186 {
8187 if (call->gtCallCookie != nullptr)
8188 {
8189 res++;
8190 }
8191 if (call->gtCallAddr != nullptr)
8192 {
8193 res++;
8194 }
8195 }
8196 return res;
8197 }
8198 case GT_NONE:
8199 return 0;
8200 default:
8201 unreached();
8202 }
8203 }
8204}
8205
8206GenTree* GenTree::GetChild(unsigned childNum)
8207{
8208 assert(childNum < NumChildren()); // Precondition.
8209 assert(NumChildren() <= MAX_CHILDREN);
8210 assert(!(OperIsConst() || OperIsLeaf()));
8211 if (OperIsUnary())
8212 {
8213 return AsUnOp()->gtOp1;
8214 }
8215 // Special case for assignment of dynamic block.
8216 // This code is here to duplicate the former case where the size may be evaluated prior to the
8217 // source and destination addresses. In order to do this, we treat the size as a child of the
8218 // assignment.
8219 // TODO-1stClassStructs: Revisit the need to duplicate former behavior, so that we can remove
8220 // these special cases.
8221 if ((OperGet() == GT_ASG) && (gtOp.gtOp1->OperGet() == GT_DYN_BLK) && (childNum == 2))
8222 {
8223 return gtOp.gtOp1->AsDynBlk()->gtDynamicSize;
8224 }
8225 else if (OperIsBinary())
8226 {
8227 if (OperIsAddrMode())
8228 {
8229 // If this is the first (0th) child, only return op1 if it is non-null
8230 // Otherwise, we return gtOp2.
8231 if (childNum == 0 && AsOp()->gtOp1 != nullptr)
8232 {
8233 return AsOp()->gtOp1;
8234 }
8235 return AsOp()->gtOp2;
8236 }
8237 // TODO-Cleanup: Consider handling ReverseOps here, and then we wouldn't have to handle it in
8238 // fgGetFirstNode(). However, it seems that it causes loop hoisting behavior to change.
8239 if (childNum == 0)
8240 {
8241 return AsOp()->gtOp1;
8242 }
8243 else
8244 {
8245 return AsOp()->gtOp2;
8246 }
8247 }
8248 else
8249 {
8250 // Special
8251 switch (OperGet())
8252 {
8253 case GT_CMPXCHG:
8254 switch (childNum)
8255 {
8256 case 0:
8257 return AsCmpXchg()->gtOpLocation;
8258 case 1:
8259 return AsCmpXchg()->gtOpValue;
8260 case 2:
8261 return AsCmpXchg()->gtOpComparand;
8262 default:
8263 unreached();
8264 }
8265 case GT_ARR_BOUNDS_CHECK:
8266#ifdef FEATURE_SIMD
8267 case GT_SIMD_CHK:
8268#endif // FEATURE_SIMD
8269#ifdef FEATURE_HW_INTRINSICS
8270 case GT_HW_INTRINSIC_CHK:
8271#endif // FEATURE_HW_INTRINSICS
8272 switch (childNum)
8273 {
8274 case 0:
8275 return AsBoundsChk()->gtIndex;
8276 case 1:
8277 return AsBoundsChk()->gtArrLen;
8278 default:
8279 unreached();
8280 }
8281
8282 case GT_STORE_DYN_BLK:
8283 switch (childNum)
8284 {
8285 case 0:
8286 return AsDynBlk()->Addr();
8287 case 1:
8288 return AsDynBlk()->Data();
8289 case 2:
8290 return AsDynBlk()->gtDynamicSize;
8291 default:
8292 unreached();
8293 }
8294 case GT_DYN_BLK:
8295 switch (childNum)
8296 {
8297 case 0:
8298 return AsDynBlk()->gtEvalSizeFirst ? AsDynBlk()->gtDynamicSize : AsDynBlk()->Addr();
8299 case 1:
8300 return AsDynBlk()->gtEvalSizeFirst ? AsDynBlk()->Addr() : AsDynBlk()->gtDynamicSize;
8301 default:
8302 unreached();
8303 }
8304
8305 case GT_FIELD:
8306 return AsField()->gtFldObj;
8307
8308 case GT_STMT:
8309 return AsStmt()->gtStmtExpr;
8310
8311 case GT_ARR_ELEM:
8312 if (childNum == 0)
8313 {
8314 return AsArrElem()->gtArrObj;
8315 }
8316 else
8317 {
8318 return AsArrElem()->gtArrInds[childNum - 1];
8319 }
8320
8321 case GT_ARR_OFFSET:
8322 switch (childNum)
8323 {
8324 case 0:
8325 return AsArrOffs()->gtOffset;
8326 case 1:
8327 return AsArrOffs()->gtIndex;
8328 case 2:
8329 return AsArrOffs()->gtArrObj;
8330 default:
8331 unreached();
8332 }
8333
8334 case GT_CALL:
8335 {
8336 // The if chain below assumes that all possible children are non-null.
8337 // If some are null, "virtually skip them."
8338 // If there isn't "virtually skip it."
8339 GenTreeCall* call = AsCall();
8340
8341 if (call->gtCallObjp == nullptr)
8342 {
8343 childNum++;
8344 }
8345 if (childNum >= 1 && call->gtCallArgs == nullptr)
8346 {
8347 childNum++;
8348 }
8349 if (childNum >= 2 && call->gtCallLateArgs == nullptr)
8350 {
8351 childNum++;
8352 }
8353 if (childNum >= 3 && call->gtControlExpr == nullptr)
8354 {
8355 childNum++;
8356 }
8357 if (call->gtCallType == CT_INDIRECT)
8358 {
8359 if (childNum >= 4 && call->gtCallCookie == nullptr)
8360 {
8361 childNum++;
8362 }
8363 }
8364
8365 if (childNum == 0)
8366 {
8367 return call->gtCallObjp;
8368 }
8369 else if (childNum == 1)
8370 {
8371 return call->gtCallArgs;
8372 }
8373 else if (childNum == 2)
8374 {
8375 return call->gtCallLateArgs;
8376 }
8377 else if (childNum == 3)
8378 {
8379 return call->gtControlExpr;
8380 }
8381 else
8382 {
8383 assert(call->gtCallType == CT_INDIRECT);
8384 if (childNum == 4)
8385 {
8386 return call->gtCallCookie;
8387 }
8388 else
8389 {
8390 assert(childNum == 5);
8391 return call->gtCallAddr;
8392 }
8393 }
8394 }
8395 case GT_NONE:
8396 unreached();
8397 default:
8398 unreached();
8399 }
8400 }
8401}
8402
8403GenTreeUseEdgeIterator::GenTreeUseEdgeIterator()
8404 : m_advance(nullptr), m_node(nullptr), m_edge(nullptr), m_argList(nullptr), m_state(-1)
8405{
8406}
8407
8408GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node)
8409 : m_advance(nullptr), m_node(node), m_edge(nullptr), m_argList(nullptr), m_state(0)
8410{
8411 assert(m_node != nullptr);
8412
8413 // NOTE: the switch statement below must be updated when introducing new nodes.
8414
8415 switch (m_node->OperGet())
8416 {
8417 // Leaf nodes
8418 case GT_LCL_VAR:
8419 case GT_LCL_FLD:
8420 case GT_LCL_VAR_ADDR:
8421 case GT_LCL_FLD_ADDR:
8422 case GT_CATCH_ARG:
8423 case GT_LABEL:
8424 case GT_FTN_ADDR:
8425 case GT_RET_EXPR:
8426 case GT_CNS_INT:
8427 case GT_CNS_LNG:
8428 case GT_CNS_DBL:
8429 case GT_CNS_STR:
8430 case GT_MEMORYBARRIER:
8431 case GT_JMP:
8432 case GT_JCC:
8433 case GT_SETCC:
8434 case GT_NO_OP:
8435 case GT_START_NONGC:
8436 case GT_PROF_HOOK:
8437#if !FEATURE_EH_FUNCLETS
8438 case GT_END_LFIN:
8439#endif // !FEATURE_EH_FUNCLETS
8440 case GT_PHI_ARG:
8441 case GT_JMPTABLE:
8442 case GT_CLS_VAR:
8443 case GT_CLS_VAR_ADDR:
8444 case GT_ARGPLACE:
8445 case GT_PHYSREG:
8446 case GT_EMITNOP:
8447 case GT_PINVOKE_PROLOG:
8448 case GT_PINVOKE_EPILOG:
8449 case GT_IL_OFFSET:
8450 m_state = -1;
8451 return;
8452
8453 // Standard unary operators
8454 case GT_STORE_LCL_VAR:
8455 case GT_STORE_LCL_FLD:
8456 case GT_NOT:
8457 case GT_NEG:
8458 case GT_COPY:
8459 case GT_RELOAD:
8460 case GT_ARR_LENGTH:
8461 case GT_CAST:
8462 case GT_BITCAST:
8463 case GT_CKFINITE:
8464 case GT_LCLHEAP:
8465 case GT_ADDR:
8466 case GT_IND:
8467 case GT_OBJ:
8468 case GT_BLK:
8469 case GT_BOX:
8470 case GT_ALLOCOBJ:
8471 case GT_RUNTIMELOOKUP:
8472 case GT_INIT_VAL:
8473 case GT_JTRUE:
8474 case GT_SWITCH:
8475 case GT_NULLCHECK:
8476 case GT_PUTARG_REG:
8477 case GT_PUTARG_STK:
8478 case GT_BSWAP:
8479 case GT_BSWAP16:
8480#if FEATURE_ARG_SPLIT
8481 case GT_PUTARG_SPLIT:
8482#endif // FEATURE_ARG_SPLIT
8483 case GT_RETURNTRAP:
8484 m_edge = &m_node->AsUnOp()->gtOp1;
8485 assert(*m_edge != nullptr);
8486 m_advance = &GenTreeUseEdgeIterator::Terminate;
8487 return;
8488
8489 // Unary operators with an optional operand
8490 case GT_NOP:
8491 case GT_RETURN:
8492 case GT_RETFILT:
8493 if (m_node->AsUnOp()->gtOp1 == nullptr)
8494 {
8495 assert(m_node->NullOp1Legal());
8496 m_state = -1;
8497 }
8498 else
8499 {
8500 m_edge = &m_node->AsUnOp()->gtOp1;
8501 m_advance = &GenTreeUseEdgeIterator::Terminate;
8502 }
8503 return;
8504
8505 // Variadic nodes
8506 case GT_PHI:
8507 SetEntryStateForList(m_node->AsUnOp()->gtOp1);
8508 return;
8509
8510 case GT_FIELD_LIST:
8511 SetEntryStateForList(m_node);
8512 return;
8513
8514#ifdef FEATURE_SIMD
8515 case GT_SIMD:
8516 if (m_node->AsSIMD()->gtSIMDIntrinsicID == SIMDIntrinsicInitN)
8517 {
8518 SetEntryStateForList(m_node->AsSIMD()->gtOp1);
8519 }
8520 else
8521 {
8522 SetEntryStateForBinOp();
8523 }
8524 return;
8525#endif // FEATURE_SIMD
8526
8527#ifdef FEATURE_HW_INTRINSICS
8528 case GT_HWIntrinsic:
8529 if (m_node->AsHWIntrinsic()->gtOp1 == nullptr)
8530 {
8531 assert(m_node->NullOp1Legal());
8532 m_state = -1;
8533 }
8534 else if (m_node->AsHWIntrinsic()->gtOp1->OperIsList())
8535 {
8536 SetEntryStateForList(m_node->AsHWIntrinsic()->gtOp1);
8537 }
8538 else
8539 {
8540 SetEntryStateForBinOp();
8541 }
8542 return;
8543#endif // FEATURE_HW_INTRINSICS
8544
8545 // LEA, which may have no first operand
8546 case GT_LEA:
8547 if (m_node->AsAddrMode()->gtOp1 == nullptr)
8548 {
8549 m_edge = &m_node->AsAddrMode()->gtOp2;
8550 m_advance = &GenTreeUseEdgeIterator::Terminate;
8551 }
8552 else
8553 {
8554 SetEntryStateForBinOp();
8555 }
8556 return;
8557
8558 // Special nodes
8559 case GT_CMPXCHG:
8560 m_edge = &m_node->AsCmpXchg()->gtOpLocation;
8561 assert(*m_edge != nullptr);
8562 m_advance = &GenTreeUseEdgeIterator::AdvanceCmpXchg;
8563 return;
8564
8565 case GT_ARR_BOUNDS_CHECK:
8566#ifdef FEATURE_SIMD
8567 case GT_SIMD_CHK:
8568#endif // FEATURE_SIMD
8569#ifdef FEATURE_HW_INTRINSICS
8570 case GT_HW_INTRINSIC_CHK:
8571#endif // FEATURE_HW_INTRINSICS
8572 m_edge = &m_node->AsBoundsChk()->gtIndex;
8573 assert(*m_edge != nullptr);
8574 m_advance = &GenTreeUseEdgeIterator::AdvanceBoundsChk;
8575 return;
8576
8577 case GT_FIELD:
8578 if (m_node->AsField()->gtFldObj == nullptr)
8579 {
8580 m_state = -1;
8581 }
8582 else
8583 {
8584 m_edge = &m_node->AsField()->gtFldObj;
8585 m_advance = &GenTreeUseEdgeIterator::Terminate;
8586 }
8587 return;
8588
8589 case GT_STMT:
8590 if (m_node->AsStmt()->gtStmtExpr == nullptr)
8591 {
8592 m_state = -1;
8593 }
8594 else
8595 {
8596 m_edge = &m_node->AsStmt()->gtStmtExpr;
8597 m_advance = &GenTreeUseEdgeIterator::Terminate;
8598 }
8599 return;
8600
8601 case GT_ARR_ELEM:
8602 m_edge = &m_node->AsArrElem()->gtArrObj;
8603 assert(*m_edge != nullptr);
8604 m_advance = &GenTreeUseEdgeIterator::AdvanceArrElem;
8605 return;
8606
8607 case GT_ARR_OFFSET:
8608 m_edge = &m_node->AsArrOffs()->gtOffset;
8609 assert(*m_edge != nullptr);
8610 m_advance = &GenTreeUseEdgeIterator::AdvanceArrOffset;
8611 return;
8612
8613 case GT_DYN_BLK:
8614 {
8615 GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
8616 m_edge = dynBlock->gtEvalSizeFirst ? &dynBlock->gtDynamicSize : &dynBlock->gtOp1;
8617 assert(*m_edge != nullptr);
8618 m_advance = &GenTreeUseEdgeIterator::AdvanceDynBlk;
8619 }
8620 return;
8621
8622 case GT_STORE_DYN_BLK:
8623 {
8624 GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
8625 if (dynBlock->gtEvalSizeFirst)
8626 {
8627 m_edge = &dynBlock->gtDynamicSize;
8628 }
8629 else
8630 {
8631 m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp2 : &dynBlock->gtOp1;
8632 }
8633 assert(*m_edge != nullptr);
8634
8635 m_advance = &GenTreeUseEdgeIterator::AdvanceStoreDynBlk;
8636 }
8637 return;
8638
8639 case GT_CALL:
8640 AdvanceCall<CALL_INSTANCE>();
8641 return;
8642
8643 // Binary nodes
8644 default:
8645 assert(m_node->OperIsBinary());
8646 SetEntryStateForBinOp();
8647 return;
8648 }
8649}
8650
8651//------------------------------------------------------------------------
8652// GenTreeUseEdgeIterator::AdvanceCmpXchg: produces the next operand of a CmpXchg node and advances the state.
8653//
8654void GenTreeUseEdgeIterator::AdvanceCmpXchg()
8655{
8656 switch (m_state)
8657 {
8658 case 0:
8659 m_edge = &m_node->AsCmpXchg()->gtOpValue;
8660 m_state = 1;
8661 break;
8662 case 1:
8663 m_edge = &m_node->AsCmpXchg()->gtOpComparand;
8664 m_advance = &GenTreeUseEdgeIterator::Terminate;
8665 break;
8666 default:
8667 unreached();
8668 }
8669
8670 assert(*m_edge != nullptr);
8671}
8672
8673//------------------------------------------------------------------------
8674// GenTreeUseEdgeIterator::AdvanceBoundsChk: produces the next operand of a BoundsChk node and advances the state.
8675//
8676void GenTreeUseEdgeIterator::AdvanceBoundsChk()
8677{
8678 m_edge = &m_node->AsBoundsChk()->gtArrLen;
8679 assert(*m_edge != nullptr);
8680 m_advance = &GenTreeUseEdgeIterator::Terminate;
8681}
8682
8683//------------------------------------------------------------------------
8684// GenTreeUseEdgeIterator::AdvanceArrElem: produces the next operand of a ArrElem node and advances the state.
8685//
8686// Because these nodes are variadic, this function uses `m_state` to index into the list of array indices.
8687//
8688void GenTreeUseEdgeIterator::AdvanceArrElem()
8689{
8690 if (m_state < m_node->AsArrElem()->gtArrRank)
8691 {
8692 m_edge = &m_node->AsArrElem()->gtArrInds[m_state];
8693 assert(*m_edge != nullptr);
8694 m_state++;
8695 }
8696 else
8697 {
8698 m_state = -1;
8699 }
8700}
8701
8702//------------------------------------------------------------------------
8703// GenTreeUseEdgeIterator::AdvanceArrOffset: produces the next operand of a ArrOffset node and advances the state.
8704//
8705void GenTreeUseEdgeIterator::AdvanceArrOffset()
8706{
8707 switch (m_state)
8708 {
8709 case 0:
8710 m_edge = &m_node->AsArrOffs()->gtIndex;
8711 m_state = 1;
8712 break;
8713 case 1:
8714 m_edge = &m_node->AsArrOffs()->gtArrObj;
8715 m_advance = &GenTreeUseEdgeIterator::Terminate;
8716 break;
8717 default:
8718 unreached();
8719 }
8720
8721 assert(*m_edge != nullptr);
8722}
8723
8724//------------------------------------------------------------------------
8725// GenTreeUseEdgeIterator::AdvanceDynBlk: produces the next operand of a DynBlk node and advances the state.
8726//
8727void GenTreeUseEdgeIterator::AdvanceDynBlk()
8728{
8729 GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
8730
8731 m_edge = dynBlock->gtEvalSizeFirst ? &dynBlock->gtOp1 : &dynBlock->gtDynamicSize;
8732 assert(*m_edge != nullptr);
8733 m_advance = &GenTreeUseEdgeIterator::Terminate;
8734}
8735
8736//------------------------------------------------------------------------
8737// GenTreeUseEdgeIterator::AdvanceStoreDynBlk: produces the next operand of a StoreDynBlk node and advances the state.
8738//
8739// These nodes are moderately complicated but rare enough that templating this function is probably not
8740// worth the extra complexity.
8741//
8742void GenTreeUseEdgeIterator::AdvanceStoreDynBlk()
8743{
8744 GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
8745 if (dynBlock->gtEvalSizeFirst)
8746 {
8747 switch (m_state)
8748 {
8749 case 0:
8750 m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp2 : &dynBlock->gtOp1;
8751 m_state = 1;
8752 break;
8753 case 1:
8754 m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp1 : &dynBlock->gtOp2;
8755 m_advance = &GenTreeUseEdgeIterator::Terminate;
8756 break;
8757 default:
8758 unreached();
8759 }
8760 }
8761 else
8762 {
8763 switch (m_state)
8764 {
8765 case 0:
8766 m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp1 : &dynBlock->gtOp2;
8767 m_state = 1;
8768 break;
8769 case 1:
8770 m_edge = &dynBlock->gtDynamicSize;
8771 m_advance = &GenTreeUseEdgeIterator::Terminate;
8772 break;
8773 default:
8774 unreached();
8775 }
8776 }
8777
8778 assert(*m_edge != nullptr);
8779}
8780
8781//------------------------------------------------------------------------
8782// GenTreeUseEdgeIterator::AdvanceBinOp: produces the next operand of a binary node and advances the state.
8783//
8784// This function must be instantiated s.t. `ReverseOperands` is `true` iff the node is marked with the
8785// `GTF_REVERSE_OPS` flag.
8786//
8787template <bool ReverseOperands>
8788void GenTreeUseEdgeIterator::AdvanceBinOp()
8789{
8790 assert(ReverseOperands == ((m_node->gtFlags & GTF_REVERSE_OPS) != 0));
8791
8792 m_edge = !ReverseOperands ? &m_node->AsOp()->gtOp2 : &m_node->AsOp()->gtOp1;
8793 assert(*m_edge != nullptr);
8794 m_advance = &GenTreeUseEdgeIterator::Terminate;
8795}
8796
8797//------------------------------------------------------------------------
8798// GenTreeUseEdgeIterator::SetEntryStateForBinOp: produces the first operand of a binary node and chooses
8799// the appropriate advance function.
8800//
8801void GenTreeUseEdgeIterator::SetEntryStateForBinOp()
8802{
8803 assert(m_node != nullptr);
8804 assert(m_node->OperIsBinary());
8805
8806 GenTreeOp* const node = m_node->AsOp();
8807
8808 if (node->gtOp2 == nullptr)
8809 {
8810 assert(node->gtOp1 != nullptr);
8811 assert(node->NullOp2Legal());
8812 m_edge = &node->gtOp1;
8813 m_advance = &GenTreeUseEdgeIterator::Terminate;
8814 }
8815 else if ((node->gtFlags & GTF_REVERSE_OPS) != 0)
8816 {
8817 m_edge = &m_node->AsOp()->gtOp2;
8818 m_advance = &GenTreeUseEdgeIterator::AdvanceBinOp<true>;
8819 }
8820 else
8821 {
8822 m_edge = &m_node->AsOp()->gtOp1;
8823 m_advance = &GenTreeUseEdgeIterator::AdvanceBinOp<false>;
8824 }
8825}
8826
8827//------------------------------------------------------------------------
8828// GenTreeUseEdgeIterator::AdvanceList: produces the next operand of a variadic node and advances the state.
8829//
8830// This function does not use `m_state` for anything meaningful; it simply walks the `m_argList` until
8831// there are no further entries.
8832//
8833void GenTreeUseEdgeIterator::AdvanceList()
8834{
8835 assert(m_state == 0);
8836
8837 if (m_argList == nullptr)
8838 {
8839 m_state = -1;
8840 }
8841 else
8842 {
8843 GenTreeArgList* listNode = m_argList->AsArgList();
8844 m_edge = &listNode->gtOp1;
8845 m_argList = listNode->Rest();
8846 }
8847}
8848
8849//------------------------------------------------------------------------
8850// GenTreeUseEdgeIterator::SetEntryStateForList: produces the first operand of a list node.
8851//
8852void GenTreeUseEdgeIterator::SetEntryStateForList(GenTree* list)
8853{
8854 m_argList = list;
8855 m_advance = &GenTreeUseEdgeIterator::AdvanceList;
8856 AdvanceList();
8857}
8858
8859//------------------------------------------------------------------------
8860// GenTreeUseEdgeIterator::AdvanceCall: produces the next operand of a call node and advances the state.
8861//
8862// This function is a bit tricky: in order to avoid doing unnecessary work, it is instantiated with the
8863// state number the iterator will be in when it is called. For example, `AdvanceCall<CALL_INSTANCE>`
8864// is the instantiation used when the iterator is at the `CALL_INSTANCE` state (i.e. the entry state).
8865// This sort of templating allows each state to avoid processing earlier states without unnecessary
8866// duplication of code.
8867//
8868// Note that this method expands the argument lists (`gtCallArgs` and `gtCallLateArgs`) into their
8869// component operands.
8870//
8871template <int state>
8872void GenTreeUseEdgeIterator::AdvanceCall()
8873{
8874 GenTreeCall* const call = m_node->AsCall();
8875
8876 switch (state)
8877 {
8878 case CALL_INSTANCE:
8879 m_argList = call->gtCallArgs;
8880 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_ARGS>;
8881 if (call->gtCallObjp != nullptr)
8882 {
8883 m_edge = &call->gtCallObjp;
8884 return;
8885 }
8886 __fallthrough;
8887
8888 case CALL_ARGS:
8889 if (m_argList != nullptr)
8890 {
8891 GenTreeArgList* argNode = m_argList->AsArgList();
8892 m_edge = &argNode->gtOp1;
8893 m_argList = argNode->Rest();
8894 return;
8895 }
8896 m_argList = call->gtCallLateArgs;
8897 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_LATE_ARGS>;
8898 __fallthrough;
8899
8900 case CALL_LATE_ARGS:
8901 if (m_argList != nullptr)
8902 {
8903 GenTreeArgList* argNode = m_argList->AsArgList();
8904 m_edge = &argNode->gtOp1;
8905 m_argList = argNode->Rest();
8906 return;
8907 }
8908 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_CONTROL_EXPR>;
8909 __fallthrough;
8910
8911 case CALL_CONTROL_EXPR:
8912 if (call->gtControlExpr != nullptr)
8913 {
8914 if (call->gtCallType == CT_INDIRECT)
8915 {
8916 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_COOKIE>;
8917 }
8918 else
8919 {
8920 m_advance = &GenTreeUseEdgeIterator::Terminate;
8921 }
8922 m_edge = &call->gtControlExpr;
8923 return;
8924 }
8925 else if (call->gtCallType != CT_INDIRECT)
8926 {
8927 m_state = -1;
8928 return;
8929 }
8930 __fallthrough;
8931
8932 case CALL_COOKIE:
8933 assert(call->gtCallType == CT_INDIRECT);
8934
8935 m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_ADDRESS>;
8936 if (call->gtCallCookie != nullptr)
8937 {
8938 m_edge = &call->gtCallCookie;
8939 return;
8940 }
8941 __fallthrough;
8942
8943 case CALL_ADDRESS:
8944 assert(call->gtCallType == CT_INDIRECT);
8945
8946 m_advance = &GenTreeUseEdgeIterator::Terminate;
8947 if (call->gtCallAddr != nullptr)
8948 {
8949 m_edge = &call->gtCallAddr;
8950 }
8951 return;
8952
8953 default:
8954 unreached();
8955 }
8956}
8957
8958//------------------------------------------------------------------------
8959// GenTreeUseEdgeIterator::Terminate: advances the iterator to the terminal state.
8960//
8961void GenTreeUseEdgeIterator::Terminate()
8962{
8963 m_state = -1;
8964}
8965
8966//------------------------------------------------------------------------
8967// GenTreeUseEdgeIterator::operator++: advances the iterator to the next operand.
8968//
8969GenTreeUseEdgeIterator& GenTreeUseEdgeIterator::operator++()
8970{
8971 // If we've reached the terminal state, do nothing.
8972 if (m_state != -1)
8973 {
8974 (this->*m_advance)();
8975 }
8976
8977 return *this;
8978}
8979
8980GenTreeUseEdgeIterator GenTree::UseEdgesBegin()
8981{
8982 return GenTreeUseEdgeIterator(this);
8983}
8984
8985GenTreeUseEdgeIterator GenTree::UseEdgesEnd()
8986{
8987 return GenTreeUseEdgeIterator();
8988}
8989
8990IteratorPair<GenTreeUseEdgeIterator> GenTree::UseEdges()
8991{
8992 return MakeIteratorPair(UseEdgesBegin(), UseEdgesEnd());
8993}
8994
8995GenTreeOperandIterator GenTree::OperandsBegin()
8996{
8997 return GenTreeOperandIterator(this);
8998}
8999
9000GenTreeOperandIterator GenTree::OperandsEnd()
9001{
9002 return GenTreeOperandIterator();
9003}
9004
9005IteratorPair<GenTreeOperandIterator> GenTree::Operands()
9006{
9007 return MakeIteratorPair(OperandsBegin(), OperandsEnd());
9008}
9009
9010bool GenTree::Precedes(GenTree* other)
9011{
9012 assert(other != nullptr);
9013
9014 for (GenTree* node = gtNext; node != nullptr; node = node->gtNext)
9015 {
9016 if (node == other)
9017 {
9018 return true;
9019 }
9020 }
9021
9022 return false;
9023}
9024
9025#ifdef DEBUG
9026
9027/* static */ int GenTree::gtDispFlags(unsigned flags, unsigned debugFlags)
9028{
9029 int charsDisplayed = 11; // 11 is the "baseline" number of flag characters displayed
9030
9031 printf("%c", (flags & GTF_ASG) ? 'A' : (IsContained(flags) ? 'c' : '-'));
9032 printf("%c", (flags & GTF_CALL) ? 'C' : '-');
9033 printf("%c", (flags & GTF_EXCEPT) ? 'X' : '-');
9034 printf("%c", (flags & GTF_GLOB_REF) ? 'G' : '-');
9035 printf("%c", (debugFlags & GTF_DEBUG_NODE_MORPHED) ? '+' : // First print '+' if GTF_DEBUG_NODE_MORPHED is set
9036 (flags & GTF_ORDER_SIDEEFF) ? 'O' : '-'); // otherwise print 'O' or '-'
9037 printf("%c", (flags & GTF_COLON_COND) ? '?' : '-');
9038 printf("%c", (flags & GTF_DONT_CSE) ? 'N' : // N is for No cse
9039 (flags & GTF_MAKE_CSE) ? 'H' : '-'); // H is for Hoist this expr
9040 printf("%c", (flags & GTF_REVERSE_OPS) ? 'R' : '-');
9041 printf("%c", (flags & GTF_UNSIGNED) ? 'U' : (flags & GTF_BOOLEAN) ? 'B' : '-');
9042#if FEATURE_SET_FLAGS
9043 printf("%c", (flags & GTF_SET_FLAGS) ? 'S' : '-');
9044 ++charsDisplayed;
9045#endif
9046 printf("%c", (flags & GTF_LATE_ARG) ? 'L' : '-');
9047 printf("%c", (flags & GTF_SPILLED) ? 'z' : (flags & GTF_SPILL) ? 'Z' : '-');
9048
9049 return charsDisplayed;
9050}
9051
9052/*****************************************************************************/
9053
9054void Compiler::gtDispNodeName(GenTree* tree)
9055{
9056 /* print the node name */
9057
9058 const char* name;
9059
9060 assert(tree);
9061 if (tree->gtOper < GT_COUNT)
9062 {
9063 name = GenTree::OpName(tree->OperGet());
9064 }
9065 else
9066 {
9067 name = "<ERROR>";
9068 }
9069 char buf[32];
9070 char* bufp = &buf[0];
9071
9072 if ((tree->gtOper == GT_CNS_INT) && tree->IsIconHandle())
9073 {
9074 sprintf_s(bufp, sizeof(buf), " %s(h)%c", name, 0);
9075 }
9076 else if (tree->gtOper == GT_PUTARG_STK)
9077 {
9078 sprintf_s(bufp, sizeof(buf), " %s [+0x%02x]%c", name, tree->AsPutArgStk()->getArgOffset(), 0);
9079 }
9080 else if (tree->gtOper == GT_CALL)
9081 {
9082 const char* callType = "CALL";
9083 const char* gtfType = "";
9084 const char* ctType = "";
9085 char gtfTypeBuf[100];
9086
9087 if (tree->gtCall.gtCallType == CT_USER_FUNC)
9088 {
9089 if (tree->gtCall.IsVirtual())
9090 {
9091 callType = "CALLV";
9092 }
9093 }
9094 else if (tree->gtCall.gtCallType == CT_HELPER)
9095 {
9096 ctType = " help";
9097 }
9098 else if (tree->gtCall.gtCallType == CT_INDIRECT)
9099 {
9100 ctType = " ind";
9101 }
9102 else
9103 {
9104 assert(!"Unknown gtCallType");
9105 }
9106
9107 if (tree->gtFlags & GTF_CALL_NULLCHECK)
9108 {
9109 gtfType = " nullcheck";
9110 }
9111 if (tree->gtCall.IsVirtualVtable())
9112 {
9113 gtfType = " ind";
9114 }
9115 else if (tree->gtCall.IsVirtualStub())
9116 {
9117 gtfType = " stub";
9118 }
9119#ifdef FEATURE_READYTORUN_COMPILER
9120 else if (tree->gtCall.IsR2RRelativeIndir())
9121 {
9122 gtfType = " r2r_ind";
9123 }
9124#endif // FEATURE_READYTORUN_COMPILER
9125 else if (tree->gtFlags & GTF_CALL_UNMANAGED)
9126 {
9127 char* gtfTypeBufWalk = gtfTypeBuf;
9128 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " unman");
9129 if (tree->gtFlags & GTF_CALL_POP_ARGS)
9130 {
9131 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " popargs");
9132 }
9133 if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
9134 {
9135 gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " thiscall");
9136 }
9137 gtfType = gtfTypeBuf;
9138 }
9139
9140 sprintf_s(bufp, sizeof(buf), " %s%s%s%c", callType, ctType, gtfType, 0);
9141 }
9142 else if (tree->gtOper == GT_ARR_ELEM)
9143 {
9144 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s[", name);
9145 for (unsigned rank = tree->gtArrElem.gtArrRank - 1; rank; rank--)
9146 {
9147 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), ",");
9148 }
9149 SimpleSprintf_s(bufp, buf, sizeof(buf), "]");
9150 }
9151 else if (tree->gtOper == GT_ARR_OFFSET || tree->gtOper == GT_ARR_INDEX)
9152 {
9153 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s[", name);
9154 unsigned char currDim;
9155 unsigned char rank;
9156 if (tree->gtOper == GT_ARR_OFFSET)
9157 {
9158 currDim = tree->gtArrOffs.gtCurrDim;
9159 rank = tree->gtArrOffs.gtArrRank;
9160 }
9161 else
9162 {
9163 currDim = tree->gtArrIndex.gtCurrDim;
9164 rank = tree->gtArrIndex.gtArrRank;
9165 }
9166
9167 for (unsigned char dim = 0; dim < rank; dim++)
9168 {
9169 // Use a defacto standard i,j,k for the dimensions.
9170 // Note that we only support up to rank 3 arrays with these nodes, so we won't run out of characters.
9171 char dimChar = '*';
9172 if (dim == currDim)
9173 {
9174 dimChar = 'i' + dim;
9175 }
9176 else if (dim > currDim)
9177 {
9178 dimChar = ' ';
9179 }
9180
9181 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "%c", dimChar);
9182 if (dim != rank - 1)
9183 {
9184 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), ",");
9185 }
9186 }
9187 SimpleSprintf_s(bufp, buf, sizeof(buf), "]");
9188 }
9189 else if (tree->gtOper == GT_LEA)
9190 {
9191 GenTreeAddrMode* lea = tree->AsAddrMode();
9192 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), " %s(", name);
9193 if (lea->Base() != nullptr)
9194 {
9195 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "b+");
9196 }
9197 if (lea->Index() != nullptr)
9198 {
9199 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "(i*%d)+", lea->gtScale);
9200 }
9201 bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "%d)", lea->Offset());
9202 }
9203 else if (tree->gtOper == GT_ARR_BOUNDS_CHECK)
9204 {
9205 switch (tree->gtBoundsChk.gtThrowKind)
9206 {
9207 case SCK_RNGCHK_FAIL:
9208 sprintf_s(bufp, sizeof(buf), " %s_Rng", name);
9209 break;
9210 case SCK_ARG_EXCPN:
9211 sprintf_s(bufp, sizeof(buf), " %s_Arg", name);
9212 break;
9213 case SCK_ARG_RNG_EXCPN:
9214 sprintf_s(bufp, sizeof(buf), " %s_ArgRng", name);
9215 break;
9216 default:
9217 unreached();
9218 }
9219 }
9220 else if (tree->gtOverflowEx())
9221 {
9222 sprintf_s(bufp, sizeof(buf), " %s_ovfl%c", name, 0);
9223 }
9224 else if (tree->OperIsBlk() && !tree->OperIsDynBlk())
9225 {
9226 sprintf_s(bufp, sizeof(buf), " %s(%d)", name, tree->AsBlk()->gtBlkSize);
9227 }
9228 else
9229 {
9230 sprintf_s(bufp, sizeof(buf), " %s%c", name, 0);
9231 }
9232
9233 if (strlen(buf) < 10)
9234 {
9235 printf(" %-10s", buf);
9236 }
9237 else
9238 {
9239 printf(" %s", buf);
9240 }
9241}
9242
9243void Compiler::gtDispVN(GenTree* tree)
9244{
9245 if (tree->gtVNPair.GetLiberal() != ValueNumStore::NoVN)
9246 {
9247 assert(tree->gtVNPair.GetConservative() != ValueNumStore::NoVN);
9248 printf(" ");
9249 vnpPrint(tree->gtVNPair, 0);
9250 }
9251}
9252
9253//------------------------------------------------------------------------
9254// gtDispNode: Print a tree to jitstdout.
9255//
9256// Arguments:
9257// tree - the tree to be printed
9258// indentStack - the specification for the current level of indentation & arcs
9259// msg - a contextual method (i.e. from the parent) to print
9260//
9261// Return Value:
9262// None.
9263//
9264// Notes:
9265// 'indentStack' may be null, in which case no indentation or arcs are printed
9266// 'msg' may be null
9267
9268void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, __in __in_z __in_opt const char* msg, bool isLIR)
9269{
9270 bool printPointer = true; // always true..
9271 bool printFlags = true; // always true..
9272 bool printCost = true; // always true..
9273
9274 int msgLength = 25;
9275
9276 GenTree* prev;
9277
9278 if (tree->gtSeqNum)
9279 {
9280 printf("N%03u ", tree->gtSeqNum);
9281 if (tree->gtCostsInitialized)
9282 {
9283 printf("(%3u,%3u) ", tree->gtCostEx, tree->gtCostSz);
9284 }
9285 else
9286 {
9287 printf("(???"
9288 ",???"
9289 ") "); // This probably indicates a bug: the node has a sequence number, but not costs.
9290 }
9291 }
9292 else
9293 {
9294 if (tree->gtOper == GT_STMT)
9295 {
9296 prev = tree->gtStmt.gtStmtExpr;
9297 }
9298 else
9299 {
9300 prev = tree;
9301 }
9302
9303 bool hasSeqNum = true;
9304 unsigned dotNum = 0;
9305 do
9306 {
9307 dotNum++;
9308 prev = prev->gtPrev;
9309
9310 if ((prev == nullptr) || (prev == tree))
9311 {
9312 hasSeqNum = false;
9313 break;
9314 }
9315
9316 assert(prev);
9317 } while (prev->gtSeqNum == 0);
9318
9319 // If we have an indent stack, don't add additional characters,
9320 // as it will mess up the alignment.
9321 bool displayDotNum = tree->gtOper != GT_STMT && hasSeqNum && (indentStack == nullptr);
9322 if (displayDotNum)
9323 {
9324 printf("N%03u.%02u ", prev->gtSeqNum, dotNum);
9325 }
9326 else
9327 {
9328 printf(" ");
9329 }
9330
9331 if (tree->gtCostsInitialized)
9332 {
9333 printf("(%3u,%3u) ", tree->gtCostEx, tree->gtCostSz);
9334 }
9335 else
9336 {
9337 if (displayDotNum)
9338 {
9339 // Do better alignment in this case
9340 printf(" ");
9341 }
9342 else
9343 {
9344 printf(" ");
9345 }
9346 }
9347 }
9348
9349 if (optValnumCSE_phase)
9350 {
9351 if (IS_CSE_INDEX(tree->gtCSEnum))
9352 {
9353 printf("CSE #%02d (%s)", GET_CSE_INDEX(tree->gtCSEnum), (IS_CSE_USE(tree->gtCSEnum) ? "use" : "def"));
9354 }
9355 else
9356 {
9357 printf(" ");
9358 }
9359 }
9360
9361 /* Print the node ID */
9362 printTreeID(tree);
9363 printf(" ");
9364
9365 if (tree->gtOper >= GT_COUNT)
9366 {
9367 printf(" **** ILLEGAL NODE ****");
9368 return;
9369 }
9370
9371 if (printFlags)
9372 {
9373 /* First print the flags associated with the node */
9374 switch (tree->gtOper)
9375 {
9376 case GT_LEA:
9377 case GT_BLK:
9378 case GT_OBJ:
9379 case GT_DYN_BLK:
9380 case GT_STORE_BLK:
9381 case GT_STORE_OBJ:
9382 case GT_STORE_DYN_BLK:
9383
9384 case GT_IND:
9385 // We prefer printing V or U
9386 if ((tree->gtFlags & (GTF_IND_VOLATILE | GTF_IND_UNALIGNED)) == 0)
9387 {
9388 if (tree->gtFlags & GTF_IND_TGTANYWHERE)
9389 {
9390 printf("*");
9391 --msgLength;
9392 break;
9393 }
9394 if (tree->gtFlags & GTF_IND_INVARIANT)
9395 {
9396 printf("#");
9397 --msgLength;
9398 break;
9399 }
9400 if (tree->gtFlags & GTF_IND_ARR_INDEX)
9401 {
9402 printf("a");
9403 --msgLength;
9404 break;
9405 }
9406 if (tree->gtFlags & GTF_IND_NONFAULTING)
9407 {
9408 printf("n"); // print a n for non-faulting
9409 --msgLength;
9410 break;
9411 }
9412 if (tree->gtFlags & GTF_IND_ASG_LHS)
9413 {
9414 printf("D"); // print a D for definition
9415 --msgLength;
9416 break;
9417 }
9418 }
9419 __fallthrough;
9420
9421 case GT_INDEX:
9422 case GT_INDEX_ADDR:
9423
9424 if ((tree->gtFlags & (GTF_IND_VOLATILE | GTF_IND_UNALIGNED)) == 0) // We prefer printing V or U over R
9425 {
9426 if (tree->gtFlags & GTF_INX_REFARR_LAYOUT)
9427 {
9428 printf("R");
9429 --msgLength;
9430 break;
9431 } // R means RefArray
9432 }
9433 __fallthrough;
9434
9435 case GT_FIELD:
9436 case GT_CLS_VAR:
9437 if (tree->gtFlags & GTF_IND_VOLATILE)
9438 {
9439 printf("V");
9440 --msgLength;
9441 break;
9442 }
9443 if (tree->gtFlags & GTF_IND_UNALIGNED)
9444 {
9445 printf("U");
9446 --msgLength;
9447 break;
9448 }
9449 goto DASH;
9450
9451 case GT_ASG:
9452 if (tree->OperIsInitBlkOp())
9453 {
9454 printf("I");
9455 --msgLength;
9456 break;
9457 }
9458 goto DASH;
9459
9460 case GT_CALL:
9461 if (tree->gtCall.IsInlineCandidate())
9462 {
9463 if (tree->gtCall.IsGuardedDevirtualizationCandidate())
9464 {
9465 printf("&");
9466 }
9467 else
9468 {
9469 printf("I");
9470 }
9471 --msgLength;
9472 break;
9473 }
9474 else if (tree->gtCall.IsGuardedDevirtualizationCandidate())
9475 {
9476 printf("G");
9477 --msgLength;
9478 break;
9479 }
9480 if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_RETBUFFARG)
9481 {
9482 printf("S");
9483 --msgLength;
9484 break;
9485 }
9486 if (tree->gtFlags & GTF_CALL_HOISTABLE)
9487 {
9488 printf("H");
9489 --msgLength;
9490 break;
9491 }
9492
9493 goto DASH;
9494
9495 case GT_MUL:
9496#if !defined(_TARGET_64BIT_)
9497 case GT_MUL_LONG:
9498#endif
9499 if (tree->gtFlags & GTF_MUL_64RSLT)
9500 {
9501 printf("L");
9502 --msgLength;
9503 break;
9504 }
9505 goto DASH;
9506
9507 case GT_ADDR:
9508 if (tree->gtFlags & GTF_ADDR_ONSTACK)
9509 {
9510 printf("L");
9511 --msgLength;
9512 break;
9513 } // L means LclVar
9514 goto DASH;
9515
9516 case GT_LCL_FLD:
9517 case GT_LCL_VAR:
9518 case GT_LCL_VAR_ADDR:
9519 case GT_LCL_FLD_ADDR:
9520 case GT_STORE_LCL_FLD:
9521 case GT_STORE_LCL_VAR:
9522 if (tree->gtFlags & GTF_VAR_USEASG)
9523 {
9524 printf("U");
9525 --msgLength;
9526 break;
9527 }
9528 if (tree->gtFlags & GTF_VAR_DEF)
9529 {
9530 printf("D");
9531 --msgLength;
9532 break;
9533 }
9534 if (tree->gtFlags & GTF_VAR_CAST)
9535 {
9536 printf("C");
9537 --msgLength;
9538 break;
9539 }
9540 if (tree->gtFlags & GTF_VAR_ARR_INDEX)
9541 {
9542 printf("i");
9543 --msgLength;
9544 break;
9545 }
9546 goto DASH;
9547
9548 case GT_EQ:
9549 case GT_NE:
9550 case GT_LT:
9551 case GT_LE:
9552 case GT_GE:
9553 case GT_GT:
9554 case GT_TEST_EQ:
9555 case GT_TEST_NE:
9556 if (tree->gtFlags & GTF_RELOP_NAN_UN)
9557 {
9558 printf("N");
9559 --msgLength;
9560 break;
9561 }
9562 if (tree->gtFlags & GTF_RELOP_JMP_USED)
9563 {
9564 printf("J");
9565 --msgLength;
9566 break;
9567 }
9568 if (tree->gtFlags & GTF_RELOP_QMARK)
9569 {
9570 printf("Q");
9571 --msgLength;
9572 break;
9573 }
9574 goto DASH;
9575
9576 case GT_JCMP:
9577 printf((tree->gtFlags & GTF_JCMP_TST) ? "T" : "C");
9578 printf((tree->gtFlags & GTF_JCMP_EQ) ? "EQ" : "NE");
9579 goto DASH;
9580
9581 case GT_FIELD_LIST:
9582 if (tree->gtFlags & GTF_FIELD_LIST_HEAD)
9583 {
9584 printf("H");
9585 --msgLength;
9586 break;
9587 }
9588 goto DASH;
9589
9590 default:
9591 DASH:
9592 printf("-");
9593 --msgLength;
9594 break;
9595 }
9596
9597 /* Then print the general purpose flags */
9598 unsigned flags = tree->gtFlags;
9599
9600 if (tree->OperIsBinary())
9601 {
9602 genTreeOps oper = tree->OperGet();
9603
9604 // Check for GTF_ADDRMODE_NO_CSE flag on add/mul/shl Binary Operators
9605 if ((oper == GT_ADD) || (oper == GT_MUL) || (oper == GT_LSH))
9606 {
9607 if ((tree->gtFlags & GTF_ADDRMODE_NO_CSE) != 0)
9608 {
9609 flags |= GTF_DONT_CSE; // Force the GTF_ADDRMODE_NO_CSE flag to print out like GTF_DONT_CSE
9610 }
9611 }
9612 }
9613 else // !tree->OperIsBinary()
9614 {
9615 // the GTF_REVERSE flag only applies to binary operations
9616 flags &= ~GTF_REVERSE_OPS; // we use this value for GTF_VAR_ARR_INDEX above
9617 }
9618
9619 msgLength -= GenTree::gtDispFlags(flags, tree->gtDebugFlags);
9620 /*
9621 printf("%c", (flags & GTF_ASG ) ? 'A' : '-');
9622 printf("%c", (flags & GTF_CALL ) ? 'C' : '-');
9623 printf("%c", (flags & GTF_EXCEPT ) ? 'X' : '-');
9624 printf("%c", (flags & GTF_GLOB_REF ) ? 'G' : '-');
9625 printf("%c", (flags & GTF_ORDER_SIDEEFF ) ? 'O' : '-');
9626 printf("%c", (flags & GTF_COLON_COND ) ? '?' : '-');
9627 printf("%c", (flags & GTF_DONT_CSE ) ? 'N' : // N is for No cse
9628 (flags & GTF_MAKE_CSE ) ? 'H' : '-'); // H is for Hoist this expr
9629 printf("%c", (flags & GTF_REVERSE_OPS ) ? 'R' : '-');
9630 printf("%c", (flags & GTF_UNSIGNED ) ? 'U' :
9631 (flags & GTF_BOOLEAN ) ? 'B' : '-');
9632 printf("%c", (flags & GTF_SET_FLAGS ) ? 'S' : '-');
9633 printf("%c", (flags & GTF_SPILLED ) ? 'z' : '-');
9634 printf("%c", (flags & GTF_SPILL ) ? 'Z' : '-');
9635 */
9636 }
9637
9638 // If we're printing a node for LIR, we use the space normally associated with the message
9639 // to display the node's temp name (if any)
9640 const bool hasOperands = tree->OperandsBegin() != tree->OperandsEnd();
9641 if (isLIR)
9642 {
9643 assert(msg == nullptr);
9644
9645 // If the tree does not have any operands, we do not display the indent stack. This gives us
9646 // two additional characters for alignment.
9647 if (!hasOperands)
9648 {
9649 msgLength += 1;
9650 }
9651
9652 if (tree->IsValue())
9653 {
9654 const size_t bufLength = msgLength - 1;
9655 msg = reinterpret_cast<char*>(alloca(bufLength * sizeof(char)));
9656 sprintf_s(const_cast<char*>(msg), bufLength, "t%d = %s", tree->gtTreeID, hasOperands ? "" : " ");
9657 }
9658 }
9659
9660 /* print the msg associated with the node */
9661
9662 if (msg == nullptr)
9663 {
9664 msg = "";
9665 }
9666 if (msgLength < 0)
9667 {
9668 msgLength = 0;
9669 }
9670
9671 printf(isLIR ? " %+*s" : " %-*s", msgLength, msg);
9672
9673 /* Indent the node accordingly */
9674 if (!isLIR || hasOperands)
9675 {
9676 printIndent(indentStack);
9677 }
9678
9679 gtDispNodeName(tree);
9680
9681 assert(tree == nullptr || tree->gtOper < GT_COUNT);
9682
9683 if (tree)
9684 {
9685 /* print the type of the node */
9686 if (tree->gtOper != GT_CAST)
9687 {
9688 printf(" %-6s", varTypeName(tree->TypeGet()));
9689 if (tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_STORE_LCL_VAR)
9690 {
9691 LclVarDsc* varDsc = &lvaTable[tree->gtLclVarCommon.gtLclNum];
9692 if (varDsc->lvAddrExposed)
9693 {
9694 printf("(AX)"); // Variable has address exposed.
9695 }
9696
9697 if (varDsc->lvUnusedStruct)
9698 {
9699 assert(varDsc->lvPromoted);
9700 printf("(U)"); // Unused struct
9701 }
9702 else if (varDsc->lvPromoted)
9703 {
9704 if (varTypeIsPromotable(varDsc))
9705 {
9706 printf("(P)"); // Promoted struct
9707 }
9708 else
9709 {
9710 // Promoted implicit by-refs can have this state during
9711 // global morph while they are being rewritten
9712 assert(fgGlobalMorph);
9713 printf("(P?!)"); // Promoted struct
9714 }
9715 }
9716 }
9717
9718 if (tree->gtOper == GT_STMT)
9719 {
9720 if (opts.compDbgInfo)
9721 {
9722 IL_OFFSET endIL = tree->gtStmt.gtStmtLastILoffs;
9723
9724 printf("(IL ");
9725 if (tree->gtStmt.gtStmtILoffsx == BAD_IL_OFFSET)
9726 {
9727 printf(" ???");
9728 }
9729 else
9730 {
9731 printf("0x%03X", jitGetILoffs(tree->gtStmt.gtStmtILoffsx));
9732 }
9733 printf("...");
9734 if (endIL == BAD_IL_OFFSET)
9735 {
9736 printf(" ???");
9737 }
9738 else
9739 {
9740 printf("0x%03X", endIL);
9741 }
9742 printf(")");
9743 }
9744 }
9745
9746 if (tree->IsArgPlaceHolderNode() && (tree->gtArgPlace.gtArgPlaceClsHnd != nullptr))
9747 {
9748 printf(" => [clsHnd=%08X]", dspPtr(tree->gtArgPlace.gtArgPlaceClsHnd));
9749 }
9750
9751 if (tree->gtOper == GT_RUNTIMELOOKUP)
9752 {
9753#ifdef _TARGET_64BIT_
9754 printf(" 0x%llx", dspPtr(tree->gtRuntimeLookup.gtHnd));
9755#else
9756 printf(" 0x%x", dspPtr(tree->gtRuntimeLookup.gtHnd));
9757#endif
9758
9759 switch (tree->gtRuntimeLookup.gtHndType)
9760 {
9761 case CORINFO_HANDLETYPE_CLASS:
9762 printf(" class");
9763 break;
9764 case CORINFO_HANDLETYPE_METHOD:
9765 printf(" method");
9766 break;
9767 case CORINFO_HANDLETYPE_FIELD:
9768 printf(" field");
9769 break;
9770 default:
9771 printf(" unknown");
9772 break;
9773 }
9774 }
9775 }
9776
9777 // for tracking down problems in reguse prediction or liveness tracking
9778
9779 if (verbose && 0)
9780 {
9781 printf(" RR=");
9782 dspRegMask(tree->gtRsvdRegs);
9783 printf("\n");
9784 }
9785 }
9786}
9787
9788void Compiler::gtDispRegVal(GenTree* tree)
9789{
9790 switch (tree->GetRegTag())
9791 {
9792 // Don't display NOREG; the absence of this tag will imply this state
9793 // case GenTree::GT_REGTAG_NONE: printf(" NOREG"); break;
9794
9795 case GenTree::GT_REGTAG_REG:
9796 printf(" REG %s", compRegVarName(tree->gtRegNum));
9797 break;
9798
9799 default:
9800 break;
9801 }
9802
9803 if (tree->IsMultiRegCall())
9804 {
9805 // 0th reg is gtRegNum, which is already printed above.
9806 // Print the remaining regs of a multi-reg call node.
9807 GenTreeCall* call = tree->AsCall();
9808 unsigned regCount = call->GetReturnTypeDesc()->TryGetReturnRegCount();
9809 for (unsigned i = 1; i < regCount; ++i)
9810 {
9811 printf(",%s", compRegVarName(call->GetRegNumByIdx(i)));
9812 }
9813 }
9814 else if (tree->IsCopyOrReloadOfMultiRegCall())
9815 {
9816 GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload();
9817 GenTreeCall* call = tree->gtGetOp1()->AsCall();
9818 unsigned regCount = call->GetReturnTypeDesc()->TryGetReturnRegCount();
9819 for (unsigned i = 1; i < regCount; ++i)
9820 {
9821 printf(",%s", compRegVarName(copyOrReload->GetRegNumByIdx(i)));
9822 }
9823 }
9824
9825#if FEATURE_MULTIREG_RET
9826 if (tree->IsCopyOrReload())
9827 {
9828 for (int i = 1; i < MAX_RET_REG_COUNT; i++)
9829 {
9830 regNumber reg = (regNumber)tree->AsCopyOrReload()->GetRegNumByIdx(i);
9831 if (reg == REG_NA)
9832 {
9833 break;
9834 }
9835 printf(",%s", compRegVarName(reg));
9836 }
9837 }
9838#endif
9839
9840#if defined(_TARGET_ARM_)
9841 if (tree->OperIsMultiRegOp() && (tree->AsMultiRegOp()->gtOtherReg != REG_NA))
9842 {
9843 printf(",%s", compRegVarName(tree->AsMultiRegOp()->gtOtherReg));
9844 }
9845#endif
9846}
9847
9848// We usually/commonly don't expect to print anything longer than this string,
9849#define LONGEST_COMMON_LCL_VAR_DISPLAY "V99 PInvokeFrame"
9850#define LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH (sizeof(LONGEST_COMMON_LCL_VAR_DISPLAY))
9851#define BUF_SIZE (LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH * 2)
9852
9853void Compiler::gtGetLclVarNameInfo(unsigned lclNum, const char** ilKindOut, const char** ilNameOut, unsigned* ilNumOut)
9854{
9855 const char* ilKind = nullptr;
9856 const char* ilName = nullptr;
9857
9858 unsigned ilNum = compMap2ILvarNum(lclNum);
9859
9860 if (ilNum == (unsigned)ICorDebugInfo::RETBUF_ILNUM)
9861 {
9862 ilName = "RetBuf";
9863 }
9864 else if (ilNum == (unsigned)ICorDebugInfo::VARARGS_HND_ILNUM)
9865 {
9866 ilName = "VarArgHandle";
9867 }
9868 else if (ilNum == (unsigned)ICorDebugInfo::TYPECTXT_ILNUM)
9869 {
9870 ilName = "TypeCtx";
9871 }
9872 else if (ilNum == (unsigned)ICorDebugInfo::UNKNOWN_ILNUM)
9873 {
9874#if FEATURE_ANYCSE
9875 if (lclNumIsTrueCSE(lclNum))
9876 {
9877 ilKind = "cse";
9878 ilNum = lclNum - optCSEstart;
9879 }
9880 else if (lclNum >= optCSEstart)
9881 {
9882 // Currently any new LclVar's introduced after the CSE phase
9883 // are believed to be created by the "rationalizer" that is what is meant by the "rat" prefix.
9884 ilKind = "rat";
9885 ilNum = lclNum - (optCSEstart + optCSEcount);
9886 }
9887 else
9888#endif // FEATURE_ANYCSE
9889 {
9890 if (lclNum == info.compLvFrameListRoot)
9891 {
9892 ilName = "FramesRoot";
9893 }
9894 else if (lclNum == lvaInlinedPInvokeFrameVar)
9895 {
9896 ilName = "PInvokeFrame";
9897 }
9898 else if (lclNum == lvaGSSecurityCookie)
9899 {
9900 ilName = "GsCookie";
9901 }
9902#if FEATURE_FIXED_OUT_ARGS
9903 else if (lclNum == lvaPInvokeFrameRegSaveVar)
9904 {
9905 ilName = "PInvokeFrameRegSave";
9906 }
9907 else if (lclNum == lvaOutgoingArgSpaceVar)
9908 {
9909 ilName = "OutArgs";
9910 }
9911#endif // FEATURE_FIXED_OUT_ARGS
9912#ifdef _TARGET_ARM_
9913 else if (lclNum == lvaPromotedStructAssemblyScratchVar)
9914 {
9915 ilName = "PromotedStructScratch";
9916 }
9917#endif // _TARGET_ARM_
9918#if !FEATURE_EH_FUNCLETS
9919 else if (lclNum == lvaShadowSPslotsVar)
9920 {
9921 ilName = "EHSlots";
9922 }
9923#endif // !FEATURE_EH_FUNCLETS
9924#ifdef JIT32_GCENCODER
9925 else if (lclNum == lvaLocAllocSPvar)
9926 {
9927 ilName = "LocAllocSP";
9928 }
9929#endif // JIT32_GCENCODER
9930#if FEATURE_EH_FUNCLETS
9931 else if (lclNum == lvaPSPSym)
9932 {
9933 ilName = "PSPSym";
9934 }
9935#endif // FEATURE_EH_FUNCLETS
9936 else
9937 {
9938 ilKind = "tmp";
9939 if (compIsForInlining())
9940 {
9941 ilNum = lclNum - impInlineInfo->InlinerCompiler->info.compLocalsCount;
9942 }
9943 else
9944 {
9945 ilNum = lclNum - info.compLocalsCount;
9946 }
9947 }
9948 }
9949 }
9950 else if (lclNum < (compIsForInlining() ? impInlineInfo->InlinerCompiler->info.compArgsCount : info.compArgsCount))
9951 {
9952 if (ilNum == 0 && !info.compIsStatic)
9953 {
9954 ilName = "this";
9955 }
9956 else
9957 {
9958 ilKind = "arg";
9959 }
9960 }
9961 else
9962 {
9963 if (!lvaTable[lclNum].lvIsStructField)
9964 {
9965 ilKind = "loc";
9966 }
9967 if (compIsForInlining())
9968 {
9969 ilNum -= impInlineInfo->InlinerCompiler->info.compILargsCount;
9970 }
9971 else
9972 {
9973 ilNum -= info.compILargsCount;
9974 }
9975 }
9976
9977 *ilKindOut = ilKind;
9978 *ilNameOut = ilName;
9979 *ilNumOut = ilNum;
9980}
9981
9982/*****************************************************************************/
9983int Compiler::gtGetLclVarName(unsigned lclNum, char* buf, unsigned buf_remaining)
9984{
9985 char* bufp_next = buf;
9986 unsigned charsPrinted = 0;
9987 int sprintf_result;
9988
9989 sprintf_result = sprintf_s(bufp_next, buf_remaining, "V%02u", lclNum);
9990
9991 if (sprintf_result < 0)
9992 {
9993 return sprintf_result;
9994 }
9995
9996 charsPrinted += sprintf_result;
9997 bufp_next += sprintf_result;
9998 buf_remaining -= sprintf_result;
9999
10000 const char* ilKind = nullptr;
10001 const char* ilName = nullptr;
10002 unsigned ilNum = 0;
10003
10004 gtGetLclVarNameInfo(lclNum, &ilKind, &ilName, &ilNum);
10005
10006 if (ilName != nullptr)
10007 {
10008 sprintf_result = sprintf_s(bufp_next, buf_remaining, " %s", ilName);
10009 if (sprintf_result < 0)
10010 {
10011 return sprintf_result;
10012 }
10013 charsPrinted += sprintf_result;
10014 bufp_next += sprintf_result;
10015 buf_remaining -= sprintf_result;
10016 }
10017 else if (ilKind != nullptr)
10018 {
10019 sprintf_result = sprintf_s(bufp_next, buf_remaining, " %s%d", ilKind, ilNum);
10020 if (sprintf_result < 0)
10021 {
10022 return sprintf_result;
10023 }
10024 charsPrinted += sprintf_result;
10025 bufp_next += sprintf_result;
10026 buf_remaining -= sprintf_result;
10027 }
10028
10029 assert(charsPrinted > 0);
10030 assert(buf_remaining > 0);
10031
10032 return (int)charsPrinted;
10033}
10034
10035/*****************************************************************************
10036 * Get the local var name, and create a copy of the string that can be used in debug output.
10037 */
10038char* Compiler::gtGetLclVarName(unsigned lclNum)
10039{
10040 char buf[BUF_SIZE];
10041 int charsPrinted = gtGetLclVarName(lclNum, buf, _countof(buf));
10042 if (charsPrinted < 0)
10043 {
10044 return nullptr;
10045 }
10046
10047 char* retBuf = new (this, CMK_DebugOnly) char[charsPrinted + 1];
10048 strcpy_s(retBuf, charsPrinted + 1, buf);
10049 return retBuf;
10050}
10051
10052/*****************************************************************************/
10053void Compiler::gtDispLclVar(unsigned lclNum, bool padForBiggestDisp)
10054{
10055 char buf[BUF_SIZE];
10056 int charsPrinted = gtGetLclVarName(lclNum, buf, _countof(buf));
10057
10058 if (charsPrinted < 0)
10059 {
10060 return;
10061 }
10062
10063 printf("%s", buf);
10064
10065 if (padForBiggestDisp && (charsPrinted < LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH))
10066 {
10067 printf("%*c", LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH - charsPrinted, ' ');
10068 }
10069}
10070
10071/*****************************************************************************/
10072void Compiler::gtDispConst(GenTree* tree)
10073{
10074 assert(tree->OperKind() & GTK_CONST);
10075
10076 switch (tree->gtOper)
10077 {
10078 case GT_CNS_INT:
10079 if (tree->IsIconHandle(GTF_ICON_STR_HDL))
10080 {
10081 const wchar_t* str = eeGetCPString(tree->gtIntCon.gtIconVal);
10082 if (str != nullptr)
10083 {
10084 printf(" 0x%X \"%S\"", dspPtr(tree->gtIntCon.gtIconVal), str);
10085 }
10086 else
10087 {
10088 // Note that eGetCPString isn't currently implemented on Linux/ARM
10089 // and instead always returns nullptr
10090 printf(" 0x%X [ICON_STR_HDL]", dspPtr(tree->gtIntCon.gtIconVal));
10091 }
10092 }
10093 else
10094 {
10095 ssize_t dspIconVal = tree->IsIconHandle() ? dspPtr(tree->gtIntCon.gtIconVal) : tree->gtIntCon.gtIconVal;
10096
10097 if (tree->TypeGet() == TYP_REF)
10098 {
10099 assert(tree->gtIntCon.gtIconVal == 0);
10100 printf(" null");
10101 }
10102 else if ((tree->gtIntCon.gtIconVal > -1000) && (tree->gtIntCon.gtIconVal < 1000))
10103 {
10104 printf(" %ld", dspIconVal);
10105#ifdef _TARGET_64BIT_
10106 }
10107 else if ((tree->gtIntCon.gtIconVal & 0xFFFFFFFF00000000LL) != 0)
10108 {
10109 printf(" 0x%llx", dspIconVal);
10110#endif
10111 }
10112 else
10113 {
10114 printf(" 0x%X", dspIconVal);
10115 }
10116
10117 if (tree->IsIconHandle())
10118 {
10119 switch (tree->GetIconHandleFlag())
10120 {
10121 case GTF_ICON_SCOPE_HDL:
10122 printf(" scope");
10123 break;
10124 case GTF_ICON_CLASS_HDL:
10125 printf(" class");
10126 break;
10127 case GTF_ICON_METHOD_HDL:
10128 printf(" method");
10129 break;
10130 case GTF_ICON_FIELD_HDL:
10131 printf(" field");
10132 break;
10133 case GTF_ICON_STATIC_HDL:
10134 printf(" static");
10135 break;
10136 case GTF_ICON_STR_HDL:
10137 unreached(); // This case is handled above
10138 break;
10139 case GTF_ICON_PSTR_HDL:
10140 printf(" pstr");
10141 break;
10142 case GTF_ICON_PTR_HDL:
10143 printf(" ptr");
10144 break;
10145 case GTF_ICON_VARG_HDL:
10146 printf(" vararg");
10147 break;
10148 case GTF_ICON_PINVKI_HDL:
10149 printf(" pinvoke");
10150 break;
10151 case GTF_ICON_TOKEN_HDL:
10152 printf(" token");
10153 break;
10154 case GTF_ICON_TLS_HDL:
10155 printf(" tls");
10156 break;
10157 case GTF_ICON_FTN_ADDR:
10158 printf(" ftn");
10159 break;
10160 case GTF_ICON_CIDMID_HDL:
10161 printf(" cid/mid");
10162 break;
10163 case GTF_ICON_BBC_PTR:
10164 printf(" bbc");
10165 break;
10166 default:
10167 printf(" UNKNOWN");
10168 break;
10169 }
10170 }
10171
10172 if ((tree->gtFlags & GTF_ICON_FIELD_OFF) != 0)
10173 {
10174 printf(" field offset");
10175 }
10176
10177#ifdef FEATURE_SIMD
10178 if ((tree->gtFlags & GTF_ICON_SIMD_COUNT) != 0)
10179 {
10180 printf(" Vector<T>.Count");
10181 }
10182#endif
10183
10184 if ((tree->IsReuseRegVal()) != 0)
10185 {
10186 printf(" reuse reg val");
10187 }
10188 }
10189
10190 gtDispFieldSeq(tree->gtIntCon.gtFieldSeq);
10191
10192 break;
10193
10194 case GT_CNS_LNG:
10195 printf(" 0x%016I64x", tree->gtLngCon.gtLconVal);
10196 break;
10197
10198 case GT_CNS_DBL:
10199 if (*((__int64*)&tree->gtDblCon.gtDconVal) == (__int64)I64(0x8000000000000000))
10200 {
10201 printf(" -0.00000");
10202 }
10203 else
10204 {
10205 printf(" %#.17g", tree->gtDblCon.gtDconVal);
10206 }
10207 break;
10208 case GT_CNS_STR:
10209 printf("<string constant>");
10210 break;
10211 default:
10212 assert(!"unexpected constant node");
10213 }
10214
10215 gtDispRegVal(tree);
10216}
10217
10218void Compiler::gtDispFieldSeq(FieldSeqNode* pfsn)
10219{
10220 if (pfsn == FieldSeqStore::NotAField() || (pfsn == nullptr))
10221 {
10222 return;
10223 }
10224
10225 // Otherwise...
10226 printf(" Fseq[");
10227 while (pfsn != nullptr)
10228 {
10229 assert(pfsn != FieldSeqStore::NotAField()); // Can't exist in a field sequence list except alone
10230 CORINFO_FIELD_HANDLE fldHnd = pfsn->m_fieldHnd;
10231 // First check the "pseudo" field handles...
10232 if (fldHnd == FieldSeqStore::FirstElemPseudoField)
10233 {
10234 printf("#FirstElem");
10235 }
10236 else if (fldHnd == FieldSeqStore::ConstantIndexPseudoField)
10237 {
10238 printf("#ConstantIndex");
10239 }
10240 else
10241 {
10242 printf("%s", eeGetFieldName(fldHnd));
10243 }
10244 pfsn = pfsn->m_next;
10245 if (pfsn != nullptr)
10246 {
10247 printf(", ");
10248 }
10249 }
10250 printf("]");
10251}
10252
10253//------------------------------------------------------------------------
10254// gtDispLeaf: Print a single leaf node to jitstdout.
10255//
10256// Arguments:
10257// tree - the tree to be printed
10258// indentStack - the specification for the current level of indentation & arcs
10259//
10260// Return Value:
10261// None.
10262//
10263// Notes:
10264// 'indentStack' may be null, in which case no indentation or arcs are printed
10265
10266void Compiler::gtDispLeaf(GenTree* tree, IndentStack* indentStack)
10267{
10268 if (tree->OperKind() & GTK_CONST)
10269 {
10270 gtDispConst(tree);
10271 return;
10272 }
10273
10274 bool isLclFld = false;
10275
10276 switch (tree->gtOper)
10277 {
10278 unsigned varNum;
10279 LclVarDsc* varDsc;
10280
10281 case GT_LCL_FLD:
10282 case GT_LCL_FLD_ADDR:
10283 case GT_STORE_LCL_FLD:
10284 isLclFld = true;
10285 __fallthrough;
10286
10287 case GT_PHI_ARG:
10288 case GT_LCL_VAR:
10289 case GT_LCL_VAR_ADDR:
10290 case GT_STORE_LCL_VAR:
10291 printf(" ");
10292 varNum = tree->gtLclVarCommon.gtLclNum;
10293 varDsc = &lvaTable[varNum];
10294 gtDispLclVar(varNum);
10295 if (tree->gtLclVarCommon.HasSsaName())
10296 {
10297 if (tree->gtFlags & GTF_VAR_USEASG)
10298 {
10299 assert(tree->gtFlags & GTF_VAR_DEF);
10300 printf("ud:%d->%d", tree->gtLclVarCommon.gtSsaNum, GetSsaNumForLocalVarDef(tree));
10301 }
10302 else
10303 {
10304 printf("%s:%d", (tree->gtFlags & GTF_VAR_DEF) ? "d" : "u", tree->gtLclVarCommon.gtSsaNum);
10305 }
10306 }
10307
10308 if (isLclFld)
10309 {
10310 printf("[+%u]", tree->gtLclFld.gtLclOffs);
10311 gtDispFieldSeq(tree->gtLclFld.gtFieldSeq);
10312 }
10313
10314 if (varDsc->lvRegister)
10315 {
10316 printf(" ");
10317 varDsc->PrintVarReg();
10318 }
10319 else if (tree->InReg())
10320 {
10321 printf(" %s", compRegVarName(tree->gtRegNum));
10322 }
10323
10324 if (varDsc->lvPromoted)
10325 {
10326 if (!varTypeIsPromotable(varDsc) && !varDsc->lvUnusedStruct)
10327 {
10328 // Promoted implicit byrefs can get in this state while they are being rewritten
10329 // in global morph.
10330 assert(fgGlobalMorph);
10331 }
10332 else
10333 {
10334 CORINFO_CLASS_HANDLE typeHnd = varDsc->lvVerTypeInfo.GetClassHandle();
10335 CORINFO_FIELD_HANDLE fldHnd;
10336
10337 for (unsigned i = varDsc->lvFieldLclStart; i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++i)
10338 {
10339 LclVarDsc* fieldVarDsc = &lvaTable[i];
10340 const char* fieldName;
10341#if !defined(_TARGET_64BIT_)
10342 if (varTypeIsLong(varDsc))
10343 {
10344 fieldName = (i == 0) ? "lo" : "hi";
10345 }
10346 else
10347#endif // !defined(_TARGET_64BIT_)
10348 {
10349 fldHnd = info.compCompHnd->getFieldInClass(typeHnd, fieldVarDsc->lvFldOrdinal);
10350 fieldName = eeGetFieldName(fldHnd);
10351 }
10352
10353 printf("\n");
10354 printf(" ");
10355 printIndent(indentStack);
10356 printf(" %-6s V%02u.%s (offs=0x%02x) -> ", varTypeName(fieldVarDsc->TypeGet()),
10357 tree->gtLclVarCommon.gtLclNum, fieldName, fieldVarDsc->lvFldOffset);
10358 gtDispLclVar(i);
10359
10360 if (fieldVarDsc->lvRegister)
10361 {
10362 printf(" ");
10363 fieldVarDsc->PrintVarReg();
10364 }
10365
10366 if (fieldVarDsc->lvTracked && fgLocalVarLivenessDone && // Includes local variable liveness
10367 ((tree->gtFlags & GTF_VAR_DEATH) != 0))
10368 {
10369 printf(" (last use)");
10370 }
10371 }
10372 }
10373 }
10374 else // a normal not-promoted lclvar
10375 {
10376 if (varDsc->lvTracked && fgLocalVarLivenessDone && ((tree->gtFlags & GTF_VAR_DEATH) != 0))
10377 {
10378 printf(" (last use)");
10379 }
10380 }
10381 break;
10382
10383 case GT_JMP:
10384 {
10385 const char* methodName;
10386 const char* className;
10387
10388 methodName = eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtVal.gtVal1, &className);
10389 printf(" %s.%s\n", className, methodName);
10390 }
10391 break;
10392
10393 case GT_CLS_VAR:
10394 printf(" Hnd=%#x", dspPtr(tree->gtClsVar.gtClsVarHnd));
10395 gtDispFieldSeq(tree->gtClsVar.gtFieldSeq);
10396 break;
10397
10398 case GT_CLS_VAR_ADDR:
10399 printf(" Hnd=%#x", dspPtr(tree->gtClsVar.gtClsVarHnd));
10400 break;
10401
10402 case GT_LABEL:
10403 if (tree->gtLabel.gtLabBB)
10404 {
10405 printf(" dst=" FMT_BB, tree->gtLabel.gtLabBB->bbNum);
10406 }
10407 else
10408 {
10409 printf(" dst=<null>");
10410 }
10411
10412 break;
10413
10414 case GT_FTN_ADDR:
10415 {
10416 const char* methodName;
10417 const char* className;
10418
10419 methodName = eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtFptrVal.gtFptrMethod, &className);
10420 printf(" %s.%s\n", className, methodName);
10421 }
10422 break;
10423
10424#if !FEATURE_EH_FUNCLETS
10425 case GT_END_LFIN:
10426 printf(" endNstLvl=%d", tree->gtVal.gtVal1);
10427 break;
10428#endif // !FEATURE_EH_FUNCLETS
10429
10430 // Vanilla leaves. No qualifying information available. So do nothing
10431
10432 case GT_NO_OP:
10433 case GT_START_NONGC:
10434 case GT_PROF_HOOK:
10435 case GT_CATCH_ARG:
10436 case GT_MEMORYBARRIER:
10437 case GT_ARGPLACE:
10438 case GT_PINVOKE_PROLOG:
10439 case GT_JMPTABLE:
10440 break;
10441
10442 case GT_RET_EXPR:
10443 printf("(inl return from call ");
10444 printTreeID(tree->gtRetExpr.gtInlineCandidate);
10445 printf(")");
10446 break;
10447
10448 case GT_PHYSREG:
10449 printf(" %s", getRegName(tree->gtPhysReg.gtSrcReg, varTypeIsFloating(tree)));
10450 break;
10451
10452 case GT_IL_OFFSET:
10453 printf(" IL offset: ");
10454 if (tree->gtStmt.gtStmtILoffsx == BAD_IL_OFFSET)
10455 {
10456 printf("???");
10457 }
10458 else
10459 {
10460 printf("0x%x", jitGetILoffs(tree->gtStmt.gtStmtILoffsx));
10461 }
10462 break;
10463
10464 case GT_JCC:
10465 case GT_SETCC:
10466 printf(" cond=%s", GenTree::OpName(tree->AsCC()->gtCondition));
10467 break;
10468 case GT_JCMP:
10469 printf(" cond=%s%s", (tree->gtFlags & GTF_JCMP_TST) ? "TEST_" : "",
10470 (tree->gtFlags & GTF_JCMP_EQ) ? "EQ" : "NE");
10471
10472 default:
10473 assert(!"don't know how to display tree leaf node");
10474 }
10475
10476 gtDispRegVal(tree);
10477}
10478
10479//------------------------------------------------------------------------
10480// gtDispLeaf: Print a child node to jitstdout.
10481//
10482// Arguments:
10483// tree - the tree to be printed
10484// indentStack - the specification for the current level of indentation & arcs
10485// arcType - the type of arc to use for this child
10486// msg - a contextual method (i.e. from the parent) to print
10487// topOnly - a boolean indicating whether to print the children, or just the top node
10488//
10489// Return Value:
10490// None.
10491//
10492// Notes:
10493// 'indentStack' may be null, in which case no indentation or arcs are printed
10494// 'msg' has a default value of null
10495// 'topOnly' is an optional argument that defaults to false
10496
10497void Compiler::gtDispChild(GenTree* child,
10498 IndentStack* indentStack,
10499 IndentInfo arcType,
10500 __in_opt const char* msg, /* = nullptr */
10501 bool topOnly) /* = false */
10502{
10503 indentStack->Push(arcType);
10504 gtDispTree(child, indentStack, msg, topOnly);
10505 indentStack->Pop();
10506}
10507
10508#ifdef FEATURE_SIMD
10509// Intrinsic Id to name map
10510extern const char* const simdIntrinsicNames[] = {
10511#define SIMD_INTRINSIC(mname, inst, id, name, r, ac, arg1, arg2, arg3, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) name,
10512#include "simdintrinsiclist.h"
10513};
10514#endif // FEATURE_SIMD
10515
10516/*****************************************************************************/
10517
10518void Compiler::gtDispTree(GenTree* tree,
10519 IndentStack* indentStack, /* = nullptr */
10520 __in __in_z __in_opt const char* msg, /* = nullptr */
10521 bool topOnly, /* = false */
10522 bool isLIR) /* = false */
10523{
10524 if (tree == nullptr)
10525 {
10526 printf(" [%08X] <NULL>\n", tree);
10527 printf(""); // null string means flush
10528 return;
10529 }
10530
10531 if (indentStack == nullptr)
10532 {
10533 indentStack = new (this, CMK_DebugOnly) IndentStack(this);
10534 }
10535
10536 if (IsUninitialized(tree))
10537 {
10538 /* Value used to initalize nodes */
10539 printf("Uninitialized tree node!");
10540 return;
10541 }
10542
10543 if (tree->gtOper >= GT_COUNT)
10544 {
10545 gtDispNode(tree, indentStack, msg, isLIR);
10546 printf("Bogus operator!");
10547 return;
10548 }
10549
10550 /* Is tree a leaf node? */
10551
10552 if (tree->OperIsLeaf() || tree->OperIsLocalStore()) // local stores used to be leaves
10553 {
10554 gtDispNode(tree, indentStack, msg, isLIR);
10555 gtDispLeaf(tree, indentStack);
10556 gtDispVN(tree);
10557 printf("\n");
10558 if (tree->OperIsLocalStore() && !topOnly)
10559 {
10560 gtDispChild(tree->gtOp.gtOp1, indentStack, IINone);
10561 }
10562 return;
10563 }
10564
10565 // Determine what kind of arc to propagate.
10566 IndentInfo myArc = IINone;
10567 IndentInfo lowerArc = IINone;
10568 if (indentStack->Depth() > 0)
10569 {
10570 myArc = indentStack->Pop();
10571 switch (myArc)
10572 {
10573 case IIArcBottom:
10574 indentStack->Push(IIArc);
10575 lowerArc = IINone;
10576 break;
10577 case IIArc:
10578 indentStack->Push(IIArc);
10579 lowerArc = IIArc;
10580 break;
10581 case IIArcTop:
10582 indentStack->Push(IINone);
10583 lowerArc = IIArc;
10584 break;
10585 case IIEmbedded:
10586 indentStack->Push(IIEmbedded);
10587 lowerArc = IIEmbedded;
10588 break;
10589 case IINone:
10590 indentStack->Push(IINone);
10591 lowerArc = IINone;
10592 break;
10593 default:
10594 unreached();
10595 break;
10596 }
10597 }
10598
10599 // Special case formatting for PHI nodes -- arg lists like calls.
10600
10601 if (tree->OperGet() == GT_PHI)
10602 {
10603 gtDispNode(tree, indentStack, msg, isLIR);
10604 gtDispVN(tree);
10605 printf("\n");
10606
10607 if (!topOnly)
10608 {
10609 if (tree->gtOp.gtOp1 != nullptr)
10610 {
10611 IndentInfo arcType = IIArcTop;
10612 for (GenTreeArgList* args = tree->gtOp.gtOp1->AsArgList(); args != nullptr; args = args->Rest())
10613 {
10614 if (args->Rest() == nullptr)
10615 {
10616 arcType = IIArcBottom;
10617 }
10618 gtDispChild(args->Current(), indentStack, arcType);
10619 arcType = IIArc;
10620 }
10621 }
10622 }
10623 return;
10624 }
10625
10626 /* Is it a 'simple' unary/binary operator? */
10627
10628 const char* childMsg = nullptr;
10629
10630 if (tree->OperIsSimple())
10631 {
10632 if (!topOnly)
10633 {
10634 if (tree->gtGetOp2IfPresent())
10635 {
10636 // Label the childMsgs of the GT_COLON operator
10637 // op2 is the then part
10638
10639 if (tree->gtOper == GT_COLON)
10640 {
10641 childMsg = "then";
10642 }
10643 gtDispChild(tree->gtOp.gtOp2, indentStack, IIArcTop, childMsg, topOnly);
10644 }
10645 }
10646
10647 // Now, get the right type of arc for this node
10648 if (myArc != IINone)
10649 {
10650 indentStack->Pop();
10651 indentStack->Push(myArc);
10652 }
10653
10654 gtDispNode(tree, indentStack, msg, isLIR);
10655
10656 // Propagate lowerArc to the lower children.
10657 if (indentStack->Depth() > 0)
10658 {
10659 (void)indentStack->Pop();
10660 indentStack->Push(lowerArc);
10661 }
10662
10663 if (tree->gtOper == GT_CAST)
10664 {
10665 /* Format a message that explains the effect of this GT_CAST */
10666
10667 var_types fromType = genActualType(tree->gtCast.CastOp()->TypeGet());
10668 var_types toType = tree->CastToType();
10669 var_types finalType = tree->TypeGet();
10670
10671 /* if GTF_UNSIGNED is set then force fromType to an unsigned type */
10672 if (tree->gtFlags & GTF_UNSIGNED)
10673 {
10674 fromType = genUnsignedType(fromType);
10675 }
10676
10677 if (finalType != toType)
10678 {
10679 printf(" %s <-", varTypeName(finalType));
10680 }
10681
10682 printf(" %s <- %s", varTypeName(toType), varTypeName(fromType));
10683 }
10684
10685 if (tree->gtOper == GT_OBJ && (tree->gtFlags & GTF_VAR_DEATH))
10686 {
10687 printf(" (last use)");
10688 }
10689 if (tree->OperIsBlkOp())
10690 {
10691 if (tree->OperIsCopyBlkOp())
10692 {
10693 printf(" (copy)");
10694 }
10695 else if (tree->OperIsInitBlkOp())
10696 {
10697 printf(" (init)");
10698 }
10699 if (tree->OperIsStoreBlk() && (tree->AsBlk()->gtBlkOpKind != GenTreeBlk::BlkOpKindInvalid))
10700 {
10701 switch (tree->AsBlk()->gtBlkOpKind)
10702 {
10703 case GenTreeBlk::BlkOpKindRepInstr:
10704 printf(" (RepInstr)");
10705 break;
10706 case GenTreeBlk::BlkOpKindUnroll:
10707 printf(" (Unroll)");
10708 break;
10709 case GenTreeBlk::BlkOpKindHelper:
10710 printf(" (Helper)");
10711 break;
10712 default:
10713 unreached();
10714 }
10715 }
10716 }
10717 else if (tree->OperIsFieldList())
10718 {
10719 printf(" %s at offset %d", varTypeName(tree->AsFieldList()->gtFieldType),
10720 tree->AsFieldList()->gtFieldOffset);
10721 }
10722#if FEATURE_PUT_STRUCT_ARG_STK
10723 else if (tree->OperGet() == GT_PUTARG_STK)
10724 {
10725 printf(" (%d slots)", tree->AsPutArgStk()->gtNumSlots);
10726 if (tree->AsPutArgStk()->gtPutArgStkKind != GenTreePutArgStk::Kind::Invalid)
10727 {
10728 switch (tree->AsPutArgStk()->gtPutArgStkKind)
10729 {
10730 case GenTreePutArgStk::Kind::RepInstr:
10731 printf(" (RepInstr)");
10732 break;
10733 case GenTreePutArgStk::Kind::Unroll:
10734 printf(" (Unroll)");
10735 break;
10736 case GenTreePutArgStk::Kind::Push:
10737 printf(" (Push)");
10738 break;
10739 case GenTreePutArgStk::Kind::PushAllSlots:
10740 printf(" (PushAllSlots)");
10741 break;
10742 default:
10743 unreached();
10744 }
10745 }
10746 }
10747#endif // FEATURE_PUT_STRUCT_ARG_STK
10748
10749 if (tree->gtOper == GT_INTRINSIC)
10750 {
10751 switch (tree->gtIntrinsic.gtIntrinsicId)
10752 {
10753 case CORINFO_INTRINSIC_Sin:
10754 printf(" sin");
10755 break;
10756 case CORINFO_INTRINSIC_Cos:
10757 printf(" cos");
10758 break;
10759 case CORINFO_INTRINSIC_Cbrt:
10760 printf(" cbrt");
10761 break;
10762 case CORINFO_INTRINSIC_Sqrt:
10763 printf(" sqrt");
10764 break;
10765 case CORINFO_INTRINSIC_Abs:
10766 printf(" abs");
10767 break;
10768 case CORINFO_INTRINSIC_Round:
10769 printf(" round");
10770 break;
10771 case CORINFO_INTRINSIC_Cosh:
10772 printf(" cosh");
10773 break;
10774 case CORINFO_INTRINSIC_Sinh:
10775 printf(" sinh");
10776 break;
10777 case CORINFO_INTRINSIC_Tan:
10778 printf(" tan");
10779 break;
10780 case CORINFO_INTRINSIC_Tanh:
10781 printf(" tanh");
10782 break;
10783 case CORINFO_INTRINSIC_Asin:
10784 printf(" asin");
10785 break;
10786 case CORINFO_INTRINSIC_Asinh:
10787 printf(" asinh");
10788 break;
10789 case CORINFO_INTRINSIC_Acos:
10790 printf(" acos");
10791 break;
10792 case CORINFO_INTRINSIC_Acosh:
10793 printf(" acosh");
10794 break;
10795 case CORINFO_INTRINSIC_Atan:
10796 printf(" atan");
10797 break;
10798 case CORINFO_INTRINSIC_Atan2:
10799 printf(" atan2");
10800 break;
10801 case CORINFO_INTRINSIC_Atanh:
10802 printf(" atanh");
10803 break;
10804 case CORINFO_INTRINSIC_Log10:
10805 printf(" log10");
10806 break;
10807 case CORINFO_INTRINSIC_Pow:
10808 printf(" pow");
10809 break;
10810 case CORINFO_INTRINSIC_Exp:
10811 printf(" exp");
10812 break;
10813 case CORINFO_INTRINSIC_Ceiling:
10814 printf(" ceiling");
10815 break;
10816 case CORINFO_INTRINSIC_Floor:
10817 printf(" floor");
10818 break;
10819 case CORINFO_INTRINSIC_Object_GetType:
10820 printf(" objGetType");
10821 break;
10822
10823 default:
10824 unreached();
10825 }
10826 }
10827
10828#ifdef FEATURE_SIMD
10829 if (tree->gtOper == GT_SIMD)
10830 {
10831 printf(" %s %s", varTypeName(tree->gtSIMD.gtSIMDBaseType),
10832 simdIntrinsicNames[tree->gtSIMD.gtSIMDIntrinsicID]);
10833 }
10834#endif // FEATURE_SIMD
10835
10836#ifdef FEATURE_HW_INTRINSICS
10837 if (tree->gtOper == GT_HWIntrinsic)
10838 {
10839 printf(" %s %s",
10840 tree->gtHWIntrinsic.gtSIMDBaseType == TYP_UNKNOWN ? ""
10841 : varTypeName(tree->gtHWIntrinsic.gtSIMDBaseType),
10842 HWIntrinsicInfo::lookupName(tree->gtHWIntrinsic.gtHWIntrinsicId));
10843 }
10844#endif // FEATURE_HW_INTRINSICS
10845
10846 gtDispRegVal(tree);
10847 gtDispVN(tree);
10848 printf("\n");
10849
10850 if (!topOnly && tree->gtOp.gtOp1)
10851 {
10852
10853 // Label the child of the GT_COLON operator
10854 // op1 is the else part
10855
10856 if (tree->gtOper == GT_COLON)
10857 {
10858 childMsg = "else";
10859 }
10860 else if (tree->gtOper == GT_QMARK)
10861 {
10862 childMsg = " if";
10863 }
10864 gtDispChild(tree->gtOp.gtOp1, indentStack, IIArcBottom, childMsg, topOnly);
10865 }
10866
10867 return;
10868 }
10869
10870 // Now, get the right type of arc for this node
10871 if (myArc != IINone)
10872 {
10873 indentStack->Pop();
10874 indentStack->Push(myArc);
10875 }
10876 gtDispNode(tree, indentStack, msg, isLIR);
10877
10878 // Propagate lowerArc to the lower children.
10879 if (indentStack->Depth() > 0)
10880 {
10881 (void)indentStack->Pop();
10882 indentStack->Push(lowerArc);
10883 }
10884
10885 // See what kind of a special operator we have here, and handle its special children.
10886
10887 switch (tree->gtOper)
10888 {
10889 case GT_FIELD:
10890 if (FieldSeqStore::IsPseudoField(tree->gtField.gtFldHnd))
10891 {
10892 printf(" #PseudoField:0x%x", tree->gtField.gtFldOffset);
10893 }
10894 else
10895 {
10896 printf(" %s", eeGetFieldName(tree->gtField.gtFldHnd), 0);
10897 }
10898
10899 if (tree->gtField.gtFldObj && !topOnly)
10900 {
10901 gtDispVN(tree);
10902 printf("\n");
10903 gtDispChild(tree->gtField.gtFldObj, indentStack, IIArcBottom);
10904 }
10905 else
10906 {
10907 gtDispRegVal(tree);
10908 gtDispVN(tree);
10909 printf("\n");
10910 }
10911 break;
10912
10913 case GT_CALL:
10914 {
10915 GenTreeCall* call = tree->AsCall();
10916 assert(call->gtFlags & GTF_CALL);
10917 unsigned numChildren = call->NumChildren();
10918 GenTree* lastChild = nullptr;
10919 if (numChildren != 0)
10920 {
10921 lastChild = call->GetChild(numChildren - 1);
10922 }
10923
10924 if (call->gtCallType != CT_INDIRECT)
10925 {
10926 const char* methodName;
10927 const char* className;
10928
10929 methodName = eeGetMethodName(call->gtCallMethHnd, &className);
10930
10931 printf(" %s.%s", className, methodName);
10932 }
10933
10934 if ((call->gtFlags & GTF_CALL_UNMANAGED) && (call->gtCallMoreFlags & GTF_CALL_M_FRAME_VAR_DEATH))
10935 {
10936 printf(" (FramesRoot last use)");
10937 }
10938
10939 if (((call->gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0) && (call->gtInlineCandidateInfo != nullptr) &&
10940 (call->gtInlineCandidateInfo->exactContextHnd != nullptr))
10941 {
10942 printf(" (exactContextHnd=0x%p)", dspPtr(call->gtInlineCandidateInfo->exactContextHnd));
10943 }
10944
10945 gtDispVN(call);
10946 if (call->IsMultiRegCall())
10947 {
10948 gtDispRegVal(call);
10949 }
10950 printf("\n");
10951
10952 if (!topOnly)
10953 {
10954 char buf[64];
10955 char* bufp;
10956
10957 bufp = &buf[0];
10958
10959 if ((call->gtCallObjp != nullptr) && (call->gtCallObjp->gtOper != GT_NOP) &&
10960 (!call->gtCallObjp->IsArgPlaceHolderNode()))
10961 {
10962 if (call->gtCallObjp->gtOper == GT_ASG)
10963 {
10964 sprintf_s(bufp, sizeof(buf), "this SETUP%c", 0);
10965 }
10966 else
10967 {
10968 sprintf_s(bufp, sizeof(buf), "this in %s%c", compRegVarName(REG_ARG_0), 0);
10969 }
10970 gtDispChild(call->gtCallObjp, indentStack, (call->gtCallObjp == lastChild) ? IIArcBottom : IIArc,
10971 bufp, topOnly);
10972 }
10973
10974 if (call->gtCallArgs)
10975 {
10976 gtDispArgList(call, indentStack);
10977 }
10978
10979 if (call->gtCallType == CT_INDIRECT)
10980 {
10981 gtDispChild(call->gtCallAddr, indentStack, (call->gtCallAddr == lastChild) ? IIArcBottom : IIArc,
10982 "calli tgt", topOnly);
10983 }
10984
10985 if (call->gtControlExpr != nullptr)
10986 {
10987 gtDispChild(call->gtControlExpr, indentStack,
10988 (call->gtControlExpr == lastChild) ? IIArcBottom : IIArc, "control expr", topOnly);
10989 }
10990
10991#if !FEATURE_FIXED_OUT_ARGS
10992 regList list = call->regArgList;
10993#endif
10994 /* process the late argument list */
10995 int lateArgIndex = 0;
10996 for (GenTreeArgList* lateArgs = call->gtCallLateArgs; lateArgs;
10997 (lateArgIndex++, lateArgs = lateArgs->Rest()))
10998 {
10999 GenTree* argx;
11000
11001 argx = lateArgs->Current();
11002
11003 IndentInfo arcType = (lateArgs->Rest() == nullptr) ? IIArcBottom : IIArc;
11004 gtGetLateArgMsg(call, argx, lateArgIndex, -1, bufp, sizeof(buf));
11005 gtDispChild(argx, indentStack, arcType, bufp, topOnly);
11006 }
11007 }
11008 }
11009 break;
11010
11011 case GT_STMT:
11012 printf("\n");
11013
11014 if (!topOnly)
11015 {
11016 gtDispChild(tree->gtStmt.gtStmtExpr, indentStack, IIArcBottom);
11017 }
11018 break;
11019
11020 case GT_ARR_ELEM:
11021 gtDispVN(tree);
11022 printf("\n");
11023
11024 if (!topOnly)
11025 {
11026 gtDispChild(tree->gtArrElem.gtArrObj, indentStack, IIArc, nullptr, topOnly);
11027
11028 unsigned dim;
11029 for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
11030 {
11031 IndentInfo arcType = ((dim + 1) == tree->gtArrElem.gtArrRank) ? IIArcBottom : IIArc;
11032 gtDispChild(tree->gtArrElem.gtArrInds[dim], indentStack, arcType, nullptr, topOnly);
11033 }
11034 }
11035 break;
11036
11037 case GT_ARR_OFFSET:
11038 gtDispVN(tree);
11039 printf("\n");
11040 if (!topOnly)
11041 {
11042 gtDispChild(tree->gtArrOffs.gtOffset, indentStack, IIArc, nullptr, topOnly);
11043 gtDispChild(tree->gtArrOffs.gtIndex, indentStack, IIArc, nullptr, topOnly);
11044 gtDispChild(tree->gtArrOffs.gtArrObj, indentStack, IIArcBottom, nullptr, topOnly);
11045 }
11046 break;
11047
11048 case GT_CMPXCHG:
11049 gtDispVN(tree);
11050 printf("\n");
11051 if (!topOnly)
11052 {
11053 gtDispChild(tree->gtCmpXchg.gtOpLocation, indentStack, IIArc, nullptr, topOnly);
11054 gtDispChild(tree->gtCmpXchg.gtOpValue, indentStack, IIArc, nullptr, topOnly);
11055 gtDispChild(tree->gtCmpXchg.gtOpComparand, indentStack, IIArcBottom, nullptr, topOnly);
11056 }
11057 break;
11058
11059 case GT_ARR_BOUNDS_CHECK:
11060#ifdef FEATURE_SIMD
11061 case GT_SIMD_CHK:
11062#endif // FEATURE_SIMD
11063#ifdef FEATURE_HW_INTRINSICS
11064 case GT_HW_INTRINSIC_CHK:
11065#endif // FEATURE_HW_INTRINSICS
11066 gtDispVN(tree);
11067 printf("\n");
11068 if (!topOnly)
11069 {
11070 gtDispChild(tree->gtBoundsChk.gtIndex, indentStack, IIArc, nullptr, topOnly);
11071 gtDispChild(tree->gtBoundsChk.gtArrLen, indentStack, IIArcBottom, nullptr, topOnly);
11072 }
11073 break;
11074
11075 case GT_STORE_DYN_BLK:
11076 case GT_DYN_BLK:
11077 if (tree->OperIsCopyBlkOp())
11078 {
11079 printf(" (copy)");
11080 }
11081 else if (tree->OperIsInitBlkOp())
11082 {
11083 printf(" (init)");
11084 }
11085 gtDispVN(tree);
11086 printf("\n");
11087 if (!topOnly)
11088 {
11089 if (tree->gtDynBlk.Data() != nullptr)
11090 {
11091 gtDispChild(tree->gtDynBlk.Data(), indentStack, IIArc, nullptr, topOnly);
11092 }
11093 gtDispChild(tree->gtDynBlk.Addr(), indentStack, IIArc, nullptr, topOnly);
11094 gtDispChild(tree->gtDynBlk.gtDynamicSize, indentStack, IIArcBottom, nullptr, topOnly);
11095 }
11096 break;
11097
11098 default:
11099 printf("<DON'T KNOW HOW TO DISPLAY THIS NODE> :");
11100 printf(""); // null string means flush
11101 break;
11102 }
11103}
11104
11105//------------------------------------------------------------------------
11106// gtGetArgMsg: Construct a message about the given argument
11107//
11108// Arguments:
11109// call - The call for which 'arg' is an argument
11110// arg - The argument for which a message should be constructed
11111// argNum - The ordinal number of the arg in the argument list
11112// listCount - When printing in LIR form this is the count for a GT_FIELD_LIST
11113// or -1 if we are not printing in LIR form
11114// bufp - A pointer to the buffer into which the message is written
11115// bufLength - The length of the buffer pointed to by bufp
11116//
11117// Return Value:
11118// No return value, but bufp is written.
11119//
11120// Assumptions:
11121// 'call' must be a call node
11122// 'arg' must be an argument to 'call' (else gtArgEntryByNode will assert)
11123
11124void Compiler::gtGetArgMsg(
11125 GenTreeCall* call, GenTree* arg, unsigned argNum, int listCount, char* bufp, unsigned bufLength)
11126{
11127 if (call->gtCallLateArgs != nullptr)
11128 {
11129 fgArgTabEntry* curArgTabEntry = gtArgEntryByArgNum(call, argNum);
11130 assert(curArgTabEntry);
11131
11132 if (arg->gtFlags & GTF_LATE_ARG)
11133 {
11134 sprintf_s(bufp, bufLength, "arg%d SETUP%c", argNum, 0);
11135 }
11136 else
11137 {
11138#ifdef _TARGET_ARM_
11139 if (curArgTabEntry->isSplit)
11140 {
11141 regNumber firstReg = curArgTabEntry->regNum;
11142 if (listCount == -1)
11143 {
11144 if (curArgTabEntry->numRegs == 1)
11145 {
11146 sprintf_s(bufp, bufLength, "arg%d %s out+%02x%c", argNum, compRegVarName(firstReg),
11147 (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE, 0);
11148 }
11149 else
11150 {
11151 regNumber lastReg = REG_STK;
11152 char separator = (curArgTabEntry->numRegs == 2) ? ',' : '-';
11153 if (curArgTabEntry->isHfaRegArg)
11154 {
11155 unsigned lastRegNum = genMapFloatRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
11156 lastReg = genMapFloatRegArgNumToRegNum(lastRegNum);
11157 }
11158 else
11159 {
11160 unsigned lastRegNum = genMapIntRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
11161 lastReg = genMapIntRegArgNumToRegNum(lastRegNum);
11162 }
11163 sprintf_s(bufp, bufLength, "arg%d %s%c%s out+%02x%c", argNum, compRegVarName(firstReg),
11164 separator, compRegVarName(lastReg), (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE,
11165 0);
11166 }
11167 }
11168 else
11169 {
11170 unsigned curArgNum = BAD_VAR_NUM;
11171 bool isFloat = curArgTabEntry->isHfaRegArg;
11172 if (isFloat)
11173 {
11174 curArgNum = genMapFloatRegNumToRegArgNum(firstReg) + listCount;
11175 }
11176 else
11177 {
11178 curArgNum = genMapIntRegNumToRegArgNum(firstReg) + listCount;
11179 }
11180
11181 if (!isFloat && curArgNum < MAX_REG_ARG)
11182 {
11183 regNumber curReg = genMapIntRegArgNumToRegNum(curArgNum);
11184 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
11185 }
11186 else if (isFloat && curArgNum < MAX_FLOAT_REG_ARG)
11187 {
11188 regNumber curReg = genMapFloatRegArgNumToRegNum(curArgNum);
11189 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
11190 }
11191 else
11192 {
11193 unsigned stackSlot = listCount - curArgTabEntry->numRegs;
11194 sprintf_s(bufp, bufLength, "arg%d m%d out+%02x%c", argNum, listCount,
11195 stackSlot * TARGET_POINTER_SIZE, 0);
11196 }
11197 }
11198 return;
11199 }
11200#endif // _TARGET_ARM_
11201#if FEATURE_FIXED_OUT_ARGS
11202 if (listCount == -1)
11203 {
11204 sprintf_s(bufp, bufLength, "arg%d out+%02x%c", argNum, curArgTabEntry->slotNum * TARGET_POINTER_SIZE,
11205 0);
11206 }
11207 else // listCount is 0,1,2 or 3
11208 {
11209 assert(listCount <= MAX_ARG_REG_COUNT);
11210 sprintf_s(bufp, bufLength, "arg%d out+%02x%c", argNum,
11211 (curArgTabEntry->slotNum + listCount) * TARGET_POINTER_SIZE, 0);
11212 }
11213#else
11214 sprintf_s(bufp, bufLength, "arg%d on STK%c", argNum, 0);
11215#endif
11216 }
11217 }
11218 else
11219 {
11220 sprintf_s(bufp, bufLength, "arg%d%c", argNum, 0);
11221 }
11222}
11223
11224//------------------------------------------------------------------------
11225// gtGetLateArgMsg: Construct a message about the given argument
11226//
11227// Arguments:
11228// call - The call for which 'arg' is an argument
11229// argx - The argument for which a message should be constructed
11230// lateArgIndex - The ordinal number of the arg in the lastArg list
11231// listCount - When printing in LIR form this is the count for a multireg GT_FIELD_LIST
11232// or -1 if we are not printing in LIR form
11233// bufp - A pointer to the buffer into which the message is written
11234// bufLength - The length of the buffer pointed to by bufp
11235//
11236// Return Value:
11237// No return value, but bufp is written.
11238//
11239// Assumptions:
11240// 'call' must be a call node
11241// 'arg' must be an argument to 'call' (else gtArgEntryByNode will assert)
11242
11243void Compiler::gtGetLateArgMsg(
11244 GenTreeCall* call, GenTree* argx, int lateArgIndex, int listCount, char* bufp, unsigned bufLength)
11245{
11246 assert(!argx->IsArgPlaceHolderNode()); // No place holders nodes are in gtCallLateArgs;
11247
11248 fgArgTabEntry* curArgTabEntry = gtArgEntryByLateArgIndex(call, lateArgIndex);
11249 assert(curArgTabEntry);
11250 regNumber argReg = curArgTabEntry->regNum;
11251
11252#if !FEATURE_FIXED_OUT_ARGS
11253 assert(lateArgIndex < call->regArgListCount);
11254 assert(argReg == call->regArgList[lateArgIndex]);
11255#else
11256 if (argReg == REG_STK)
11257 {
11258 sprintf_s(bufp, bufLength, "arg%d in out+%02x%c", curArgTabEntry->argNum,
11259 curArgTabEntry->slotNum * TARGET_POINTER_SIZE, 0);
11260 }
11261 else
11262#endif
11263 {
11264 if (gtArgIsThisPtr(curArgTabEntry))
11265 {
11266 sprintf_s(bufp, bufLength, "this in %s%c", compRegVarName(argReg), 0);
11267 }
11268#ifdef _TARGET_ARM_
11269 else if (curArgTabEntry->isSplit)
11270 {
11271 regNumber firstReg = curArgTabEntry->regNum;
11272 unsigned argNum = curArgTabEntry->argNum;
11273 if (listCount == -1)
11274 {
11275 if (curArgTabEntry->numRegs == 1)
11276 {
11277 sprintf_s(bufp, bufLength, "arg%d %s out+%02x%c", argNum, compRegVarName(firstReg),
11278 (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE, 0);
11279 }
11280 else
11281 {
11282 regNumber lastReg = REG_STK;
11283 char separator = (curArgTabEntry->numRegs == 2) ? ',' : '-';
11284 if (curArgTabEntry->isHfaRegArg)
11285 {
11286 unsigned lastRegNum = genMapFloatRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
11287 lastReg = genMapFloatRegArgNumToRegNum(lastRegNum);
11288 }
11289 else
11290 {
11291 unsigned lastRegNum = genMapIntRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
11292 lastReg = genMapIntRegArgNumToRegNum(lastRegNum);
11293 }
11294 sprintf_s(bufp, bufLength, "arg%d %s%c%s out+%02x%c", argNum, compRegVarName(firstReg), separator,
11295 compRegVarName(lastReg), (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE, 0);
11296 }
11297 }
11298 else
11299 {
11300 unsigned curArgNum = BAD_VAR_NUM;
11301 bool isFloat = curArgTabEntry->isHfaRegArg;
11302 if (isFloat)
11303 {
11304 curArgNum = genMapFloatRegNumToRegArgNum(firstReg) + listCount;
11305 }
11306 else
11307 {
11308 curArgNum = genMapIntRegNumToRegArgNum(firstReg) + listCount;
11309 }
11310
11311 if (!isFloat && curArgNum < MAX_REG_ARG)
11312 {
11313 regNumber curReg = genMapIntRegArgNumToRegNum(curArgNum);
11314 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
11315 }
11316 else if (isFloat && curArgNum < MAX_FLOAT_REG_ARG)
11317 {
11318 regNumber curReg = genMapFloatRegArgNumToRegNum(curArgNum);
11319 sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
11320 }
11321 else
11322 {
11323 unsigned stackSlot = listCount - curArgTabEntry->numRegs;
11324 sprintf_s(bufp, bufLength, "arg%d m%d out+%02x%c", argNum, listCount,
11325 stackSlot * TARGET_POINTER_SIZE, 0);
11326 }
11327 }
11328 return;
11329 }
11330#endif // _TARGET_ARM_
11331 else
11332 {
11333#if FEATURE_MULTIREG_ARGS
11334 if (curArgTabEntry->numRegs >= 2)
11335 {
11336 // listCount could be -1 but it is signed, so this comparison is OK.
11337 assert(listCount <= MAX_ARG_REG_COUNT);
11338 char separator = (curArgTabEntry->numRegs == 2) ? ',' : '-';
11339 sprintf_s(bufp, bufLength, "arg%d %s%c%s%c", curArgTabEntry->argNum, compRegVarName(argReg), separator,
11340 compRegVarName(curArgTabEntry->getRegNum(curArgTabEntry->numRegs - 1)), 0);
11341 }
11342 else
11343#endif
11344 {
11345 sprintf_s(bufp, bufLength, "arg%d in %s%c", curArgTabEntry->argNum, compRegVarName(argReg), 0);
11346 }
11347 }
11348 }
11349}
11350
11351//------------------------------------------------------------------------
11352// gtDispArgList: Dump the tree for a call arg list
11353//
11354// Arguments:
11355// call - The call to dump arguments for
11356// indentStack - the specification for the current level of indentation & arcs
11357//
11358// Return Value:
11359// None.
11360//
11361void Compiler::gtDispArgList(GenTreeCall* call, IndentStack* indentStack)
11362{
11363 GenTree* args = call->gtCallArgs;
11364 unsigned argnum = 0;
11365 const int BufLength = 256;
11366 char buf[BufLength];
11367 char* bufp = &buf[0];
11368 unsigned numChildren = call->NumChildren();
11369 assert(numChildren != 0);
11370 bool argListIsLastChild = (args == call->GetChild(numChildren - 1));
11371
11372 IndentInfo arcType = IIArc;
11373 if (call->gtCallObjp != nullptr)
11374 {
11375 argnum++;
11376 }
11377
11378 while (args != nullptr)
11379 {
11380 assert(args->gtOper == GT_LIST);
11381 GenTree* arg = args->gtOp.gtOp1;
11382 if (!arg->IsNothingNode() && !arg->IsArgPlaceHolderNode())
11383 {
11384 gtGetArgMsg(call, arg, argnum, -1, bufp, BufLength);
11385 if (argListIsLastChild && (args->gtOp.gtOp2 == nullptr))
11386 {
11387 arcType = IIArcBottom;
11388 }
11389 gtDispChild(arg, indentStack, arcType, bufp, false);
11390 }
11391 args = args->gtOp.gtOp2;
11392 argnum++;
11393 }
11394}
11395
11396//------------------------------------------------------------------------
11397// gtDispArgList: Dump the tree for a call arg list
11398//
11399// Arguments:
11400// tree - The call for which 'arg' is an argument
11401// indentStack - the specification for the current level of indentation & arcs
11402//
11403// Return Value:
11404// None.
11405//
11406// Assumptions:
11407// 'tree' must be a GT_LIST node
11408
11409void Compiler::gtDispTreeList(GenTree* tree, IndentStack* indentStack /* = nullptr */)
11410{
11411 for (/*--*/; tree != nullptr; tree = tree->gtNext)
11412 {
11413 gtDispTree(tree, indentStack);
11414 printf("\n");
11415 }
11416}
11417
11418//------------------------------------------------------------------------
11419// Compiler::gtDispRange: dumps a range of LIR.
11420//
11421// Arguments:
11422// range - the range of LIR to display.
11423//
11424void Compiler::gtDispRange(LIR::ReadOnlyRange const& range)
11425{
11426 for (GenTree* node : range)
11427 {
11428 gtDispLIRNode(node);
11429 }
11430}
11431
11432//------------------------------------------------------------------------
11433// Compiler::gtDispTreeRange: dumps the LIR range that contains all of the
11434// nodes in the dataflow tree rooted at a given
11435// node.
11436//
11437// Arguments:
11438// containingRange - the LIR range that contains the root node.
11439// tree - the root of the dataflow tree.
11440//
11441void Compiler::gtDispTreeRange(LIR::Range& containingRange, GenTree* tree)
11442{
11443 bool unused;
11444 gtDispRange(containingRange.GetTreeRange(tree, &unused));
11445}
11446
11447//------------------------------------------------------------------------
11448// Compiler::gtDispLIRNode: dumps a single LIR node.
11449//
11450// Arguments:
11451// node - the LIR node to dump.
11452// prefixMsg - an optional prefix for each line of output.
11453//
11454void Compiler::gtDispLIRNode(GenTree* node, const char* prefixMsg /* = nullptr */)
11455{
11456 auto displayOperand = [](GenTree* operand, const char* message, IndentInfo operandArc, IndentStack& indentStack,
11457 size_t prefixIndent) {
11458 assert(operand != nullptr);
11459 assert(message != nullptr);
11460
11461 if (prefixIndent != 0)
11462 {
11463 printf("%*s", (int)prefixIndent, "");
11464 }
11465
11466 // 49 spaces for alignment
11467 printf("%-49s", "");
11468#if FEATURE_SET_FLAGS
11469 // additional flag enlarges the flag field by one character
11470 printf(" ");
11471#endif
11472
11473 indentStack.Push(operandArc);
11474 indentStack.print();
11475 indentStack.Pop();
11476 operandArc = IIArc;
11477
11478 printf(" t%-5d %-6s %s\n", operand->gtTreeID, varTypeName(operand->TypeGet()), message);
11479 };
11480
11481 IndentStack indentStack(this);
11482
11483 size_t prefixIndent = 0;
11484 if (prefixMsg != nullptr)
11485 {
11486 prefixIndent = strlen(prefixMsg);
11487 }
11488
11489 const int bufLength = 256;
11490 char buf[bufLength];
11491
11492 const bool nodeIsCall = node->IsCall();
11493
11494 // Visit operands
11495 IndentInfo operandArc = IIArcTop;
11496 for (GenTree* operand : node->Operands())
11497 {
11498 if (operand->IsArgPlaceHolderNode() || !operand->IsValue())
11499 {
11500 // Either of these situations may happen with calls.
11501 continue;
11502 }
11503
11504 if (nodeIsCall)
11505 {
11506 GenTreeCall* call = node->AsCall();
11507 if (operand == call->gtCallObjp)
11508 {
11509 sprintf_s(buf, sizeof(buf), "this in %s", compRegVarName(REG_ARG_0));
11510 displayOperand(operand, buf, operandArc, indentStack, prefixIndent);
11511 }
11512 else if (operand == call->gtCallAddr)
11513 {
11514 displayOperand(operand, "calli tgt", operandArc, indentStack, prefixIndent);
11515 }
11516 else if (operand == call->gtControlExpr)
11517 {
11518 displayOperand(operand, "control expr", operandArc, indentStack, prefixIndent);
11519 }
11520 else if (operand == call->gtCallCookie)
11521 {
11522 displayOperand(operand, "cookie", operandArc, indentStack, prefixIndent);
11523 }
11524 else
11525 {
11526 fgArgTabEntry* curArgTabEntry = gtArgEntryByNode(call, operand);
11527 assert(curArgTabEntry);
11528
11529 if (operand->OperGet() == GT_LIST)
11530 {
11531 int listIndex = 0;
11532 for (GenTreeArgList* element = operand->AsArgList(); element != nullptr; element = element->Rest())
11533 {
11534 operand = element->Current();
11535 if (curArgTabEntry->lateArgInx == (unsigned)-1)
11536 {
11537 gtGetArgMsg(call, operand, curArgTabEntry->argNum, listIndex, buf, sizeof(buf));
11538 }
11539 else
11540 {
11541 gtGetLateArgMsg(call, operand, curArgTabEntry->lateArgInx, listIndex, buf, sizeof(buf));
11542 }
11543
11544 displayOperand(operand, buf, operandArc, indentStack, prefixIndent);
11545 operandArc = IIArc;
11546 }
11547 }
11548 else
11549 {
11550 if (!curArgTabEntry->isLateArg())
11551 {
11552 gtGetArgMsg(call, operand, curArgTabEntry->argNum, -1, buf, sizeof(buf));
11553 }
11554 else
11555 {
11556 gtGetLateArgMsg(call, operand, curArgTabEntry->lateArgInx, -1, buf, sizeof(buf));
11557 }
11558
11559 displayOperand(operand, buf, operandArc, indentStack, prefixIndent);
11560 }
11561 }
11562 }
11563 else if (node->OperIsDynBlkOp())
11564 {
11565 if (operand == node->AsBlk()->Addr())
11566 {
11567 displayOperand(operand, "lhs", operandArc, indentStack, prefixIndent);
11568 }
11569 else if (operand == node->AsBlk()->Data())
11570 {
11571 displayOperand(operand, "rhs", operandArc, indentStack, prefixIndent);
11572 }
11573 else
11574 {
11575 assert(operand == node->AsDynBlk()->gtDynamicSize);
11576 displayOperand(operand, "size", operandArc, indentStack, prefixIndent);
11577 }
11578 }
11579 else if (node->OperGet() == GT_DYN_BLK)
11580 {
11581 if (operand == node->AsBlk()->Addr())
11582 {
11583 displayOperand(operand, "lhs", operandArc, indentStack, prefixIndent);
11584 }
11585 else
11586 {
11587 assert(operand == node->AsDynBlk()->gtDynamicSize);
11588 displayOperand(operand, "size", operandArc, indentStack, prefixIndent);
11589 }
11590 }
11591 else if (node->OperIs(GT_ASG))
11592 {
11593 if (operand == node->gtGetOp1())
11594 {
11595 displayOperand(operand, "lhs", operandArc, indentStack, prefixIndent);
11596 }
11597 else
11598 {
11599 displayOperand(operand, "rhs", operandArc, indentStack, prefixIndent);
11600 }
11601 }
11602 else
11603 {
11604 displayOperand(operand, "", operandArc, indentStack, prefixIndent);
11605 }
11606
11607 operandArc = IIArc;
11608 }
11609
11610 // Visit the operator
11611
11612 if (prefixMsg != nullptr)
11613 {
11614 printf("%s", prefixMsg);
11615 }
11616
11617 const bool topOnly = true;
11618 const bool isLIR = true;
11619 gtDispTree(node, &indentStack, nullptr, topOnly, isLIR);
11620}
11621
11622/*****************************************************************************/
11623#endif // DEBUG
11624
11625/*****************************************************************************
11626 *
11627 * Check if the given node can be folded,
11628 * and call the methods to perform the folding
11629 */
11630
11631GenTree* Compiler::gtFoldExpr(GenTree* tree)
11632{
11633 unsigned kind = tree->OperKind();
11634
11635 /* We must have a simple operation to fold */
11636
11637 // If we're in CSE, it's not safe to perform tree
11638 // folding given that it can will potentially
11639 // change considered CSE candidates.
11640 if (optValnumCSE_phase)
11641 {
11642 return tree;
11643 }
11644
11645 if (!(kind & GTK_SMPOP))
11646 {
11647 return tree;
11648 }
11649
11650 GenTree* op1 = tree->gtOp.gtOp1;
11651
11652 /* Filter out non-foldable trees that can have constant children */
11653
11654 assert(kind & (GTK_UNOP | GTK_BINOP));
11655 switch (tree->gtOper)
11656 {
11657 case GT_RETFILT:
11658 case GT_RETURN:
11659 case GT_IND:
11660 return tree;
11661 default:
11662 break;
11663 }
11664
11665 /* try to fold the current node */
11666
11667 if ((kind & GTK_UNOP) && op1)
11668 {
11669 if (op1->OperKind() & GTK_CONST)
11670 {
11671 return gtFoldExprConst(tree);
11672 }
11673 }
11674 else if ((kind & GTK_BINOP) && op1 && tree->gtOp.gtOp2 &&
11675 // Don't take out conditionals for debugging
11676 (opts.OptimizationEnabled() || !tree->OperIsCompare()))
11677 {
11678 GenTree* op2 = tree->gtOp.gtOp2;
11679
11680 // The atomic operations are exempted here because they are never computable statically;
11681 // one of their arguments is an address.
11682 if (((op1->OperKind() & op2->OperKind()) & GTK_CONST) && !tree->OperIsAtomicOp())
11683 {
11684 /* both nodes are constants - fold the expression */
11685 return gtFoldExprConst(tree);
11686 }
11687 else if ((op1->OperKind() | op2->OperKind()) & GTK_CONST)
11688 {
11689 /* at least one is a constant - see if we have a
11690 * special operator that can use only one constant
11691 * to fold - e.g. booleans */
11692
11693 return gtFoldExprSpecial(tree);
11694 }
11695 else if (tree->OperIsCompare())
11696 {
11697 /* comparisons of two local variables can sometimes be folded */
11698
11699 return gtFoldExprCompare(tree);
11700 }
11701 else if (op2->OperGet() == GT_COLON)
11702 {
11703 assert(tree->OperGet() == GT_QMARK);
11704
11705 GenTree* colon_op1 = op2->gtOp.gtOp1;
11706 GenTree* colon_op2 = op2->gtOp.gtOp2;
11707
11708 if (gtCompareTree(colon_op1, colon_op2))
11709 {
11710 // Both sides of the GT_COLON are the same tree
11711
11712 GenTree* sideEffList = nullptr;
11713 gtExtractSideEffList(op1, &sideEffList);
11714
11715 // Clear colon flags only if the qmark itself is not conditionaly executed
11716 if ((tree->gtFlags & GTF_COLON_COND) == 0)
11717 {
11718 fgWalkTreePre(&colon_op2, gtClearColonCond);
11719 }
11720
11721 if (sideEffList == nullptr)
11722 {
11723 // No side-effects, just return colon_op2
11724 return colon_op2;
11725 }
11726 else
11727 {
11728#ifdef DEBUG
11729 if (verbose)
11730 {
11731 printf("\nIdentical GT_COLON trees with side effects! Extracting side effects...\n");
11732 gtDispTree(sideEffList);
11733 printf("\n");
11734 }
11735#endif
11736 // Change the GT_COLON into a GT_COMMA node with the side-effects
11737 op2->ChangeOper(GT_COMMA);
11738 op2->gtFlags |= (sideEffList->gtFlags & GTF_ALL_EFFECT);
11739 op2->gtOp.gtOp1 = sideEffList;
11740 return op2;
11741 }
11742 }
11743 }
11744 }
11745
11746 /* Return the original node (folded/bashed or not) */
11747
11748 return tree;
11749}
11750
11751//------------------------------------------------------------------------
11752// gtFoldExprCall: see if a call is foldable
11753//
11754// Arguments:
11755// call - call to examine
11756//
11757// Returns:
11758// The original call if no folding happened.
11759// An alternative tree if folding happens.
11760//
11761// Notes:
11762// Checks for calls to Type.op_Equality, Type.op_Inequality, and
11763// Enum.HasFlag, and if the call is to one of these,
11764// attempts to optimize.
11765
11766GenTree* Compiler::gtFoldExprCall(GenTreeCall* call)
11767{
11768 // Can only fold calls to special intrinsics.
11769 if ((call->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) == 0)
11770 {
11771 return call;
11772 }
11773
11774 // Defer folding if not optimizing.
11775 if (opts.OptimizationDisabled())
11776 {
11777 return call;
11778 }
11779
11780 // Fetch id of the intrinsic.
11781 const CorInfoIntrinsics methodID = info.compCompHnd->getIntrinsicID(call->gtCallMethHnd);
11782
11783 switch (methodID)
11784 {
11785 case CORINFO_INTRINSIC_TypeEQ:
11786 case CORINFO_INTRINSIC_TypeNEQ:
11787 {
11788 noway_assert(call->TypeGet() == TYP_INT);
11789 GenTree* op1 = call->gtCallArgs->gtOp.gtOp1;
11790 GenTree* op2 = call->gtCallArgs->gtOp.gtOp2->gtOp.gtOp1;
11791
11792 // If either operand is known to be a RuntimeType, this can be folded
11793 GenTree* result = gtFoldTypeEqualityCall(methodID, op1, op2);
11794 if (result != nullptr)
11795 {
11796 return result;
11797 }
11798 break;
11799 }
11800
11801 default:
11802 break;
11803 }
11804
11805 // Check for a new-style jit intrinsic.
11806 const NamedIntrinsic ni = lookupNamedIntrinsic(call->gtCallMethHnd);
11807
11808 if (ni == NI_System_Enum_HasFlag)
11809 {
11810 GenTree* thisOp = call->gtCallObjp;
11811 GenTree* flagOp = call->gtCallArgs->gtOp.gtOp1;
11812 GenTree* result = gtOptimizeEnumHasFlag(thisOp, flagOp);
11813
11814 if (result != nullptr)
11815 {
11816 return result;
11817 }
11818 }
11819
11820 return call;
11821}
11822
11823//------------------------------------------------------------------------
11824// gtFoldTypeEqualityCall: see if a (potential) type equality call is foldable
11825//
11826// Arguments:
11827// methodID -- type equality intrinsic ID
11828// op1 -- first argument to call
11829// op2 -- second argument to call
11830//
11831// Returns:
11832// nulltpr if no folding happened.
11833// An alternative tree if folding happens.
11834//
11835// Notes:
11836// If either operand is known to be a a RuntimeType, then the type
11837// equality methods will simply check object identity and so we can
11838// fold the call into a simple compare of the call's operands.
11839
11840GenTree* Compiler::gtFoldTypeEqualityCall(CorInfoIntrinsics methodID, GenTree* op1, GenTree* op2)
11841{
11842 // The method must be be a type equality intrinsic
11843 assert(methodID == CORINFO_INTRINSIC_TypeEQ || methodID == CORINFO_INTRINSIC_TypeNEQ);
11844
11845 if ((gtGetTypeProducerKind(op1) == TPK_Unknown) && (gtGetTypeProducerKind(op2) == TPK_Unknown))
11846 {
11847 return nullptr;
11848 }
11849
11850 const genTreeOps simpleOp = (methodID == CORINFO_INTRINSIC_TypeEQ) ? GT_EQ : GT_NE;
11851
11852 JITDUMP("\nFolding call to Type:op_%s to a simple compare via %s\n",
11853 methodID == CORINFO_INTRINSIC_TypeEQ ? "Equality" : "Inequality", GenTree::OpName(simpleOp));
11854
11855 GenTree* compare = gtNewOperNode(simpleOp, TYP_INT, op1, op2);
11856
11857 return compare;
11858}
11859
11860/*****************************************************************************
11861 *
11862 * Some comparisons can be folded:
11863 *
11864 * locA == locA
11865 * classVarA == classVarA
11866 * locA + locB == locB + locA
11867 *
11868 */
11869
11870GenTree* Compiler::gtFoldExprCompare(GenTree* tree)
11871{
11872 GenTree* op1 = tree->gtOp.gtOp1;
11873 GenTree* op2 = tree->gtOp.gtOp2;
11874
11875 assert(tree->OperIsCompare());
11876
11877 /* Filter out cases that cannot be folded here */
11878
11879 /* Do not fold floats or doubles (e.g. NaN != Nan) */
11880
11881 if (varTypeIsFloating(op1->TypeGet()))
11882 {
11883 return tree;
11884 }
11885
11886 /* Currently we can only fold when the two subtrees exactly match */
11887
11888 if ((tree->gtFlags & GTF_SIDE_EFFECT) || GenTree::Compare(op1, op2, true) == false)
11889 {
11890 return tree; /* return unfolded tree */
11891 }
11892
11893 GenTree* cons;
11894
11895 switch (tree->gtOper)
11896 {
11897 case GT_EQ:
11898 case GT_LE:
11899 case GT_GE:
11900 cons = gtNewIconNode(true); /* Folds to GT_CNS_INT(true) */
11901 break;
11902
11903 case GT_NE:
11904 case GT_LT:
11905 case GT_GT:
11906 cons = gtNewIconNode(false); /* Folds to GT_CNS_INT(false) */
11907 break;
11908
11909 default:
11910 assert(!"Unexpected relOp");
11911 return tree;
11912 }
11913
11914 /* The node has beeen folded into 'cons' */
11915
11916 if (fgGlobalMorph)
11917 {
11918 fgMorphTreeDone(cons);
11919 }
11920 else
11921 {
11922 cons->gtNext = tree->gtNext;
11923 cons->gtPrev = tree->gtPrev;
11924 }
11925
11926 return cons;
11927}
11928
11929//------------------------------------------------------------------------
11930// gtCreateHandleCompare: generate a type handle comparison
11931//
11932// Arguments:
11933// oper -- comparison operation (equal/not equal)
11934// op1 -- first operand
11935// op2 -- second operand
11936// typeCheckInliningResult -- indicates how the comparison should happen
11937//
11938// Returns:
11939// Type comparison tree
11940//
11941
11942GenTree* Compiler::gtCreateHandleCompare(genTreeOps oper,
11943 GenTree* op1,
11944 GenTree* op2,
11945 CorInfoInlineTypeCheck typeCheckInliningResult)
11946{
11947 // If we can compare pointers directly, just emit the binary operation
11948 if (typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_PASS)
11949 {
11950 return gtNewOperNode(oper, TYP_INT, op1, op2);
11951 }
11952
11953 assert(typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_USE_HELPER);
11954
11955 // Emit a call to a runtime helper
11956 GenTreeArgList* helperArgs = gtNewArgList(op1, op2);
11957 GenTree* ret = gtNewHelperCallNode(CORINFO_HELP_ARE_TYPES_EQUIVALENT, TYP_INT, helperArgs);
11958 if (oper == GT_EQ)
11959 {
11960 ret = gtNewOperNode(GT_NE, TYP_INT, ret, gtNewIconNode(0, TYP_INT));
11961 }
11962 else
11963 {
11964 assert(oper == GT_NE);
11965 ret = gtNewOperNode(GT_EQ, TYP_INT, ret, gtNewIconNode(0, TYP_INT));
11966 }
11967
11968 return ret;
11969}
11970
11971//------------------------------------------------------------------------
11972// gtFoldTypeCompare: see if a type comparison can be further simplified
11973//
11974// Arguments:
11975// tree -- tree possibly comparing types
11976//
11977// Returns:
11978// An alternative tree if folding happens.
11979// Original tree otherwise.
11980//
11981// Notes:
11982// Checks for
11983// typeof(...) == obj.GetType()
11984// typeof(...) == typeof(...)
11985//
11986// And potentially optimizes away the need to obtain actual
11987// RuntimeType objects to do the comparison.
11988
11989GenTree* Compiler::gtFoldTypeCompare(GenTree* tree)
11990{
11991 // Only handle EQ and NE
11992 // (maybe relop vs null someday)
11993 const genTreeOps oper = tree->OperGet();
11994 if ((oper != GT_EQ) && (oper != GT_NE))
11995 {
11996 return tree;
11997 }
11998
11999 // Screen for the right kinds of operands
12000 GenTree* const op1 = tree->gtOp.gtOp1;
12001 const TypeProducerKind op1Kind = gtGetTypeProducerKind(op1);
12002 if (op1Kind == TPK_Unknown)
12003 {
12004 return tree;
12005 }
12006
12007 GenTree* const op2 = tree->gtOp.gtOp2;
12008 const TypeProducerKind op2Kind = gtGetTypeProducerKind(op2);
12009 if (op2Kind == TPK_Unknown)
12010 {
12011 return tree;
12012 }
12013
12014 // We must have a handle on one side or the other here to optimize,
12015 // otherwise we can't be sure that optimizing is sound.
12016 const bool op1IsFromHandle = (op1Kind == TPK_Handle);
12017 const bool op2IsFromHandle = (op2Kind == TPK_Handle);
12018
12019 if (!(op1IsFromHandle || op2IsFromHandle))
12020 {
12021 return tree;
12022 }
12023
12024 // If both types are created via handles, we can simply compare
12025 // handles (or the indirection cells for handles) instead of the
12026 // types that they'd create.
12027 if (op1IsFromHandle && op2IsFromHandle)
12028 {
12029 JITDUMP("Optimizing compare of types-from-handles to instead compare handles\n");
12030 GenTree* op1ClassFromHandle = tree->gtOp.gtOp1->gtCall.gtCallArgs->gtOp.gtOp1;
12031 GenTree* op2ClassFromHandle = tree->gtOp.gtOp2->gtCall.gtCallArgs->gtOp.gtOp1;
12032 GenTree* op1TunneledHandle = nullptr;
12033 GenTree* op2TunneledHandle = nullptr;
12034 CORINFO_CLASS_HANDLE cls1Hnd = NO_CLASS_HANDLE;
12035 CORINFO_CLASS_HANDLE cls2Hnd = NO_CLASS_HANDLE;
12036 unsigned runtimeLookupCount = 0;
12037
12038 // Try and find class handles from op1 and op2
12039 cls1Hnd = gtGetHelperArgClassHandle(op1ClassFromHandle, &runtimeLookupCount, &op1TunneledHandle);
12040 cls2Hnd = gtGetHelperArgClassHandle(op2ClassFromHandle, &runtimeLookupCount, &op2TunneledHandle);
12041
12042 // If we have both class handles, try and resolve the type equality test completely.
12043 bool resolveFailed = false;
12044
12045 if ((cls1Hnd != NO_CLASS_HANDLE) && (cls2Hnd != NO_CLASS_HANDLE))
12046 {
12047 JITDUMP("Asking runtime to compare %p (%s) and %p (%s) for equality\n", dspPtr(cls1Hnd),
12048 info.compCompHnd->getClassName(cls1Hnd), dspPtr(cls2Hnd), info.compCompHnd->getClassName(cls2Hnd));
12049 TypeCompareState s = info.compCompHnd->compareTypesForEquality(cls1Hnd, cls2Hnd);
12050
12051 if (s != TypeCompareState::May)
12052 {
12053 // Type comparison result is known.
12054 const bool typesAreEqual = (s == TypeCompareState::Must);
12055 const bool operatorIsEQ = (oper == GT_EQ);
12056 const int compareResult = operatorIsEQ ^ typesAreEqual ? 0 : 1;
12057 JITDUMP("Runtime reports comparison is known at jit time: %u\n", compareResult);
12058 GenTree* result = gtNewIconNode(compareResult);
12059
12060 // Any runtime lookups that fed into this compare are
12061 // now dead code, so they no longer require the runtime context.
12062 assert(lvaGenericsContextUseCount >= runtimeLookupCount);
12063 lvaGenericsContextUseCount -= runtimeLookupCount;
12064 return result;
12065 }
12066 else
12067 {
12068 resolveFailed = true;
12069 }
12070 }
12071
12072 if (resolveFailed)
12073 {
12074 JITDUMP("Runtime reports comparison is NOT known at jit time\n");
12075 }
12076 else
12077 {
12078 JITDUMP("Could not find handle for %s%s\n", (cls1Hnd == NO_CLASS_HANDLE) ? " cls1" : "",
12079 (cls2Hnd == NO_CLASS_HANDLE) ? " cls2" : "");
12080 }
12081
12082 // We can't answer the equality comparison definitively at jit
12083 // time, but can still simplfy the comparison.
12084 //
12085 // Find out how we can compare the two handles.
12086 // NOTE: We're potentially passing NO_CLASS_HANDLE, but the runtime knows what to do with it here.
12087 CorInfoInlineTypeCheck inliningKind =
12088 info.compCompHnd->canInlineTypeCheck(cls1Hnd, CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN);
12089
12090 // If the first type needs helper, check the other type: it might be okay with a simple compare.
12091 if (inliningKind == CORINFO_INLINE_TYPECHECK_USE_HELPER)
12092 {
12093 inliningKind = info.compCompHnd->canInlineTypeCheck(cls2Hnd, CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN);
12094 }
12095
12096 assert(inliningKind == CORINFO_INLINE_TYPECHECK_PASS || inliningKind == CORINFO_INLINE_TYPECHECK_USE_HELPER);
12097
12098 // If we successfully tunneled through both operands, compare
12099 // the tunneled values, otherwise compare the original values.
12100 GenTree* compare;
12101 if ((op1TunneledHandle != nullptr) && (op2TunneledHandle != nullptr))
12102 {
12103 compare = gtCreateHandleCompare(oper, op1TunneledHandle, op2TunneledHandle, inliningKind);
12104 }
12105 else
12106 {
12107 compare = gtCreateHandleCompare(oper, op1ClassFromHandle, op2ClassFromHandle, inliningKind);
12108 }
12109
12110 // Drop any now-irrelvant flags
12111 compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
12112
12113 return compare;
12114 }
12115
12116 // Just one operand creates a type from a handle.
12117 //
12118 // If the other operand is fetching the type from an object,
12119 // we can sometimes optimize the type compare into a simpler
12120 // method table comparison.
12121 //
12122 // TODO: if other operand is null...
12123 if ((op1Kind != TPK_GetType) && (op2Kind != TPK_GetType))
12124 {
12125 return tree;
12126 }
12127
12128 GenTree* const opHandle = op1IsFromHandle ? op1 : op2;
12129 GenTree* const opOther = op1IsFromHandle ? op2 : op1;
12130
12131 // Tunnel through the handle operand to get at the class handle involved.
12132 GenTree* const opHandleArgument = opHandle->gtCall.gtCallArgs->gtOp.gtOp1;
12133 CORINFO_CLASS_HANDLE clsHnd = gtGetHelperArgClassHandle(opHandleArgument);
12134
12135 // If we couldn't find the class handle, give up.
12136 if (clsHnd == NO_CLASS_HANDLE)
12137 {
12138 return tree;
12139 }
12140
12141 // Ask the VM if this type can be equality tested by a simple method
12142 // table comparison.
12143 CorInfoInlineTypeCheck typeCheckInliningResult =
12144 info.compCompHnd->canInlineTypeCheck(clsHnd, CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE);
12145 if (typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_NONE)
12146 {
12147 return tree;
12148 }
12149
12150 // We're good to go.
12151 JITDUMP("Optimizing compare of obj.GetType()"
12152 " and type-from-handle to compare method table pointer\n");
12153
12154 // opHandleArgument is the method table we're looking for.
12155 GenTree* const knownMT = opHandleArgument;
12156
12157 // Fetch object method table from the object itself.
12158 GenTree* objOp = nullptr;
12159
12160 // Note we may see intrinsified or regular calls to GetType
12161 if (opOther->OperGet() == GT_INTRINSIC)
12162 {
12163 objOp = opOther->gtUnOp.gtOp1;
12164 }
12165 else
12166 {
12167 assert(opOther->OperGet() == GT_CALL);
12168 objOp = opOther->gtCall.gtCallObjp;
12169 }
12170
12171 GenTree* const objMT = gtNewOperNode(GT_IND, TYP_I_IMPL, objOp);
12172
12173 // Update various flags
12174 objMT->gtFlags |= GTF_EXCEPT;
12175 compCurBB->bbFlags |= BBF_HAS_VTABREF;
12176 optMethodFlags |= OMF_HAS_VTABLEREF;
12177
12178 // Compare the two method tables
12179 GenTree* const compare = gtCreateHandleCompare(oper, objMT, knownMT, typeCheckInliningResult);
12180
12181 // Drop any now irrelevant flags
12182 compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
12183
12184 // And we're done
12185 return compare;
12186}
12187
12188//------------------------------------------------------------------------
12189// gtGetHelperArgClassHandle: find the compile time class handle from
12190// a helper call argument tree
12191//
12192// Arguments:
12193// tree - tree that passes the handle to the helper
12194// runtimeLookupCount [optional, in/out] - incremented if tree was a runtime lookup
12195// handleTree [optional, out] - set to the literal operand tree for indirect handles
12196//
12197// Returns:
12198// The compile time class handle if known.
12199//
12200CORINFO_CLASS_HANDLE Compiler::gtGetHelperArgClassHandle(GenTree* tree,
12201 unsigned* runtimeLookupCount,
12202 GenTree** handleTree)
12203{
12204 CORINFO_CLASS_HANDLE result = NO_CLASS_HANDLE;
12205
12206 // Walk through any wrapping nop.
12207 if ((tree->gtOper == GT_NOP) && (tree->gtType == TYP_I_IMPL))
12208 {
12209 tree = tree->gtOp.gtOp1;
12210 }
12211
12212 // The handle could be a literal constant
12213 if ((tree->OperGet() == GT_CNS_INT) && (tree->TypeGet() == TYP_I_IMPL))
12214 {
12215 assert(tree->IsIconHandle(GTF_ICON_CLASS_HDL));
12216 result = (CORINFO_CLASS_HANDLE)tree->gtIntCon.gtCompileTimeHandle;
12217 }
12218 // Or the result of a runtime lookup
12219 else if (tree->OperGet() == GT_RUNTIMELOOKUP)
12220 {
12221 result = tree->AsRuntimeLookup()->GetClassHandle();
12222
12223 if (runtimeLookupCount != nullptr)
12224 {
12225 *runtimeLookupCount = *runtimeLookupCount + 1;
12226 }
12227 }
12228 // Or something reached indirectly
12229 else if (tree->gtOper == GT_IND)
12230 {
12231 // The handle indirs we are looking for will be marked as non-faulting.
12232 // Certain others (eg from refanytype) may not be.
12233 if (tree->gtFlags & GTF_IND_NONFAULTING)
12234 {
12235 GenTree* handleTreeInternal = tree->gtOp.gtOp1;
12236
12237 if ((handleTreeInternal->OperGet() == GT_CNS_INT) && (handleTreeInternal->TypeGet() == TYP_I_IMPL))
12238 {
12239 // These handle constants should be class handles.
12240 assert(handleTreeInternal->IsIconHandle(GTF_ICON_CLASS_HDL));
12241 result = (CORINFO_CLASS_HANDLE)handleTreeInternal->gtIntCon.gtCompileTimeHandle;
12242
12243 if (handleTree != nullptr)
12244 {
12245 *handleTree = handleTreeInternal;
12246 }
12247 }
12248 }
12249 }
12250
12251 return result;
12252}
12253
12254/*****************************************************************************
12255 *
12256 * Some binary operators can be folded even if they have only one
12257 * operand constant - e.g. boolean operators, add with 0
12258 * multiply with 1, etc
12259 */
12260
12261GenTree* Compiler::gtFoldExprSpecial(GenTree* tree)
12262{
12263 GenTree* op1 = tree->gtOp.gtOp1;
12264 GenTree* op2 = tree->gtOp.gtOp2;
12265 genTreeOps oper = tree->OperGet();
12266
12267 GenTree* op;
12268 GenTree* cons;
12269 ssize_t val;
12270
12271 assert(tree->OperKind() & GTK_BINOP);
12272
12273 /* Filter out operators that cannot be folded here */
12274 if (oper == GT_CAST)
12275 {
12276 return tree;
12277 }
12278
12279 /* We only consider TYP_INT for folding
12280 * Do not fold pointer arithmetic (e.g. addressing modes!) */
12281
12282 if (oper != GT_QMARK && !varTypeIsIntOrI(tree->gtType))
12283 {
12284 return tree;
12285 }
12286
12287 /* Find out which is the constant node */
12288
12289 if (op1->IsCnsIntOrI())
12290 {
12291 op = op2;
12292 cons = op1;
12293 }
12294 else if (op2->IsCnsIntOrI())
12295 {
12296 op = op1;
12297 cons = op2;
12298 }
12299 else
12300 {
12301 return tree;
12302 }
12303
12304 /* Get the constant value */
12305
12306 val = cons->gtIntConCommon.IconValue();
12307
12308 /* Here op is the non-constant operand, val is the constant,
12309 first is true if the constant is op1 */
12310
12311 switch (oper)
12312 {
12313 case GT_EQ:
12314 case GT_NE:
12315 case GT_GT:
12316
12317 // Optimize boxed value classes; these are always false. This IL is
12318 // generated when a generic value is tested against null:
12319 // <T> ... foo(T x) { ... if ((object)x == null) ...
12320 if (val == 0 && op->IsBoxedValue())
12321 {
12322 JITDUMP("\nAttempting to optimize BOX(valueType) %s null [%06u]\n", GenTree::OpName(oper),
12323 dspTreeID(tree));
12324
12325 // We don't expect GT_GT with signed compares, and we
12326 // can't predict the result if we do see it, since the
12327 // boxed object addr could have its high bit set.
12328 if ((oper == GT_GT) && !tree->IsUnsigned())
12329 {
12330 JITDUMP(" bailing; unexpected signed compare via GT_GT\n");
12331 }
12332 else
12333 {
12334 // The tree under the box must be side effect free
12335 // since we will drop it if we optimize.
12336 assert(!gtTreeHasSideEffects(op->gtBox.gtOp.gtOp1, GTF_SIDE_EFFECT));
12337
12338 // See if we can optimize away the box and related statements.
12339 GenTree* boxSourceTree = gtTryRemoveBoxUpstreamEffects(op);
12340 bool didOptimize = (boxSourceTree != nullptr);
12341
12342 // If optimization succeeded, remove the box.
12343 if (didOptimize)
12344 {
12345 // Set up the result of the compare.
12346 int compareResult = 0;
12347 if (oper == GT_GT)
12348 {
12349 // GT_GT(null, box) == false
12350 // GT_GT(box, null) == true
12351 compareResult = (op1 == op);
12352 }
12353 else if (oper == GT_EQ)
12354 {
12355 // GT_EQ(box, null) == false
12356 // GT_EQ(null, box) == false
12357 compareResult = 0;
12358 }
12359 else
12360 {
12361 assert(oper == GT_NE);
12362 // GT_NE(box, null) == true
12363 // GT_NE(null, box) == true
12364 compareResult = 1;
12365 }
12366
12367 JITDUMP("\nSuccess: replacing BOX(valueType) %s null with %d\n", GenTree::OpName(oper),
12368 compareResult);
12369
12370 op = gtNewIconNode(compareResult);
12371
12372 if (fgGlobalMorph)
12373 {
12374 fgMorphTreeDone(op);
12375 }
12376 else
12377 {
12378 op->gtNext = tree->gtNext;
12379 op->gtPrev = tree->gtPrev;
12380 }
12381
12382 return op;
12383 }
12384 }
12385 }
12386
12387 break;
12388
12389 case GT_ADD:
12390 if (val == 0)
12391 {
12392 goto DONE_FOLD;
12393 }
12394 break;
12395
12396 case GT_MUL:
12397 if (val == 1)
12398 {
12399 goto DONE_FOLD;
12400 }
12401 else if (val == 0)
12402 {
12403 /* Multiply by zero - return the 'zero' node, but not if side effects */
12404 if (!(op->gtFlags & GTF_SIDE_EFFECT))
12405 {
12406 op = cons;
12407 goto DONE_FOLD;
12408 }
12409 }
12410 break;
12411
12412 case GT_DIV:
12413 case GT_UDIV:
12414 if ((op2 == cons) && (val == 1) && !(op1->OperKind() & GTK_CONST))
12415 {
12416 goto DONE_FOLD;
12417 }
12418 break;
12419
12420 case GT_SUB:
12421 if ((op2 == cons) && (val == 0) && !(op1->OperKind() & GTK_CONST))
12422 {
12423 goto DONE_FOLD;
12424 }
12425 break;
12426
12427 case GT_AND:
12428 if (val == 0)
12429 {
12430 /* AND with zero - return the 'zero' node, but not if side effects */
12431
12432 if (!(op->gtFlags & GTF_SIDE_EFFECT))
12433 {
12434 op = cons;
12435 goto DONE_FOLD;
12436 }
12437 }
12438 else
12439 {
12440 /* The GTF_BOOLEAN flag is set for nodes that are part
12441 * of a boolean expression, thus all their children
12442 * are known to evaluate to only 0 or 1 */
12443
12444 if (tree->gtFlags & GTF_BOOLEAN)
12445 {
12446
12447 /* The constant value must be 1
12448 * AND with 1 stays the same */
12449 assert(val == 1);
12450 goto DONE_FOLD;
12451 }
12452 }
12453 break;
12454
12455 case GT_OR:
12456 if (val == 0)
12457 {
12458 goto DONE_FOLD;
12459 }
12460 else if (tree->gtFlags & GTF_BOOLEAN)
12461 {
12462 /* The constant value must be 1 - OR with 1 is 1 */
12463
12464 assert(val == 1);
12465
12466 /* OR with one - return the 'one' node, but not if side effects */
12467
12468 if (!(op->gtFlags & GTF_SIDE_EFFECT))
12469 {
12470 op = cons;
12471 goto DONE_FOLD;
12472 }
12473 }
12474 break;
12475
12476 case GT_LSH:
12477 case GT_RSH:
12478 case GT_RSZ:
12479 case GT_ROL:
12480 case GT_ROR:
12481 if (val == 0)
12482 {
12483 if (op2 == cons)
12484 {
12485 goto DONE_FOLD;
12486 }
12487 else if (!(op->gtFlags & GTF_SIDE_EFFECT))
12488 {
12489 op = cons;
12490 goto DONE_FOLD;
12491 }
12492 }
12493 break;
12494
12495 case GT_QMARK:
12496 {
12497 assert(op1 == cons && op2 == op && op2->gtOper == GT_COLON);
12498 assert(op2->gtOp.gtOp1 && op2->gtOp.gtOp2);
12499
12500 assert(val == 0 || val == 1);
12501
12502 GenTree* opToDelete;
12503 if (val)
12504 {
12505 op = op2->AsColon()->ThenNode();
12506 opToDelete = op2->AsColon()->ElseNode();
12507 }
12508 else
12509 {
12510 op = op2->AsColon()->ElseNode();
12511 opToDelete = op2->AsColon()->ThenNode();
12512 }
12513
12514 // Clear colon flags only if the qmark itself is not conditionaly executed
12515 if ((tree->gtFlags & GTF_COLON_COND) == 0)
12516 {
12517 fgWalkTreePre(&op, gtClearColonCond);
12518 }
12519 }
12520
12521 goto DONE_FOLD;
12522
12523 default:
12524 break;
12525 }
12526
12527 /* The node is not foldable */
12528
12529 return tree;
12530
12531DONE_FOLD:
12532
12533 /* The node has beeen folded into 'op' */
12534
12535 // If there was an assigment update, we just morphed it into
12536 // a use, update the flags appropriately
12537 if (op->gtOper == GT_LCL_VAR)
12538 {
12539 assert(tree->OperIs(GT_ASG) || (op->gtFlags & (GTF_VAR_USEASG | GTF_VAR_DEF)) == 0);
12540
12541 op->gtFlags &= ~(GTF_VAR_USEASG | GTF_VAR_DEF);
12542 }
12543
12544 op->gtNext = tree->gtNext;
12545 op->gtPrev = tree->gtPrev;
12546
12547 return op;
12548}
12549
12550//------------------------------------------------------------------------
12551// gtTryRemoveBoxUpstreamEffects: given an unused value type box,
12552// try and remove the upstream allocation and unnecessary parts of
12553// the copy.
12554//
12555// Arguments:
12556// op - the box node to optimize
12557// options - controls whether and how trees are modified
12558// (see notes)
12559//
12560// Return Value:
12561// A tree representing the original value to box, if removal
12562// is successful/possible (but see note). nullptr if removal fails.
12563//
12564// Notes:
12565// Value typed box gets special treatment because it has associated
12566// side effects that can be removed if the box result is not used.
12567//
12568// By default (options == BR_REMOVE_AND_NARROW) this method will
12569// try and remove unnecessary trees and will try and reduce remaning
12570// operations to the minimal set, possibly narrowing the width of
12571// loads from the box source if it is a struct.
12572//
12573// To perform a trial removal, pass BR_DONT_REMOVE. This can be
12574// useful to determine if this optimization should only be
12575// performed if some other conditions hold true.
12576//
12577// To remove but not alter the access to the box source, pass
12578// BR_REMOVE_BUT_NOT_NARROW.
12579//
12580// To remove and return the tree for the type handle used for
12581// the boxed newobj, pass BR_REMOVE_BUT_NOT_NARROW_WANT_TYPE_HANDLE.
12582// This can be useful when the only part of the box that is "live"
12583// is its type.
12584//
12585// If removal fails, is is possible that a subsequent pass may be
12586// able to optimize. Blocking side effects may now be minimized
12587// (null or bounds checks might have been removed) or might be
12588// better known (inline return placeholder updated with the actual
12589// return expression). So the box is perhaps best left as is to
12590// help trigger this re-examination.
12591
12592GenTree* Compiler::gtTryRemoveBoxUpstreamEffects(GenTree* op, BoxRemovalOptions options)
12593{
12594 assert(op->IsBoxedValue());
12595
12596 // grab related parts for the optimization
12597 GenTreeBox* box = op->AsBox();
12598 GenTree* asgStmt = box->gtAsgStmtWhenInlinedBoxValue;
12599 GenTree* copyStmt = box->gtCopyStmtWhenInlinedBoxValue;
12600
12601 assert(asgStmt->gtOper == GT_STMT);
12602 assert(copyStmt->gtOper == GT_STMT);
12603
12604 JITDUMP("gtTryRemoveBoxUpstreamEffects: %s to %s of BOX (valuetype)"
12605 " [%06u] (assign/newobj [%06u] copy [%06u])\n",
12606 (options == BR_DONT_REMOVE) ? "checking if it is possible" : "attempting",
12607 (options == BR_MAKE_LOCAL_COPY) ? "make local unboxed version" : "remove side effects", dspTreeID(op),
12608 dspTreeID(asgStmt), dspTreeID(copyStmt));
12609
12610 // If we don't recognize the form of the assign, bail.
12611 GenTree* asg = asgStmt->gtStmt.gtStmtExpr;
12612 if (asg->gtOper != GT_ASG)
12613 {
12614 JITDUMP(" bailing; unexpected assignment op %s\n", GenTree::OpName(asg->gtOper));
12615 return nullptr;
12616 }
12617
12618 // If we're eventually going to return the type handle, remember it now.
12619 GenTree* boxTypeHandle = nullptr;
12620 if ((options == BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE) || (options == BR_DONT_REMOVE_WANT_TYPE_HANDLE))
12621 {
12622 GenTree* asgSrc = asg->gtOp.gtOp2;
12623 genTreeOps asgSrcOper = asgSrc->OperGet();
12624
12625 // Allocation may be via AllocObj or via helper call, depending
12626 // on when this is invoked and whether the jit is using AllocObj
12627 // for R2R allocations.
12628 if (asgSrcOper == GT_ALLOCOBJ)
12629 {
12630 GenTreeAllocObj* allocObj = asgSrc->AsAllocObj();
12631 boxTypeHandle = allocObj->gtOp.gtOp1;
12632 }
12633 else if (asgSrcOper == GT_CALL)
12634 {
12635 GenTreeCall* newobjCall = asgSrc->AsCall();
12636 GenTree* newobjArgs = newobjCall->gtCallArgs;
12637
12638 // In R2R expansions the handle may not be an explicit operand to the helper,
12639 // so we can't remove the box.
12640 if (newobjArgs == nullptr)
12641 {
12642 assert(newobjCall->IsHelperCall(this, CORINFO_HELP_READYTORUN_NEW));
12643 JITDUMP(" bailing; newobj via R2R helper\n");
12644 return nullptr;
12645 }
12646
12647 boxTypeHandle = newobjArgs->AsArgList()->Current();
12648 }
12649 else
12650 {
12651 unreached();
12652 }
12653
12654 assert(boxTypeHandle != nullptr);
12655 }
12656
12657 // If we don't recognize the form of the copy, bail.
12658 GenTree* copy = copyStmt->gtStmt.gtStmtExpr;
12659 if (copy->gtOper != GT_ASG)
12660 {
12661 // GT_RET_EXPR is a tolerable temporary failure.
12662 // The jit will revisit this optimization after
12663 // inlining is done.
12664 if (copy->gtOper == GT_RET_EXPR)
12665 {
12666 JITDUMP(" bailing; must wait for replacement of copy %s\n", GenTree::OpName(copy->gtOper));
12667 }
12668 else
12669 {
12670 // Anything else is a missed case we should
12671 // figure out how to handle. One known case
12672 // is GT_COMMAs enclosing the GT_ASG we are
12673 // looking for.
12674 JITDUMP(" bailing; unexpected copy op %s\n", GenTree::OpName(copy->gtOper));
12675 }
12676 return nullptr;
12677 }
12678
12679 // Handle case where we are optimizing the box into a local copy
12680 if (options == BR_MAKE_LOCAL_COPY)
12681 {
12682 // Drill into the box to get at the box temp local and the box type
12683 GenTree* boxTemp = box->BoxOp();
12684 assert(boxTemp->IsLocal());
12685 const unsigned boxTempLcl = boxTemp->AsLclVar()->GetLclNum();
12686 assert(lvaTable[boxTempLcl].lvType == TYP_REF);
12687 CORINFO_CLASS_HANDLE boxClass = lvaTable[boxTempLcl].lvClassHnd;
12688 assert(boxClass != nullptr);
12689
12690 // Verify that the copyDst has the expected shape
12691 // (blk|obj|ind (add (boxTempLcl, ptr-size)))
12692 //
12693 // The shape here is constrained to the patterns we produce
12694 // over in impImportAndPushBox for the inlined box case.
12695 GenTree* copyDst = copy->gtOp.gtOp1;
12696
12697 if (!copyDst->OperIs(GT_BLK, GT_IND, GT_OBJ))
12698 {
12699 JITDUMP("Unexpected copy dest operator %s\n", GenTree::OpName(copyDst->gtOper));
12700 return nullptr;
12701 }
12702
12703 GenTree* copyDstAddr = copyDst->gtOp.gtOp1;
12704 if (copyDstAddr->OperGet() != GT_ADD)
12705 {
12706 JITDUMP("Unexpected copy dest address tree\n");
12707 return nullptr;
12708 }
12709
12710 GenTree* copyDstAddrOp1 = copyDstAddr->gtOp.gtOp1;
12711 if ((copyDstAddrOp1->OperGet() != GT_LCL_VAR) || (copyDstAddrOp1->gtLclVarCommon.gtLclNum != boxTempLcl))
12712 {
12713 JITDUMP("Unexpected copy dest address 1st addend\n");
12714 return nullptr;
12715 }
12716
12717 GenTree* copyDstAddrOp2 = copyDstAddr->gtOp.gtOp2;
12718 if (!copyDstAddrOp2->IsIntegralConst(TARGET_POINTER_SIZE))
12719 {
12720 JITDUMP("Unexpected copy dest address 2nd addend\n");
12721 return nullptr;
12722 }
12723
12724 // Screening checks have all passed. Do the transformation.
12725 //
12726 // Retype the box temp to be a struct
12727 JITDUMP("Retyping box temp V%02u to struct %s\n", boxTempLcl, eeGetClassName(boxClass));
12728 lvaTable[boxTempLcl].lvType = TYP_UNDEF;
12729 const bool isUnsafeValueClass = false;
12730 lvaSetStruct(boxTempLcl, boxClass, isUnsafeValueClass);
12731 var_types boxTempType = lvaTable[boxTempLcl].lvType;
12732
12733 // Remove the newobj and assigment to box temp
12734 JITDUMP("Bashing NEWOBJ [%06u] to NOP\n", dspTreeID(asg));
12735 asg->gtBashToNOP();
12736
12737 // Update the copy from the value to be boxed to the box temp
12738 GenTree* newDst = gtNewOperNode(GT_ADDR, TYP_BYREF, gtNewLclvNode(boxTempLcl, boxTempType));
12739 copyDst->gtOp.gtOp1 = newDst;
12740
12741 // Return the address of the now-struct typed box temp
12742 GenTree* retValue = gtNewOperNode(GT_ADDR, TYP_BYREF, gtNewLclvNode(boxTempLcl, boxTempType));
12743
12744 return retValue;
12745 }
12746
12747 // If the copy is a struct copy, make sure we know how to isolate
12748 // any source side effects.
12749 GenTree* copySrc = copy->gtOp.gtOp2;
12750
12751 // If the copy source is from a pending inline, wait for it to resolve.
12752 if (copySrc->gtOper == GT_RET_EXPR)
12753 {
12754 JITDUMP(" bailing; must wait for replacement of copy source %s\n", GenTree::OpName(copySrc->gtOper));
12755 return nullptr;
12756 }
12757
12758 bool hasSrcSideEffect = false;
12759 bool isStructCopy = false;
12760
12761 if (gtTreeHasSideEffects(copySrc, GTF_SIDE_EFFECT))
12762 {
12763 hasSrcSideEffect = true;
12764
12765 if (varTypeIsStruct(copySrc->gtType))
12766 {
12767 isStructCopy = true;
12768
12769 if ((copySrc->gtOper != GT_OBJ) && (copySrc->gtOper != GT_IND) && (copySrc->gtOper != GT_FIELD))
12770 {
12771 // We don't know how to handle other cases, yet.
12772 JITDUMP(" bailing; unexpected copy source struct op with side effect %s\n",
12773 GenTree::OpName(copySrc->gtOper));
12774 return nullptr;
12775 }
12776 }
12777 }
12778
12779 // If this was a trial removal, we're done.
12780 if (options == BR_DONT_REMOVE)
12781 {
12782 return copySrc;
12783 }
12784
12785 if (options == BR_DONT_REMOVE_WANT_TYPE_HANDLE)
12786 {
12787 return boxTypeHandle;
12788 }
12789
12790 // Otherwise, proceed with the optimization.
12791 //
12792 // Change the assignment expression to a NOP.
12793 JITDUMP("\nBashing NEWOBJ [%06u] to NOP\n", dspTreeID(asg));
12794 asg->gtBashToNOP();
12795
12796 // Change the copy expression so it preserves key
12797 // source side effects.
12798 JITDUMP("\nBashing COPY [%06u]", dspTreeID(copy));
12799
12800 if (!hasSrcSideEffect)
12801 {
12802 // If there were no copy source side effects just bash
12803 // the copy to a NOP.
12804 copy->gtBashToNOP();
12805 JITDUMP(" to NOP; no source side effects.\n");
12806 }
12807 else if (!isStructCopy)
12808 {
12809 // For scalar types, go ahead and produce the
12810 // value as the copy is fairly cheap and likely
12811 // the optimizer can trim things down to just the
12812 // minimal side effect parts.
12813 copyStmt->gtStmt.gtStmtExpr = copySrc;
12814 JITDUMP(" to scalar read via [%06u]\n", dspTreeID(copySrc));
12815 }
12816 else
12817 {
12818 // For struct types read the first byte of the
12819 // source struct; there's no need to read the
12820 // entire thing, and no place to put it.
12821 assert(copySrc->gtOper == GT_OBJ || copySrc->gtOper == GT_IND || copySrc->gtOper == GT_FIELD);
12822 copyStmt->gtStmt.gtStmtExpr = copySrc;
12823
12824 if (options == BR_REMOVE_AND_NARROW || options == BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE)
12825 {
12826 JITDUMP(" to read first byte of struct via modified [%06u]\n", dspTreeID(copySrc));
12827 copySrc->ChangeOper(GT_IND);
12828 copySrc->gtType = TYP_BYTE;
12829 }
12830 else
12831 {
12832 JITDUMP(" to read entire struct via modified [%06u]\n", dspTreeID(copySrc));
12833 }
12834 }
12835
12836 if (fgStmtListThreaded)
12837 {
12838 fgSetStmtSeq(asgStmt);
12839 fgSetStmtSeq(copyStmt);
12840 }
12841
12842 // Box effects were successfully optimized.
12843
12844 if (options == BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE)
12845 {
12846 return boxTypeHandle;
12847 }
12848 else
12849 {
12850 return copySrc;
12851 }
12852}
12853
12854//------------------------------------------------------------------------
12855// gtOptimizeEnumHasFlag: given the operands for a call to Enum.HasFlag,
12856// try and optimize the call to a simple and/compare tree.
12857//
12858// Arguments:
12859// thisOp - first argument to the call
12860// flagOp - second argument to the call
12861//
12862// Return Value:
12863// A new cmp/amd tree if successful. nullptr on failure.
12864//
12865// Notes:
12866// If successful, may allocate new temps and modify connected
12867// statements.
12868
12869GenTree* Compiler::gtOptimizeEnumHasFlag(GenTree* thisOp, GenTree* flagOp)
12870{
12871 JITDUMP("Considering optimizing call to Enum.HasFlag....\n");
12872
12873 // Operands must be boxes
12874 if (!thisOp->IsBoxedValue() || !flagOp->IsBoxedValue())
12875 {
12876 JITDUMP("bailing, need both inputs to be BOXes\n");
12877 return nullptr;
12878 }
12879
12880 // Operands must have same type
12881 bool isExactThis = false;
12882 bool isNonNullThis = false;
12883 CORINFO_CLASS_HANDLE thisHnd = gtGetClassHandle(thisOp, &isExactThis, &isNonNullThis);
12884
12885 if (thisHnd == nullptr)
12886 {
12887 JITDUMP("bailing, can't find type for 'this' operand\n");
12888 return nullptr;
12889 }
12890
12891 // A boxed thisOp should have exact type and non-null instance
12892 assert(isExactThis);
12893 assert(isNonNullThis);
12894
12895 bool isExactFlag = false;
12896 bool isNonNullFlag = false;
12897 CORINFO_CLASS_HANDLE flagHnd = gtGetClassHandle(flagOp, &isExactFlag, &isNonNullFlag);
12898
12899 if (flagHnd == nullptr)
12900 {
12901 JITDUMP("bailing, can't find type for 'flag' operand\n");
12902 return nullptr;
12903 }
12904
12905 // A boxed flagOp should have exact type and non-null instance
12906 assert(isExactFlag);
12907 assert(isNonNullFlag);
12908
12909 if (flagHnd != thisHnd)
12910 {
12911 JITDUMP("bailing, operand types differ\n");
12912 return nullptr;
12913 }
12914
12915 // If we have a shared type instance we can't safely check type
12916 // equality, so bail.
12917 DWORD classAttribs = info.compCompHnd->getClassAttribs(thisHnd);
12918 if (classAttribs & CORINFO_FLG_SHAREDINST)
12919 {
12920 JITDUMP("bailing, have shared instance type\n");
12921 return nullptr;
12922 }
12923
12924 // Simulate removing the box for thisOP. We need to know that it can
12925 // be safely removed before we can optimize.
12926 GenTree* thisVal = gtTryRemoveBoxUpstreamEffects(thisOp, BR_DONT_REMOVE);
12927 if (thisVal == nullptr)
12928 {
12929 // Note we may fail here if the this operand comes from
12930 // a call. We should be able to retry this post-inlining.
12931 JITDUMP("bailing, can't undo box of 'this' operand\n");
12932 return nullptr;
12933 }
12934
12935 GenTree* flagVal = gtTryRemoveBoxUpstreamEffects(flagOp, BR_REMOVE_BUT_NOT_NARROW);
12936 if (flagVal == nullptr)
12937 {
12938 // Note we may fail here if the flag operand comes from
12939 // a call. We should be able to retry this post-inlining.
12940 JITDUMP("bailing, can't undo box of 'flag' operand\n");
12941 return nullptr;
12942 }
12943
12944 // Yes, both boxes can be cleaned up. Optimize.
12945 JITDUMP("Optimizing call to Enum.HasFlag\n");
12946
12947 // Undo the boxing of thisOp and prepare to operate directly
12948 // on the original enum values.
12949 thisVal = gtTryRemoveBoxUpstreamEffects(thisOp, BR_REMOVE_BUT_NOT_NARROW);
12950
12951 // Our trial removal above should guarantee successful removal here.
12952 assert(thisVal != nullptr);
12953
12954 // We should have a consistent view of the type
12955 var_types type = thisVal->TypeGet();
12956 assert(type == flagVal->TypeGet());
12957
12958 // The thisVal and flagVal trees come from earlier statements.
12959 //
12960 // Unless they are invariant values, we need to evaluate them both
12961 // to temps at those points to safely transmit the values here.
12962 //
12963 // Also we need to use the flag twice, so we need two trees for it.
12964 GenTree* thisValOpt = nullptr;
12965 GenTree* flagValOpt = nullptr;
12966 GenTree* flagValOptCopy = nullptr;
12967
12968 if (thisVal->IsIntegralConst())
12969 {
12970 thisValOpt = gtClone(thisVal);
12971 assert(thisValOpt != nullptr);
12972 }
12973 else
12974 {
12975 const unsigned thisTmp = lvaGrabTemp(true DEBUGARG("Enum:HasFlag this temp"));
12976 GenTree* thisAsg = gtNewTempAssign(thisTmp, thisVal);
12977 GenTree* thisAsgStmt = thisOp->AsBox()->gtCopyStmtWhenInlinedBoxValue;
12978 thisAsgStmt->gtStmt.gtStmtExpr = thisAsg;
12979 thisValOpt = gtNewLclvNode(thisTmp, type);
12980 }
12981
12982 if (flagVal->IsIntegralConst())
12983 {
12984 flagValOpt = gtClone(flagVal);
12985 assert(flagValOpt != nullptr);
12986 flagValOptCopy = gtClone(flagVal);
12987 assert(flagValOptCopy != nullptr);
12988 }
12989 else
12990 {
12991 const unsigned flagTmp = lvaGrabTemp(true DEBUGARG("Enum:HasFlag flag temp"));
12992 GenTree* flagAsg = gtNewTempAssign(flagTmp, flagVal);
12993 GenTree* flagAsgStmt = flagOp->AsBox()->gtCopyStmtWhenInlinedBoxValue;
12994 flagAsgStmt->gtStmt.gtStmtExpr = flagAsg;
12995 flagValOpt = gtNewLclvNode(flagTmp, type);
12996 flagValOptCopy = gtNewLclvNode(flagTmp, type);
12997 }
12998
12999 // Turn the call into (thisValTmp & flagTmp) == flagTmp.
13000 GenTree* andTree = gtNewOperNode(GT_AND, type, thisValOpt, flagValOpt);
13001 GenTree* cmpTree = gtNewOperNode(GT_EQ, TYP_INT, andTree, flagValOptCopy);
13002
13003 JITDUMP("Optimized call to Enum.HasFlag\n");
13004
13005 return cmpTree;
13006}
13007
13008/*****************************************************************************
13009 *
13010 * Fold the given constant tree.
13011 */
13012
13013#ifdef _PREFAST_
13014#pragma warning(push)
13015#pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
13016#endif
13017GenTree* Compiler::gtFoldExprConst(GenTree* tree)
13018{
13019 unsigned kind = tree->OperKind();
13020
13021 SSIZE_T i1, i2, itemp;
13022 INT64 lval1, lval2, ltemp;
13023 float f1, f2;
13024 double d1, d2;
13025 var_types switchType;
13026 FieldSeqNode* fieldSeq = FieldSeqStore::NotAField(); // default unless we override it when folding
13027
13028 assert(kind & (GTK_UNOP | GTK_BINOP));
13029
13030 GenTree* op1 = tree->gtOp.gtOp1;
13031 GenTree* op2 = tree->gtGetOp2IfPresent();
13032
13033 if (!opts.OptEnabled(CLFLG_CONSTANTFOLD))
13034 {
13035 return tree;
13036 }
13037
13038 if (tree->OperGet() == GT_NOP)
13039 {
13040 return tree;
13041 }
13042
13043#ifdef FEATURE_SIMD
13044 if (tree->OperGet() == GT_SIMD)
13045 {
13046 return tree;
13047 }
13048#endif // FEATURE_SIMD
13049
13050 if (tree->gtOper == GT_ALLOCOBJ)
13051 {
13052 return tree;
13053 }
13054
13055 if (tree->gtOper == GT_RUNTIMELOOKUP)
13056 {
13057 return tree;
13058 }
13059
13060 if (kind & GTK_UNOP)
13061 {
13062 assert(op1->OperKind() & GTK_CONST);
13063
13064 switch (op1->gtType)
13065 {
13066 case TYP_INT:
13067
13068 /* Fold constant INT unary operator */
13069
13070 if (!op1->gtIntCon.ImmedValCanBeFolded(this, tree->OperGet()))
13071 {
13072 return tree;
13073 }
13074
13075 i1 = (int)op1->gtIntCon.gtIconVal;
13076
13077 // If we fold a unary oper, then the folded constant
13078 // is considered a ConstantIndexField if op1 was one
13079 //
13080
13081 if ((op1->gtIntCon.gtFieldSeq != nullptr) && op1->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
13082 {
13083 fieldSeq = op1->gtIntCon.gtFieldSeq;
13084 }
13085
13086 switch (tree->gtOper)
13087 {
13088 case GT_NOT:
13089 i1 = ~i1;
13090 break;
13091
13092 case GT_NEG:
13093 i1 = -i1;
13094 break;
13095
13096 case GT_BSWAP:
13097 i1 = ((i1 >> 24) & 0xFF) | ((i1 >> 8) & 0xFF00) | ((i1 << 8) & 0xFF0000) |
13098 ((i1 << 24) & 0xFF000000);
13099 break;
13100
13101 case GT_BSWAP16:
13102 i1 = ((i1 >> 8) & 0xFF) | ((i1 << 8) & 0xFF00);
13103 break;
13104
13105 case GT_CAST:
13106 // assert (genActualType(tree->CastToType()) == tree->gtType);
13107 switch (tree->CastToType())
13108 {
13109 case TYP_BYTE:
13110 itemp = INT32(INT8(i1));
13111 goto CHK_OVF;
13112
13113 case TYP_SHORT:
13114 itemp = INT32(INT16(i1));
13115 CHK_OVF:
13116 if (tree->gtOverflow() && ((itemp != i1) || ((tree->gtFlags & GTF_UNSIGNED) && i1 < 0)))
13117 {
13118 goto INT_OVF;
13119 }
13120 i1 = itemp;
13121 goto CNS_INT;
13122
13123 case TYP_USHORT:
13124 itemp = INT32(UINT16(i1));
13125 if (tree->gtOverflow())
13126 {
13127 if (itemp != i1)
13128 {
13129 goto INT_OVF;
13130 }
13131 }
13132 i1 = itemp;
13133 goto CNS_INT;
13134
13135 case TYP_BOOL:
13136 case TYP_UBYTE:
13137 itemp = INT32(UINT8(i1));
13138 if (tree->gtOverflow())
13139 {
13140 if (itemp != i1)
13141 {
13142 goto INT_OVF;
13143 }
13144 }
13145 i1 = itemp;
13146 goto CNS_INT;
13147
13148 case TYP_UINT:
13149 if (!(tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && i1 < 0)
13150 {
13151 goto INT_OVF;
13152 }
13153 goto CNS_INT;
13154
13155 case TYP_INT:
13156 if ((tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && i1 < 0)
13157 {
13158 goto INT_OVF;
13159 }
13160 goto CNS_INT;
13161
13162 case TYP_ULONG:
13163 if (tree->IsUnsigned())
13164 {
13165 lval1 = UINT64(UINT32(i1));
13166 }
13167 else
13168 {
13169 if (tree->gtOverflow() && (i1 < 0))
13170 {
13171 goto LNG_OVF;
13172 }
13173 lval1 = UINT64(INT32(i1));
13174 }
13175 goto CNS_LONG;
13176
13177 case TYP_LONG:
13178 if (tree->IsUnsigned())
13179 {
13180 lval1 = INT64(UINT32(i1));
13181 }
13182 else
13183 {
13184 lval1 = INT64(INT32(i1));
13185 }
13186 goto CNS_LONG;
13187
13188 case TYP_FLOAT:
13189 if (tree->gtFlags & GTF_UNSIGNED)
13190 {
13191 f1 = forceCastToFloat(UINT32(i1));
13192 }
13193 else
13194 {
13195 f1 = forceCastToFloat(INT32(i1));
13196 }
13197 d1 = f1;
13198 goto CNS_DOUBLE;
13199
13200 case TYP_DOUBLE:
13201 if (tree->gtFlags & GTF_UNSIGNED)
13202 {
13203 d1 = (double)UINT32(i1);
13204 }
13205 else
13206 {
13207 d1 = (double)INT32(i1);
13208 }
13209 goto CNS_DOUBLE;
13210
13211 default:
13212 assert(!"BAD_TYP");
13213 break;
13214 }
13215 return tree;
13216
13217 default:
13218 return tree;
13219 }
13220
13221 goto CNS_INT;
13222
13223 case TYP_LONG:
13224
13225 /* Fold constant LONG unary operator */
13226
13227 if (!op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13228 {
13229 return tree;
13230 }
13231
13232 lval1 = op1->gtIntConCommon.LngValue();
13233
13234 switch (tree->gtOper)
13235 {
13236 case GT_NOT:
13237 lval1 = ~lval1;
13238 break;
13239
13240 case GT_NEG:
13241 lval1 = -lval1;
13242 break;
13243
13244 case GT_BSWAP:
13245 lval1 = ((lval1 >> 56) & 0xFF) | ((lval1 >> 40) & 0xFF00) | ((lval1 >> 24) & 0xFF0000) |
13246 ((lval1 >> 8) & 0xFF000000) | ((lval1 << 8) & 0xFF00000000) |
13247 ((lval1 << 24) & 0xFF0000000000) | ((lval1 << 40) & 0xFF000000000000) |
13248 ((lval1 << 56) & 0xFF00000000000000);
13249 break;
13250
13251 case GT_CAST:
13252 assert(genActualType(tree->CastToType()) == tree->gtType);
13253 switch (tree->CastToType())
13254 {
13255 case TYP_BYTE:
13256 i1 = INT32(INT8(lval1));
13257 goto CHECK_INT_OVERFLOW;
13258
13259 case TYP_SHORT:
13260 i1 = INT32(INT16(lval1));
13261 goto CHECK_INT_OVERFLOW;
13262
13263 case TYP_USHORT:
13264 i1 = INT32(UINT16(lval1));
13265 goto CHECK_UINT_OVERFLOW;
13266
13267 case TYP_UBYTE:
13268 i1 = INT32(UINT8(lval1));
13269 goto CHECK_UINT_OVERFLOW;
13270
13271 case TYP_INT:
13272 i1 = INT32(lval1);
13273
13274 CHECK_INT_OVERFLOW:
13275 if (tree->gtOverflow())
13276 {
13277 if (i1 != lval1)
13278 {
13279 goto INT_OVF;
13280 }
13281 if ((tree->gtFlags & GTF_UNSIGNED) && i1 < 0)
13282 {
13283 goto INT_OVF;
13284 }
13285 }
13286 goto CNS_INT;
13287
13288 case TYP_UINT:
13289 i1 = UINT32(lval1);
13290
13291 CHECK_UINT_OVERFLOW:
13292 if (tree->gtOverflow() && UINT32(i1) != lval1)
13293 {
13294 goto INT_OVF;
13295 }
13296 goto CNS_INT;
13297
13298 case TYP_ULONG:
13299 if (!(tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && lval1 < 0)
13300 {
13301 goto LNG_OVF;
13302 }
13303 goto CNS_LONG;
13304
13305 case TYP_LONG:
13306 if ((tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && lval1 < 0)
13307 {
13308 goto LNG_OVF;
13309 }
13310 goto CNS_LONG;
13311
13312 case TYP_FLOAT:
13313 case TYP_DOUBLE:
13314 if ((tree->gtFlags & GTF_UNSIGNED) && lval1 < 0)
13315 {
13316 d1 = FloatingPointUtils::convertUInt64ToDouble((unsigned __int64)lval1);
13317 }
13318 else
13319 {
13320 d1 = (double)lval1;
13321 }
13322
13323 if (tree->CastToType() == TYP_FLOAT)
13324 {
13325 f1 = forceCastToFloat(d1); // truncate precision
13326 d1 = f1;
13327 }
13328 goto CNS_DOUBLE;
13329 default:
13330 assert(!"BAD_TYP");
13331 break;
13332 }
13333 return tree;
13334
13335 default:
13336 return tree;
13337 }
13338
13339 goto CNS_LONG;
13340
13341 case TYP_FLOAT:
13342 case TYP_DOUBLE:
13343 assert(op1->gtOper == GT_CNS_DBL);
13344
13345 /* Fold constant DOUBLE unary operator */
13346
13347 d1 = op1->gtDblCon.gtDconVal;
13348
13349 switch (tree->gtOper)
13350 {
13351 case GT_NEG:
13352 d1 = -d1;
13353 break;
13354
13355 case GT_CAST:
13356
13357 if (tree->gtOverflowEx())
13358 {
13359 return tree;
13360 }
13361
13362 assert(genActualType(tree->CastToType()) == tree->gtType);
13363
13364 if ((op1->gtType == TYP_FLOAT && !_finite(forceCastToFloat(d1))) ||
13365 (op1->gtType == TYP_DOUBLE && !_finite(d1)))
13366 {
13367 // The floating point constant is not finite. The ECMA spec says, in
13368 // III 3.27, that "...if overflow occurs converting a floating point type
13369 // to an integer, ..., the value returned is unspecified." However, it would
13370 // at least be desirable to have the same value returned for casting an overflowing
13371 // constant to an int as would obtained by passing that constant as a parameter
13372 // then casting that parameter to an int type. We will assume that the C compiler's
13373 // cast logic will yield the desired result (and trust testing to tell otherwise).
13374 // Cross-compilation is an issue here; if that becomes an important scenario, we should
13375 // capture the target-specific values of overflow casts to the various integral types as
13376 // constants in a target-specific function.
13377 CLANG_FORMAT_COMMENT_ANCHOR;
13378
13379 // Don't fold conversions of +inf/-inf to integral value on all platforms
13380 // as the value returned by JIT helper doesn't match with the C compiler's cast result.
13381 // We want the behavior to be same with or without folding.
13382 return tree;
13383 }
13384
13385 if (d1 <= -1.0 && varTypeIsUnsigned(tree->CastToType()))
13386 {
13387 // Don't fold conversions of these cases becasue the result is unspecified per ECMA spec
13388 // and the native math doing the fold doesn't match the run-time computation on all
13389 // platforms.
13390 // We want the behavior to be same with or without folding.
13391 return tree;
13392 }
13393
13394 switch (tree->CastToType())
13395 {
13396 case TYP_BYTE:
13397 i1 = INT32(INT8(d1));
13398 goto CNS_INT;
13399
13400 case TYP_SHORT:
13401 i1 = INT32(INT16(d1));
13402 goto CNS_INT;
13403
13404 case TYP_USHORT:
13405 i1 = INT32(UINT16(d1));
13406 goto CNS_INT;
13407
13408 case TYP_UBYTE:
13409 i1 = INT32(UINT8(d1));
13410 goto CNS_INT;
13411
13412 case TYP_INT:
13413 i1 = INT32(d1);
13414 goto CNS_INT;
13415
13416 case TYP_UINT:
13417 i1 = forceCastToUInt32(d1);
13418 goto CNS_INT;
13419
13420 case TYP_LONG:
13421 lval1 = INT64(d1);
13422 goto CNS_LONG;
13423
13424 case TYP_ULONG:
13425 lval1 = FloatingPointUtils::convertDoubleToUInt64(d1);
13426 goto CNS_LONG;
13427
13428 case TYP_FLOAT:
13429 d1 = forceCastToFloat(d1);
13430 goto CNS_DOUBLE;
13431
13432 case TYP_DOUBLE:
13433 if (op1->gtType == TYP_FLOAT)
13434 {
13435 d1 = forceCastToFloat(d1); // truncate precision
13436 }
13437 goto CNS_DOUBLE; // redundant cast
13438
13439 default:
13440 assert(!"BAD_TYP");
13441 break;
13442 }
13443 return tree;
13444
13445 default:
13446 return tree;
13447 }
13448 goto CNS_DOUBLE;
13449
13450 default:
13451 /* not a foldable typ - e.g. RET const */
13452 return tree;
13453 }
13454 }
13455
13456 /* We have a binary operator */
13457
13458 assert(kind & GTK_BINOP);
13459 assert(op2);
13460 assert(op1->OperKind() & GTK_CONST);
13461 assert(op2->OperKind() & GTK_CONST);
13462
13463 if (tree->gtOper == GT_COMMA)
13464 {
13465 return op2;
13466 }
13467
13468 if (tree->OperIsAnyList())
13469 {
13470 return tree;
13471 }
13472
13473 switchType = op1->gtType;
13474
13475 // Normally we will just switch on op1 types, but for the case where
13476 // only op2 is a GC type and op1 is not a GC type, we use the op2 type.
13477 // This makes us handle this as a case of folding for GC type.
13478 //
13479 if (varTypeIsGC(op2->gtType) && !varTypeIsGC(op1->gtType))
13480 {
13481 switchType = op2->gtType;
13482 }
13483
13484 switch (switchType)
13485 {
13486
13487 /*-------------------------------------------------------------------------
13488 * Fold constant REF of BYREF binary operator
13489 * These can only be comparisons or null pointers
13490 */
13491
13492 case TYP_REF:
13493
13494 /* String nodes are an RVA at this point */
13495
13496 if (op1->gtOper == GT_CNS_STR || op2->gtOper == GT_CNS_STR)
13497 {
13498 return tree;
13499 }
13500
13501 __fallthrough;
13502
13503 case TYP_BYREF:
13504
13505 i1 = op1->gtIntConCommon.IconValue();
13506 i2 = op2->gtIntConCommon.IconValue();
13507
13508 switch (tree->gtOper)
13509 {
13510 case GT_EQ:
13511 i1 = (i1 == i2);
13512 goto FOLD_COND;
13513
13514 case GT_NE:
13515 i1 = (i1 != i2);
13516 goto FOLD_COND;
13517
13518 case GT_ADD:
13519 noway_assert(tree->gtType != TYP_REF);
13520 // We only fold a GT_ADD that involves a null reference.
13521 if (((op1->TypeGet() == TYP_REF) && (i1 == 0)) || ((op2->TypeGet() == TYP_REF) && (i2 == 0)))
13522 {
13523#ifdef DEBUG
13524 if (verbose)
13525 {
13526 printf("\nFolding operator with constant nodes into a constant:\n");
13527 gtDispTree(tree);
13528 }
13529#endif
13530 // Fold into GT_IND of null byref
13531 tree->ChangeOperConst(GT_CNS_INT);
13532 tree->gtType = TYP_BYREF;
13533 tree->gtIntCon.gtIconVal = 0;
13534 tree->gtIntCon.gtFieldSeq = FieldSeqStore::NotAField();
13535 if (vnStore != nullptr)
13536 {
13537 fgValueNumberTreeConst(tree);
13538 }
13539#ifdef DEBUG
13540 if (verbose)
13541 {
13542 printf("\nFolded to null byref:\n");
13543 gtDispTree(tree);
13544 }
13545#endif
13546 goto DONE;
13547 }
13548
13549 default:
13550 break;
13551 }
13552
13553 return tree;
13554
13555 /*-------------------------------------------------------------------------
13556 * Fold constant INT binary operator
13557 */
13558
13559 case TYP_INT:
13560
13561 if (tree->OperIsCompare() && (tree->gtType == TYP_BYTE))
13562 {
13563 tree->gtType = TYP_INT;
13564 }
13565
13566 assert(tree->gtType == TYP_INT || varTypeIsGC(tree->TypeGet()) || tree->gtOper == GT_MKREFANY);
13567
13568 // No GC pointer types should be folded here...
13569 //
13570 assert(!varTypeIsGC(op1->gtType) && !varTypeIsGC(op2->gtType));
13571
13572 if (!op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13573 {
13574 return tree;
13575 }
13576
13577 if (!op2->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13578 {
13579 return tree;
13580 }
13581
13582 i1 = op1->gtIntConCommon.IconValue();
13583 i2 = op2->gtIntConCommon.IconValue();
13584
13585 switch (tree->gtOper)
13586 {
13587 case GT_EQ:
13588 i1 = (INT32(i1) == INT32(i2));
13589 break;
13590 case GT_NE:
13591 i1 = (INT32(i1) != INT32(i2));
13592 break;
13593
13594 case GT_LT:
13595 if (tree->gtFlags & GTF_UNSIGNED)
13596 {
13597 i1 = (UINT32(i1) < UINT32(i2));
13598 }
13599 else
13600 {
13601 i1 = (INT32(i1) < INT32(i2));
13602 }
13603 break;
13604
13605 case GT_LE:
13606 if (tree->gtFlags & GTF_UNSIGNED)
13607 {
13608 i1 = (UINT32(i1) <= UINT32(i2));
13609 }
13610 else
13611 {
13612 i1 = (INT32(i1) <= INT32(i2));
13613 }
13614 break;
13615
13616 case GT_GE:
13617 if (tree->gtFlags & GTF_UNSIGNED)
13618 {
13619 i1 = (UINT32(i1) >= UINT32(i2));
13620 }
13621 else
13622 {
13623 i1 = (INT32(i1) >= INT32(i2));
13624 }
13625 break;
13626
13627 case GT_GT:
13628 if (tree->gtFlags & GTF_UNSIGNED)
13629 {
13630 i1 = (UINT32(i1) > UINT32(i2));
13631 }
13632 else
13633 {
13634 i1 = (INT32(i1) > INT32(i2));
13635 }
13636 break;
13637
13638 case GT_ADD:
13639 itemp = i1 + i2;
13640 if (tree->gtOverflow())
13641 {
13642 if (tree->gtFlags & GTF_UNSIGNED)
13643 {
13644 if (INT64(UINT32(itemp)) != INT64(UINT32(i1)) + INT64(UINT32(i2)))
13645 {
13646 goto INT_OVF;
13647 }
13648 }
13649 else
13650 {
13651 if (INT64(INT32(itemp)) != INT64(INT32(i1)) + INT64(INT32(i2)))
13652 {
13653 goto INT_OVF;
13654 }
13655 }
13656 }
13657 i1 = itemp;
13658 fieldSeq = GetFieldSeqStore()->Append(op1->gtIntCon.gtFieldSeq, op2->gtIntCon.gtFieldSeq);
13659 break;
13660 case GT_SUB:
13661 itemp = i1 - i2;
13662 if (tree->gtOverflow())
13663 {
13664 if (tree->gtFlags & GTF_UNSIGNED)
13665 {
13666 if (INT64(UINT32(itemp)) != ((INT64)((UINT32)i1) - (INT64)((UINT32)i2)))
13667 {
13668 goto INT_OVF;
13669 }
13670 }
13671 else
13672 {
13673 if (INT64(INT32(itemp)) != INT64(INT32(i1)) - INT64(INT32(i2)))
13674 {
13675 goto INT_OVF;
13676 }
13677 }
13678 }
13679 i1 = itemp;
13680 break;
13681 case GT_MUL:
13682 itemp = i1 * i2;
13683 if (tree->gtOverflow())
13684 {
13685 if (tree->gtFlags & GTF_UNSIGNED)
13686 {
13687 if (INT64(UINT32(itemp)) != ((INT64)((UINT32)i1) * (INT64)((UINT32)i2)))
13688 {
13689 goto INT_OVF;
13690 }
13691 }
13692 else
13693 {
13694 if (INT64(INT32(itemp)) != INT64(INT32(i1)) * INT64(INT32(i2)))
13695 {
13696 goto INT_OVF;
13697 }
13698 }
13699 }
13700 // For the very particular case of the "constant array index" pseudo-field, we
13701 // assume that multiplication is by the field width, and preserves that field.
13702 // This could obviously be made more robust by a more complicated set of annotations...
13703 if ((op1->gtIntCon.gtFieldSeq != nullptr) && op1->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
13704 {
13705 assert(op2->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField());
13706 fieldSeq = op1->gtIntCon.gtFieldSeq;
13707 }
13708 else if ((op2->gtIntCon.gtFieldSeq != nullptr) &&
13709 op2->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
13710 {
13711 assert(op1->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField());
13712 fieldSeq = op2->gtIntCon.gtFieldSeq;
13713 }
13714 i1 = itemp;
13715 break;
13716
13717 case GT_OR:
13718 i1 |= i2;
13719 break;
13720 case GT_XOR:
13721 i1 ^= i2;
13722 break;
13723 case GT_AND:
13724 i1 &= i2;
13725 break;
13726
13727 case GT_LSH:
13728 i1 <<= (i2 & 0x1f);
13729 break;
13730 case GT_RSH:
13731 i1 >>= (i2 & 0x1f);
13732 break;
13733 case GT_RSZ:
13734 /* logical shift -> make it unsigned to not propagate the sign bit */
13735 i1 = UINT32(i1) >> (i2 & 0x1f);
13736 break;
13737 case GT_ROL:
13738 i1 = (i1 << (i2 & 0x1f)) | (UINT32(i1) >> ((32 - i2) & 0x1f));
13739 break;
13740 case GT_ROR:
13741 i1 = (i1 << ((32 - i2) & 0x1f)) | (UINT32(i1) >> (i2 & 0x1f));
13742 break;
13743
13744 /* DIV and MOD can generate an INT 0 - if division by 0
13745 * or overflow - when dividing MIN by -1 */
13746
13747 case GT_DIV:
13748 case GT_MOD:
13749 case GT_UDIV:
13750 case GT_UMOD:
13751 if (INT32(i2) == 0)
13752 {
13753 // Division by zero:
13754 // We have to evaluate this expression and throw an exception
13755 return tree;
13756 }
13757 else if ((INT32(i2) == -1) && (UINT32(i1) == 0x80000000))
13758 {
13759 // Overflow Division:
13760 // We have to evaluate this expression and throw an exception
13761 return tree;
13762 }
13763
13764 if (tree->gtOper == GT_DIV)
13765 {
13766 i1 = INT32(i1) / INT32(i2);
13767 }
13768 else if (tree->gtOper == GT_MOD)
13769 {
13770 i1 = INT32(i1) % INT32(i2);
13771 }
13772 else if (tree->gtOper == GT_UDIV)
13773 {
13774 i1 = UINT32(i1) / UINT32(i2);
13775 }
13776 else
13777 {
13778 assert(tree->gtOper == GT_UMOD);
13779 i1 = UINT32(i1) % UINT32(i2);
13780 }
13781 break;
13782
13783 default:
13784 return tree;
13785 }
13786
13787 /* We get here after folding to a GT_CNS_INT type
13788 * change the node to the new type / value and make sure the node sizes are OK */
13789 CNS_INT:
13790 FOLD_COND:
13791
13792#ifdef DEBUG
13793 if (verbose)
13794 {
13795 printf("\nFolding operator with constant nodes into a constant:\n");
13796 gtDispTree(tree);
13797 }
13798#endif
13799
13800#ifdef _TARGET_64BIT_
13801 // Some operations are performed as 64 bit instead of 32 bit so the upper 32 bits
13802 // need to be discarded. Since constant values are stored as ssize_t and the node
13803 // has TYP_INT the result needs to be sign extended rather than zero extended.
13804 i1 = INT32(i1);
13805#endif // _TARGET_64BIT_
13806
13807 /* Also all conditional folding jumps here since the node hanging from
13808 * GT_JTRUE has to be a GT_CNS_INT - value 0 or 1 */
13809
13810 tree->ChangeOperConst(GT_CNS_INT);
13811 tree->gtType = TYP_INT;
13812 tree->gtIntCon.gtIconVal = i1;
13813 tree->gtIntCon.gtFieldSeq = fieldSeq;
13814 if (vnStore != nullptr)
13815 {
13816 fgValueNumberTreeConst(tree);
13817 }
13818#ifdef DEBUG
13819 if (verbose)
13820 {
13821 printf("Bashed to int constant:\n");
13822 gtDispTree(tree);
13823 }
13824#endif
13825 goto DONE;
13826
13827 /* This operation is going to cause an overflow exception. Morph into
13828 an overflow helper. Put a dummy constant value for code generation.
13829
13830 We could remove all subsequent trees in the current basic block,
13831 unless this node is a child of GT_COLON
13832
13833 NOTE: Since the folded value is not constant we should not change the
13834 "tree" node - otherwise we confuse the logic that checks if the folding
13835 was successful - instead use one of the operands, e.g. op1
13836 */
13837
13838 LNG_OVF:
13839 // Don't fold overflow operations if not global morph phase.
13840 // The reason for this is that this optimization is replacing a gentree node
13841 // with another new gentree node. Say a GT_CALL(arglist) has one 'arg'
13842 // involving overflow arithmetic. During assertion prop, it is possible
13843 // that the 'arg' could be constant folded and the result could lead to an
13844 // overflow. In such a case 'arg' will get replaced with GT_COMMA node
13845 // but fgMorphArgs() - see the logic around "if(lateArgsComputed)" - doesn't
13846 // update args table. For this reason this optimization is enabled only
13847 // for global morphing phase.
13848 //
13849 // TODO-CQ: Once fgMorphArgs() is fixed this restriction could be removed.
13850 CLANG_FORMAT_COMMENT_ANCHOR;
13851
13852 if (!fgGlobalMorph)
13853 {
13854 assert(tree->gtOverflow());
13855 return tree;
13856 }
13857
13858 op1 = gtNewLconNode(0);
13859 if (vnStore != nullptr)
13860 {
13861 op1->gtVNPair.SetBoth(vnStore->VNZeroForType(TYP_LONG));
13862 }
13863 goto OVF;
13864
13865 INT_OVF:
13866 // Don't fold overflow operations if not global morph phase.
13867 // The reason for this is that this optimization is replacing a gentree node
13868 // with another new gentree node. Say a GT_CALL(arglist) has one 'arg'
13869 // involving overflow arithmetic. During assertion prop, it is possible
13870 // that the 'arg' could be constant folded and the result could lead to an
13871 // overflow. In such a case 'arg' will get replaced with GT_COMMA node
13872 // but fgMorphArgs() - see the logic around "if(lateArgsComputed)" - doesn't
13873 // update args table. For this reason this optimization is enabled only
13874 // for global morphing phase.
13875 //
13876 // TODO-CQ: Once fgMorphArgs() is fixed this restriction could be removed.
13877
13878 if (!fgGlobalMorph)
13879 {
13880 assert(tree->gtOverflow());
13881 return tree;
13882 }
13883
13884 op1 = gtNewIconNode(0);
13885 if (vnStore != nullptr)
13886 {
13887 op1->gtVNPair.SetBoth(vnStore->VNZeroForType(TYP_INT));
13888 }
13889 goto OVF;
13890
13891 OVF:
13892#ifdef DEBUG
13893 if (verbose)
13894 {
13895 printf("\nFolding binary operator with constant nodes into a comma throw:\n");
13896 gtDispTree(tree);
13897 }
13898#endif
13899 /* We will change the cast to a GT_COMMA and attach the exception helper as gtOp.gtOp1.
13900 * The constant expression zero becomes op2. */
13901
13902 assert(tree->gtOverflow());
13903 assert(tree->gtOper == GT_ADD || tree->gtOper == GT_SUB || tree->gtOper == GT_CAST ||
13904 tree->gtOper == GT_MUL);
13905 assert(op1);
13906
13907 op2 = op1;
13908 op1 = gtNewHelperCallNode(CORINFO_HELP_OVERFLOW, TYP_VOID,
13909 gtNewArgList(gtNewIconNode(compCurBB->bbTryIndex)));
13910
13911 // op1 is a call to the JIT helper that throws an Overflow exception
13912 // attach the ExcSet for VNF_OverflowExc(Void) to this call
13913
13914 if (vnStore != nullptr)
13915 {
13916 op1->gtVNPair =
13917 vnStore->VNPWithExc(ValueNumPair(ValueNumStore::VNForVoid(), ValueNumStore::VNForVoid()),
13918 vnStore->VNPExcSetSingleton(
13919 vnStore->VNPairForFunc(TYP_REF, VNF_OverflowExc, vnStore->VNPForVoid())));
13920 }
13921
13922 tree = gtNewOperNode(GT_COMMA, tree->gtType, op1, op2);
13923
13924 return tree;
13925
13926 /*-------------------------------------------------------------------------
13927 * Fold constant LONG binary operator
13928 */
13929
13930 case TYP_LONG:
13931
13932 // No GC pointer types should be folded here...
13933 //
13934 assert(!varTypeIsGC(op1->gtType) && !varTypeIsGC(op2->gtType));
13935
13936 // op1 is known to be a TYP_LONG, op2 is normally a TYP_LONG, unless we have a shift operator in which case
13937 // it is a TYP_INT
13938 //
13939 assert((op2->gtType == TYP_LONG) || (op2->gtType == TYP_INT));
13940
13941 if (!op1->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13942 {
13943 return tree;
13944 }
13945
13946 if (!op2->gtIntConCommon.ImmedValCanBeFolded(this, tree->OperGet()))
13947 {
13948 return tree;
13949 }
13950
13951 lval1 = op1->gtIntConCommon.LngValue();
13952
13953 // For the shift operators we can have a op2 that is a TYP_INT and thus will be GT_CNS_INT
13954 if (op2->OperGet() == GT_CNS_INT)
13955 {
13956 lval2 = op2->gtIntConCommon.IconValue();
13957 }
13958 else
13959 {
13960 lval2 = op2->gtIntConCommon.LngValue();
13961 }
13962
13963 switch (tree->gtOper)
13964 {
13965 case GT_EQ:
13966 i1 = (lval1 == lval2);
13967 goto FOLD_COND;
13968 case GT_NE:
13969 i1 = (lval1 != lval2);
13970 goto FOLD_COND;
13971
13972 case GT_LT:
13973 if (tree->gtFlags & GTF_UNSIGNED)
13974 {
13975 i1 = (UINT64(lval1) < UINT64(lval2));
13976 }
13977 else
13978 {
13979 i1 = (lval1 < lval2);
13980 }
13981 goto FOLD_COND;
13982
13983 case GT_LE:
13984 if (tree->gtFlags & GTF_UNSIGNED)
13985 {
13986 i1 = (UINT64(lval1) <= UINT64(lval2));
13987 }
13988 else
13989 {
13990 i1 = (lval1 <= lval2);
13991 }
13992 goto FOLD_COND;
13993
13994 case GT_GE:
13995 if (tree->gtFlags & GTF_UNSIGNED)
13996 {
13997 i1 = (UINT64(lval1) >= UINT64(lval2));
13998 }
13999 else
14000 {
14001 i1 = (lval1 >= lval2);
14002 }
14003 goto FOLD_COND;
14004
14005 case GT_GT:
14006 if (tree->gtFlags & GTF_UNSIGNED)
14007 {
14008 i1 = (UINT64(lval1) > UINT64(lval2));
14009 }
14010 else
14011 {
14012 i1 = (lval1 > lval2);
14013 }
14014 goto FOLD_COND;
14015
14016 case GT_ADD:
14017 ltemp = lval1 + lval2;
14018
14019 LNG_ADD_CHKOVF:
14020 /* For the SIGNED case - If there is one positive and one negative operand, there can be no overflow
14021 * If both are positive, the result has to be positive, and similary for negatives.
14022 *
14023 * For the UNSIGNED case - If a UINT32 operand is bigger than the result then OVF */
14024
14025 if (tree->gtOverflow())
14026 {
14027 if (tree->gtFlags & GTF_UNSIGNED)
14028 {
14029 if ((UINT64(lval1) > UINT64(ltemp)) || (UINT64(lval2) > UINT64(ltemp)))
14030 {
14031 goto LNG_OVF;
14032 }
14033 }
14034 else if (((lval1 < 0) == (lval2 < 0)) && ((lval1 < 0) != (ltemp < 0)))
14035 {
14036 goto LNG_OVF;
14037 }
14038 }
14039 lval1 = ltemp;
14040 break;
14041
14042 case GT_SUB:
14043 ltemp = lval1 - lval2;
14044 if (tree->gtOverflow())
14045 {
14046 if (tree->gtFlags & GTF_UNSIGNED)
14047 {
14048 if (UINT64(lval2) > UINT64(lval1))
14049 {
14050 goto LNG_OVF;
14051 }
14052 }
14053 else
14054 {
14055 /* If both operands are +ve or both are -ve, there can be no
14056 overflow. Else use the logic for : lval1 + (-lval2) */
14057
14058 if ((lval1 < 0) != (lval2 < 0))
14059 {
14060 if (lval2 == INT64_MIN)
14061 {
14062 goto LNG_OVF;
14063 }
14064 lval2 = -lval2;
14065 goto LNG_ADD_CHKOVF;
14066 }
14067 }
14068 }
14069 lval1 = ltemp;
14070 break;
14071
14072 case GT_MUL:
14073 ltemp = lval1 * lval2;
14074
14075 if (tree->gtOverflow() && lval2 != 0)
14076 {
14077
14078 if (tree->gtFlags & GTF_UNSIGNED)
14079 {
14080 UINT64 ultemp = ltemp;
14081 UINT64 ulval1 = lval1;
14082 UINT64 ulval2 = lval2;
14083 if ((ultemp / ulval2) != ulval1)
14084 {
14085 goto LNG_OVF;
14086 }
14087 }
14088 else
14089 {
14090 // This does a multiply and then reverses it. This test works great except for MIN_INT *
14091 //-1. In that case we mess up the sign on ltmp. Make sure to double check the sign.
14092 // if either is 0, then no overflow
14093 if (lval1 != 0) // lval2 checked above.
14094 {
14095 if (((lval1 < 0) == (lval2 < 0)) && (ltemp < 0))
14096 {
14097 goto LNG_OVF;
14098 }
14099 if (((lval1 < 0) != (lval2 < 0)) && (ltemp > 0))
14100 {
14101 goto LNG_OVF;
14102 }
14103
14104 // TODO-Amd64-Unix: Remove the code that disables optimizations for this method when the
14105 // clang
14106 // optimizer is fixed and/or the method implementation is refactored in a simpler code.
14107 // There is a bug in the clang-3.5 optimizer. The issue is that in release build the
14108 // optimizer is mistyping (or just wrongly decides to use 32 bit operation for a corner
14109 // case of MIN_LONG) the args of the (ltemp / lval2) to int (it does a 32 bit div
14110 // operation instead of 64 bit.). For the case of lval1 and lval2 equal to MIN_LONG
14111 // (0x8000000000000000) this results in raising a SIGFPE.
14112 // Optimizations disabled for now. See compiler.h.
14113 if ((ltemp / lval2) != lval1)
14114 {
14115 goto LNG_OVF;
14116 }
14117 }
14118 }
14119 }
14120
14121 lval1 = ltemp;
14122 break;
14123
14124 case GT_OR:
14125 lval1 |= lval2;
14126 break;
14127 case GT_XOR:
14128 lval1 ^= lval2;
14129 break;
14130 case GT_AND:
14131 lval1 &= lval2;
14132 break;
14133
14134 case GT_LSH:
14135 lval1 <<= (lval2 & 0x3f);
14136 break;
14137 case GT_RSH:
14138 lval1 >>= (lval2 & 0x3f);
14139 break;
14140 case GT_RSZ:
14141 /* logical shift -> make it unsigned to not propagate the sign bit */
14142 lval1 = UINT64(lval1) >> (lval2 & 0x3f);
14143 break;
14144 case GT_ROL:
14145 lval1 = (lval1 << (lval2 & 0x3f)) | (UINT64(lval1) >> ((64 - lval2) & 0x3f));
14146 break;
14147 case GT_ROR:
14148 lval1 = (lval1 << ((64 - lval2) & 0x3f)) | (UINT64(lval1) >> (lval2 & 0x3f));
14149 break;
14150
14151 // Both DIV and IDIV on x86 raise an exception for min_int (and min_long) / -1. So we preserve
14152 // that behavior here.
14153 case GT_DIV:
14154 if (!lval2)
14155 {
14156 return tree;
14157 }
14158
14159 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
14160 {
14161 return tree;
14162 }
14163 lval1 /= lval2;
14164 break;
14165
14166 case GT_MOD:
14167 if (!lval2)
14168 {
14169 return tree;
14170 }
14171 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
14172 {
14173 return tree;
14174 }
14175 lval1 %= lval2;
14176 break;
14177
14178 case GT_UDIV:
14179 if (!lval2)
14180 {
14181 return tree;
14182 }
14183 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
14184 {
14185 return tree;
14186 }
14187 lval1 = UINT64(lval1) / UINT64(lval2);
14188 break;
14189
14190 case GT_UMOD:
14191 if (!lval2)
14192 {
14193 return tree;
14194 }
14195 if (UINT64(lval1) == UI64(0x8000000000000000) && lval2 == INT64(-1))
14196 {
14197 return tree;
14198 }
14199 lval1 = UINT64(lval1) % UINT64(lval2);
14200 break;
14201 default:
14202 return tree;
14203 }
14204
14205 CNS_LONG:
14206
14207 if (fieldSeq != FieldSeqStore::NotAField())
14208 {
14209 return tree;
14210 }
14211
14212#ifdef DEBUG
14213 if (verbose)
14214 {
14215 printf("\nFolding long operator with constant nodes into a constant:\n");
14216 gtDispTree(tree);
14217 }
14218#endif
14219 assert((GenTree::s_gtNodeSizes[GT_CNS_NATIVELONG] == TREE_NODE_SZ_SMALL) ||
14220 (tree->gtDebugFlags & GTF_DEBUG_NODE_LARGE));
14221
14222 tree->ChangeOperConst(GT_CNS_NATIVELONG);
14223 tree->gtIntConCommon.SetLngValue(lval1);
14224 if (vnStore != nullptr)
14225 {
14226 fgValueNumberTreeConst(tree);
14227 }
14228
14229#ifdef DEBUG
14230 if (verbose)
14231 {
14232 printf("Bashed to long constant:\n");
14233 gtDispTree(tree);
14234 }
14235#endif
14236 goto DONE;
14237
14238 /*-------------------------------------------------------------------------
14239 * Fold constant FLOAT or DOUBLE binary operator
14240 */
14241
14242 case TYP_FLOAT:
14243 case TYP_DOUBLE:
14244
14245 if (tree->gtOverflowEx())
14246 {
14247 return tree;
14248 }
14249
14250 assert(op1->gtOper == GT_CNS_DBL);
14251 d1 = op1->gtDblCon.gtDconVal;
14252
14253 assert(varTypeIsFloating(op2->gtType));
14254 assert(op2->gtOper == GT_CNS_DBL);
14255 d2 = op2->gtDblCon.gtDconVal;
14256
14257 /* Special case - check if we have NaN operands.
14258 * For comparisons if not an unordered operation always return 0.
14259 * For unordered operations (i.e. the GTF_RELOP_NAN_UN flag is set)
14260 * the result is always true - return 1. */
14261
14262 if (_isnan(d1) || _isnan(d2))
14263 {
14264#ifdef DEBUG
14265 if (verbose)
14266 {
14267 printf("Double operator(s) is NaN\n");
14268 }
14269#endif
14270 if (tree->OperKind() & GTK_RELOP)
14271 {
14272 if (tree->gtFlags & GTF_RELOP_NAN_UN)
14273 {
14274 /* Unordered comparison with NaN always succeeds */
14275 i1 = 1;
14276 goto FOLD_COND;
14277 }
14278 else
14279 {
14280 /* Normal comparison with NaN always fails */
14281 i1 = 0;
14282 goto FOLD_COND;
14283 }
14284 }
14285 }
14286
14287 switch (tree->gtOper)
14288 {
14289 case GT_EQ:
14290 i1 = (d1 == d2);
14291 goto FOLD_COND;
14292 case GT_NE:
14293 i1 = (d1 != d2);
14294 goto FOLD_COND;
14295
14296 case GT_LT:
14297 i1 = (d1 < d2);
14298 goto FOLD_COND;
14299 case GT_LE:
14300 i1 = (d1 <= d2);
14301 goto FOLD_COND;
14302 case GT_GE:
14303 i1 = (d1 >= d2);
14304 goto FOLD_COND;
14305 case GT_GT:
14306 i1 = (d1 > d2);
14307 goto FOLD_COND;
14308
14309 // Floating point arithmetic should be done in declared
14310 // precision while doing constant folding. For this reason though TYP_FLOAT
14311 // constants are stored as double constants, while performing float arithmetic,
14312 // double constants should be converted to float. Here is an example case
14313 // where performing arithmetic in double precision would lead to incorrect
14314 // results.
14315 //
14316 // Example:
14317 // float a = float.MaxValue;
14318 // float b = a*a; This will produce +inf in single precision and 1.1579207543382391e+077 in double
14319 // precision.
14320 // flaot c = b/b; This will produce NaN in single precision and 1 in double precision.
14321 case GT_ADD:
14322 if (op1->TypeGet() == TYP_FLOAT)
14323 {
14324 f1 = forceCastToFloat(d1);
14325 f2 = forceCastToFloat(d2);
14326 d1 = forceCastToFloat(f1 + f2);
14327 }
14328 else
14329 {
14330 d1 += d2;
14331 }
14332 break;
14333
14334 case GT_SUB:
14335 if (op1->TypeGet() == TYP_FLOAT)
14336 {
14337 f1 = forceCastToFloat(d1);
14338 f2 = forceCastToFloat(d2);
14339 d1 = forceCastToFloat(f1 - f2);
14340 }
14341 else
14342 {
14343 d1 -= d2;
14344 }
14345 break;
14346
14347 case GT_MUL:
14348 if (op1->TypeGet() == TYP_FLOAT)
14349 {
14350 f1 = forceCastToFloat(d1);
14351 f2 = forceCastToFloat(d2);
14352 d1 = forceCastToFloat(f1 * f2);
14353 }
14354 else
14355 {
14356 d1 *= d2;
14357 }
14358 break;
14359
14360 case GT_DIV:
14361 if (!d2)
14362 {
14363 return tree;
14364 }
14365 if (op1->TypeGet() == TYP_FLOAT)
14366 {
14367 f1 = forceCastToFloat(d1);
14368 f2 = forceCastToFloat(d2);
14369 d1 = forceCastToFloat(f1 / f2);
14370 }
14371 else
14372 {
14373 d1 /= d2;
14374 }
14375 break;
14376
14377 default:
14378 return tree;
14379 }
14380
14381 CNS_DOUBLE:
14382
14383#ifdef DEBUG
14384 if (verbose)
14385 {
14386 printf("\nFolding fp operator with constant nodes into a fp constant:\n");
14387 gtDispTree(tree);
14388 }
14389#endif
14390
14391 assert((GenTree::s_gtNodeSizes[GT_CNS_DBL] == TREE_NODE_SZ_SMALL) ||
14392 (tree->gtDebugFlags & GTF_DEBUG_NODE_LARGE));
14393
14394 tree->ChangeOperConst(GT_CNS_DBL);
14395 tree->gtDblCon.gtDconVal = d1;
14396 if (vnStore != nullptr)
14397 {
14398 fgValueNumberTreeConst(tree);
14399 }
14400#ifdef DEBUG
14401 if (verbose)
14402 {
14403 printf("Bashed to fp constant:\n");
14404 gtDispTree(tree);
14405 }
14406#endif
14407 goto DONE;
14408
14409 default:
14410 /* not a foldable typ */
14411 return tree;
14412 }
14413
14414//-------------------------------------------------------------------------
14415
14416DONE:
14417
14418 /* Make sure no side effect flags are set on this constant node */
14419
14420 tree->gtFlags &= ~GTF_ALL_EFFECT;
14421
14422 return tree;
14423}
14424#ifdef _PREFAST_
14425#pragma warning(pop)
14426#endif
14427
14428//------------------------------------------------------------------------
14429// gtNewTempAssign: Create an assignment of the given value to a temp.
14430//
14431// Arguments:
14432// tmp - local number for a compiler temp
14433// val - value to assign to the temp
14434// pAfterStmt - statement to insert any additional statements after
14435// ilOffset - il offset for new statements
14436// block - block to insert any additional statements in
14437//
14438// Return Value:
14439// Normally a new assignment node.
14440// However may return a nop node if val is simply a reference to the temp.
14441//
14442// Notes:
14443// Self-assignments may be represented via NOPs.
14444//
14445// May update the type of the temp, if it was previously unknown.
14446//
14447// May set compFloatingPointUsed.
14448
14449GenTree* Compiler::gtNewTempAssign(
14450 unsigned tmp, GenTree* val, GenTree** pAfterStmt, IL_OFFSETX ilOffset, BasicBlock* block)
14451{
14452 // Self-assignment is a nop.
14453 if (val->OperGet() == GT_LCL_VAR && val->gtLclVarCommon.gtLclNum == tmp)
14454 {
14455 return gtNewNothingNode();
14456 }
14457
14458 LclVarDsc* varDsc = lvaTable + tmp;
14459
14460 if (varDsc->TypeGet() == TYP_I_IMPL && val->TypeGet() == TYP_BYREF)
14461 {
14462 impBashVarAddrsToI(val);
14463 }
14464
14465 var_types valTyp = val->TypeGet();
14466 if (val->OperGet() == GT_LCL_VAR && lvaTable[val->gtLclVar.gtLclNum].lvNormalizeOnLoad())
14467 {
14468 valTyp = lvaGetRealType(val->gtLclVar.gtLclNum);
14469 val->gtType = valTyp;
14470 }
14471 var_types dstTyp = varDsc->TypeGet();
14472
14473 /* If the variable's lvType is not yet set then set it here */
14474 if (dstTyp == TYP_UNDEF)
14475 {
14476 varDsc->lvType = dstTyp = genActualType(valTyp);
14477 if (varTypeIsGC(dstTyp))
14478 {
14479 varDsc->lvStructGcCount = 1;
14480 }
14481#if FEATURE_SIMD
14482 else if (varTypeIsSIMD(dstTyp))
14483 {
14484 varDsc->lvSIMDType = 1;
14485 }
14486#endif
14487 }
14488
14489#ifdef DEBUG
14490 /* Make sure the actual types match */
14491 if (genActualType(valTyp) != genActualType(dstTyp))
14492 {
14493 // Plus some other exceptions that are apparently legal:
14494 // 1) TYP_REF or BYREF = TYP_I_IMPL
14495 bool ok = false;
14496 if (varTypeIsGC(dstTyp) && (valTyp == TYP_I_IMPL))
14497 {
14498 ok = true;
14499 }
14500 // 2) TYP_DOUBLE = TYP_FLOAT or TYP_FLOAT = TYP_DOUBLE
14501 else if (varTypeIsFloating(dstTyp) && varTypeIsFloating(valTyp))
14502 {
14503 ok = true;
14504 }
14505
14506 if (!ok)
14507 {
14508 gtDispTree(val);
14509 assert(!"Incompatible types for gtNewTempAssign");
14510 }
14511 }
14512#endif
14513
14514 // Floating Point assignments can be created during inlining
14515 // see "Zero init inlinee locals:" in fgInlinePrependStatements
14516 // thus we may need to set compFloatingPointUsed to true here.
14517 //
14518 if (varTypeIsFloating(dstTyp) && (compFloatingPointUsed == false))
14519 {
14520 compFloatingPointUsed = true;
14521 }
14522
14523 /* Create the assignment node */
14524
14525 GenTree* asg;
14526 GenTree* dest = gtNewLclvNode(tmp, dstTyp);
14527 dest->gtFlags |= GTF_VAR_DEF;
14528
14529 // With first-class structs, we should be propagating the class handle on all non-primitive
14530 // struct types. We don't have a convenient way to do that for all SIMD temps, since some
14531 // internal trees use SIMD types that are not used by the input IL. In this case, we allow
14532 // a null type handle and derive the necessary information about the type from its varType.
14533 CORINFO_CLASS_HANDLE structHnd = gtGetStructHandleIfPresent(val);
14534 if (varTypeIsStruct(valTyp) && ((structHnd != NO_CLASS_HANDLE) || (varTypeIsSIMD(valTyp))))
14535 {
14536 // The struct value may be be a child of a GT_COMMA.
14537 GenTree* valx = val->gtEffectiveVal(/*commaOnly*/ true);
14538
14539 if (structHnd != NO_CLASS_HANDLE)
14540 {
14541 lvaSetStruct(tmp, structHnd, false);
14542 }
14543 else
14544 {
14545 assert(valx->gtOper != GT_OBJ);
14546 }
14547 dest->gtFlags |= GTF_DONT_CSE;
14548 valx->gtFlags |= GTF_DONT_CSE;
14549 asg = impAssignStruct(dest, val, structHnd, (unsigned)CHECK_SPILL_NONE, pAfterStmt, ilOffset, block);
14550 }
14551 else
14552 {
14553 asg = gtNewAssignNode(dest, val);
14554 }
14555
14556 if (compRationalIRForm)
14557 {
14558 Rationalizer::RewriteAssignmentIntoStoreLcl(asg->AsOp());
14559 }
14560
14561 return asg;
14562}
14563
14564/*****************************************************************************
14565 *
14566 * Create a helper call to access a COM field (iff 'assg' is non-zero this is
14567 * an assignment and 'assg' is the new value).
14568 */
14569
14570GenTree* Compiler::gtNewRefCOMfield(GenTree* objPtr,
14571 CORINFO_RESOLVED_TOKEN* pResolvedToken,
14572 CORINFO_ACCESS_FLAGS access,
14573 CORINFO_FIELD_INFO* pFieldInfo,
14574 var_types lclTyp,
14575 CORINFO_CLASS_HANDLE structType,
14576 GenTree* assg)
14577{
14578 assert(pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER ||
14579 pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_ADDR_HELPER ||
14580 pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_ADDR_HELPER);
14581
14582 /* If we can't access it directly, we need to call a helper function */
14583 GenTreeArgList* args = nullptr;
14584 var_types helperType = TYP_BYREF;
14585
14586 if (pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER)
14587 {
14588 if (access & CORINFO_ACCESS_SET)
14589 {
14590 assert(assg != nullptr);
14591 // helper needs pointer to struct, not struct itself
14592 if (pFieldInfo->helper == CORINFO_HELP_SETFIELDSTRUCT)
14593 {
14594 assert(structType != nullptr);
14595 assg = impGetStructAddr(assg, structType, (unsigned)CHECK_SPILL_ALL, true);
14596 }
14597 else if (lclTyp == TYP_DOUBLE && assg->TypeGet() == TYP_FLOAT)
14598 {
14599 assg = gtNewCastNode(TYP_DOUBLE, assg, false, TYP_DOUBLE);
14600 }
14601 else if (lclTyp == TYP_FLOAT && assg->TypeGet() == TYP_DOUBLE)
14602 {
14603 assg = gtNewCastNode(TYP_FLOAT, assg, false, TYP_FLOAT);
14604 }
14605
14606 args = gtNewArgList(assg);
14607 helperType = TYP_VOID;
14608 }
14609 else if (access & CORINFO_ACCESS_GET)
14610 {
14611 helperType = lclTyp;
14612
14613 // The calling convention for the helper does not take into
14614 // account optimization of primitive structs.
14615 if ((pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT) && !varTypeIsStruct(lclTyp))
14616 {
14617 helperType = TYP_STRUCT;
14618 }
14619 }
14620 }
14621
14622 if (pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT || pFieldInfo->helper == CORINFO_HELP_SETFIELDSTRUCT)
14623 {
14624 assert(pFieldInfo->structType != nullptr);
14625 args = gtNewListNode(gtNewIconEmbClsHndNode(pFieldInfo->structType), args);
14626 }
14627
14628 GenTree* fieldHnd = impTokenToHandle(pResolvedToken);
14629 if (fieldHnd == nullptr)
14630 { // compDonotInline()
14631 return nullptr;
14632 }
14633
14634 args = gtNewListNode(fieldHnd, args);
14635
14636 // If it's a static field, we shouldn't have an object node
14637 // If it's an instance field, we have an object node
14638 assert((pFieldInfo->fieldAccessor != CORINFO_FIELD_STATIC_ADDR_HELPER) ^ (objPtr == nullptr));
14639
14640 if (objPtr != nullptr)
14641 {
14642 args = gtNewListNode(objPtr, args);
14643 }
14644
14645 GenTreeCall* call = gtNewHelperCallNode(pFieldInfo->helper, genActualType(helperType), args);
14646
14647#if FEATURE_MULTIREG_RET
14648 if (varTypeIsStruct(call))
14649 {
14650 // Initialize Return type descriptor of call node.
14651 ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc();
14652 retTypeDesc->InitializeStructReturnType(this, structType);
14653 }
14654#endif // FEATURE_MULTIREG_RET
14655
14656 GenTree* result = call;
14657
14658 if (pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER)
14659 {
14660 if (access & CORINFO_ACCESS_GET)
14661 {
14662 if (pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT)
14663 {
14664 if (!varTypeIsStruct(lclTyp))
14665 {
14666 // get the result as primitive type
14667 result = impGetStructAddr(result, structType, (unsigned)CHECK_SPILL_ALL, true);
14668 result = gtNewOperNode(GT_IND, lclTyp, result);
14669 }
14670 }
14671 else if (varTypeIsIntegral(lclTyp) && genTypeSize(lclTyp) < genTypeSize(TYP_INT))
14672 {
14673 // The helper does not extend the small return types.
14674 result = gtNewCastNode(genActualType(lclTyp), result, false, lclTyp);
14675 }
14676 }
14677 }
14678 else
14679 {
14680 // OK, now do the indirection
14681 if (access & CORINFO_ACCESS_GET)
14682 {
14683 if (varTypeIsStruct(lclTyp))
14684 {
14685 result = gtNewObjNode(structType, result);
14686 }
14687 else
14688 {
14689 result = gtNewOperNode(GT_IND, lclTyp, result);
14690 }
14691 result->gtFlags |= (GTF_EXCEPT | GTF_GLOB_REF);
14692 }
14693 else if (access & CORINFO_ACCESS_SET)
14694 {
14695 if (varTypeIsStruct(lclTyp))
14696 {
14697 result = impAssignStructPtr(result, assg, structType, (unsigned)CHECK_SPILL_ALL);
14698 }
14699 else
14700 {
14701 result = gtNewOperNode(GT_IND, lclTyp, result);
14702 result->gtFlags |= (GTF_EXCEPT | GTF_GLOB_REF | GTF_IND_TGTANYWHERE);
14703 result = gtNewAssignNode(result, assg);
14704 }
14705 }
14706 }
14707
14708 return result;
14709}
14710
14711/*****************************************************************************
14712 *
14713 * Return true if the given node (excluding children trees) contains side effects.
14714 * Note that it does not recurse, and children need to be handled separately.
14715 * It may return false even if the node has GTF_SIDE_EFFECT (because of its children).
14716 *
14717 * Similar to OperMayThrow() (but handles GT_CALLs specially), but considers
14718 * assignments too.
14719 */
14720
14721bool Compiler::gtNodeHasSideEffects(GenTree* tree, unsigned flags)
14722{
14723 if (flags & GTF_ASG)
14724 {
14725 // TODO-Cleanup: This only checks for GT_ASG but according to OperRequiresAsgFlag there
14726 // are many more opers that are considered to have an assignment side effect: atomic ops
14727 // (GT_CMPXCHG & co.), GT_MEMORYBARRIER (not classified as an atomic op) and HW intrinsic
14728 // memory stores. Atomic ops have special handling in gtExtractSideEffList but the others
14729 // will simply be dropped is they are ever subject to an "extract side effects" operation.
14730 // It is possible that the reason no bugs have yet been observed in this area is that the
14731 // other nodes are likely to always be tree roots.
14732 if (tree->OperIs(GT_ASG))
14733 {
14734 return true;
14735 }
14736 }
14737
14738 // Are there only GTF_CALL side effects remaining? (and no other side effect kinds)
14739 if (flags & GTF_CALL)
14740 {
14741 if (tree->OperGet() == GT_CALL)
14742 {
14743 GenTreeCall* const call = tree->AsCall();
14744 const bool ignoreExceptions = (flags & GTF_EXCEPT) == 0;
14745 const bool ignoreCctors = (flags & GTF_IS_IN_CSE) != 0; // We can CSE helpers that run cctors.
14746 if (!call->HasSideEffects(this, ignoreExceptions, ignoreCctors))
14747 {
14748 // If this call is otherwise side effect free, check its arguments.
14749 for (GenTreeArgList* args = call->gtCallArgs; args != nullptr; args = args->Rest())
14750 {
14751 if (gtTreeHasSideEffects(args->Current(), flags))
14752 {
14753 return true;
14754 }
14755 }
14756 // I'm a little worried that args that assign to temps that are late args will look like
14757 // side effects...but better to be conservative for now.
14758 for (GenTreeArgList* args = call->gtCallLateArgs; args != nullptr; args = args->Rest())
14759 {
14760 if (gtTreeHasSideEffects(args->Current(), flags))
14761 {
14762 return true;
14763 }
14764 }
14765
14766 // Otherwise:
14767 return false;
14768 }
14769
14770 // Otherwise the GT_CALL is considered to have side-effects.
14771 return true;
14772 }
14773 }
14774
14775 if (flags & GTF_EXCEPT)
14776 {
14777 if (tree->OperMayThrow(this))
14778 {
14779 return true;
14780 }
14781 }
14782
14783 // Expressions declared as CSE by (e.g.) hoisting code are considered to have relevant side
14784 // effects (if we care about GTF_MAKE_CSE).
14785 if ((flags & GTF_MAKE_CSE) && (tree->gtFlags & GTF_MAKE_CSE))
14786 {
14787 return true;
14788 }
14789
14790 return false;
14791}
14792
14793/*****************************************************************************
14794 * Returns true if the expr tree has any side effects.
14795 */
14796
14797bool Compiler::gtTreeHasSideEffects(GenTree* tree, unsigned flags /* = GTF_SIDE_EFFECT*/)
14798{
14799 // These are the side effect flags that we care about for this tree
14800 unsigned sideEffectFlags = tree->gtFlags & flags;
14801
14802 // Does this tree have any Side-effect flags set that we care about?
14803 if (sideEffectFlags == 0)
14804 {
14805 // no it doesn't..
14806 return false;
14807 }
14808
14809 if (sideEffectFlags == GTF_CALL)
14810 {
14811 if (tree->OperGet() == GT_CALL)
14812 {
14813 // Generally all trees that contain GT_CALL nodes are considered to have side-effects.
14814 //
14815 if (tree->gtCall.gtCallType == CT_HELPER)
14816 {
14817 // If this node is a helper call we may not care about the side-effects.
14818 // Note that gtNodeHasSideEffects checks the side effects of the helper itself
14819 // as well as the side effects of its arguments.
14820 return gtNodeHasSideEffects(tree, flags);
14821 }
14822 }
14823 else if (tree->OperGet() == GT_INTRINSIC)
14824 {
14825 if (gtNodeHasSideEffects(tree, flags))
14826 {
14827 return true;
14828 }
14829
14830 if (gtNodeHasSideEffects(tree->gtOp.gtOp1, flags))
14831 {
14832 return true;
14833 }
14834
14835 if ((tree->gtOp.gtOp2 != nullptr) && gtNodeHasSideEffects(tree->gtOp.gtOp2, flags))
14836 {
14837 return true;
14838 }
14839
14840 return false;
14841 }
14842 }
14843
14844 return true;
14845}
14846
14847GenTree* Compiler::gtBuildCommaList(GenTree* list, GenTree* expr)
14848{
14849 // 'list' starts off as null,
14850 // and when it is null we haven't started the list yet.
14851 //
14852 if (list != nullptr)
14853 {
14854 // Create a GT_COMMA that appends 'expr' in front of the remaining set of expressions in (*list)
14855 GenTree* result = gtNewOperNode(GT_COMMA, TYP_VOID, expr, list);
14856
14857 // Set the flags in the comma node
14858 result->gtFlags |= (list->gtFlags & GTF_ALL_EFFECT);
14859 result->gtFlags |= (expr->gtFlags & GTF_ALL_EFFECT);
14860
14861 // 'list' and 'expr' should have valuenumbers defined for both or for neither one (unless we are remorphing,
14862 // in which case a prior transform involving either node may have discarded or otherwise invalidated the value
14863 // numbers).
14864 assert((list->gtVNPair.BothDefined() == expr->gtVNPair.BothDefined()) || !fgGlobalMorph);
14865
14866 // Set the ValueNumber 'gtVNPair' for the new GT_COMMA node
14867 //
14868 if (list->gtVNPair.BothDefined() && expr->gtVNPair.BothDefined())
14869 {
14870 // The result of a GT_COMMA node is op2, the normal value number is op2vnp
14871 // But we also need to include the union of side effects from op1 and op2.
14872 // we compute this value into exceptions_vnp.
14873 ValueNumPair op1vnp;
14874 ValueNumPair op1Xvnp = ValueNumStore::VNPForEmptyExcSet();
14875 ValueNumPair op2vnp;
14876 ValueNumPair op2Xvnp = ValueNumStore::VNPForEmptyExcSet();
14877
14878 vnStore->VNPUnpackExc(expr->gtVNPair, &op1vnp, &op1Xvnp);
14879 vnStore->VNPUnpackExc(list->gtVNPair, &op2vnp, &op2Xvnp);
14880
14881 ValueNumPair exceptions_vnp = ValueNumStore::VNPForEmptyExcSet();
14882
14883 exceptions_vnp = vnStore->VNPExcSetUnion(exceptions_vnp, op1Xvnp);
14884 exceptions_vnp = vnStore->VNPExcSetUnion(exceptions_vnp, op2Xvnp);
14885
14886 result->gtVNPair = vnStore->VNPWithExc(op2vnp, exceptions_vnp);
14887 }
14888
14889 return result;
14890 }
14891 else
14892 {
14893 // The 'expr' will start the list of expressions
14894 return expr;
14895 }
14896}
14897
14898//------------------------------------------------------------------------
14899// gtExtractSideEffList: Extracts side effects from the given expression.
14900//
14901// Arguments:
14902// expr - the expression tree to extract side effects from
14903// pList - pointer to a (possibly null) GT_COMMA list that
14904// will contain the extracted side effects
14905// flags - side effect flags to be considered
14906// ignoreRoot - ignore side effects on the expression root node
14907//
14908// Notes:
14909// Side effects are prepended to the GT_COMMA list such that op1 of
14910// each comma node holds the side effect tree and op2 points to the
14911// next comma node. The original side effect execution order is preserved.
14912//
14913void Compiler::gtExtractSideEffList(GenTree* expr,
14914 GenTree** pList,
14915 unsigned flags /* = GTF_SIDE_EFFECT*/,
14916 bool ignoreRoot /* = false */)
14917{
14918 class SideEffectExtractor final : public GenTreeVisitor<SideEffectExtractor>
14919 {
14920 public:
14921 const unsigned m_flags;
14922 ArrayStack<GenTree*> m_sideEffects;
14923
14924 enum
14925 {
14926 DoPreOrder = true,
14927 UseExecutionOrder = true
14928 };
14929
14930 SideEffectExtractor(Compiler* compiler, unsigned flags)
14931 : GenTreeVisitor(compiler), m_flags(flags), m_sideEffects(compiler->getAllocator(CMK_SideEffects))
14932 {
14933 }
14934
14935 fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
14936 {
14937 GenTree* node = *use;
14938
14939 bool treeHasSideEffects = m_compiler->gtTreeHasSideEffects(node, m_flags);
14940
14941 if (treeHasSideEffects)
14942 {
14943 if (m_compiler->gtNodeHasSideEffects(node, m_flags))
14944 {
14945 m_sideEffects.Push(node);
14946 return Compiler::WALK_SKIP_SUBTREES;
14947 }
14948
14949 // TODO-Cleanup: These have GTF_ASG set but for some reason gtNodeHasSideEffects ignores
14950 // them. See the related gtNodeHasSideEffects comment as well.
14951 // Also, these nodes must always be preserved, no matter what side effect flags are passed
14952 // in. But then it should never be the case that gtExtractSideEffList gets called without
14953 // specifying GTF_ASG so there doesn't seem to be any reason to be inconsistent with
14954 // gtNodeHasSideEffects and make this check unconditionally.
14955 if (node->OperIsAtomicOp())
14956 {
14957 m_sideEffects.Push(node);
14958 return Compiler::WALK_SKIP_SUBTREES;
14959 }
14960
14961 if ((m_flags & GTF_EXCEPT) != 0)
14962 {
14963 // Special case - GT_ADDR of GT_IND nodes of TYP_STRUCT have to be kept together.
14964 if (node->OperIs(GT_ADDR) && node->gtGetOp1()->OperIsIndir() &&
14965 (node->gtGetOp1()->TypeGet() == TYP_STRUCT))
14966 {
14967#ifdef DEBUG
14968 if (m_compiler->verbose)
14969 {
14970 printf("Keep the GT_ADDR and GT_IND together:\n");
14971 }
14972#endif
14973 m_sideEffects.Push(node);
14974 return Compiler::WALK_SKIP_SUBTREES;
14975 }
14976 }
14977
14978 // Generally all GT_CALL nodes are considered to have side-effects.
14979 // So if we get here it must be a helper call that we decided it does
14980 // not have side effects that we needed to keep.
14981 assert(!node->OperIs(GT_CALL) || (node->AsCall()->gtCallType == CT_HELPER));
14982 }
14983
14984 if ((m_flags & GTF_IS_IN_CSE) != 0)
14985 {
14986 // If we're doing CSE then we also need to unmark CSE nodes. This will fail for CSE defs,
14987 // those need to be extracted as if they're side effects.
14988 if (!UnmarkCSE(node))
14989 {
14990 m_sideEffects.Push(node);
14991 return Compiler::WALK_SKIP_SUBTREES;
14992 }
14993
14994 // The existence of CSE defs and uses is not propagated up the tree like side
14995 // effects are. We need to continue visiting the tree as if it has side effects.
14996 treeHasSideEffects = true;
14997 }
14998
14999 return treeHasSideEffects ? Compiler::WALK_CONTINUE : Compiler::WALK_SKIP_SUBTREES;
15000 }
15001
15002 private:
15003 bool UnmarkCSE(GenTree* node)
15004 {
15005 assert(m_compiler->optValnumCSE_phase);
15006
15007 if (m_compiler->optUnmarkCSE(node))
15008 {
15009 // The call to optUnmarkCSE(node) should have cleared any CSE info.
15010 assert(!IS_CSE_INDEX(node->gtCSEnum));
15011 return true;
15012 }
15013 else
15014 {
15015 assert(IS_CSE_DEF(node->gtCSEnum));
15016#ifdef DEBUG
15017 if (m_compiler->verbose)
15018 {
15019 printf("Preserving the CSE def #%02d at ", GET_CSE_INDEX(node->gtCSEnum));
15020 m_compiler->printTreeID(node);
15021 }
15022#endif
15023 return false;
15024 }
15025 }
15026 };
15027
15028 assert(!expr->OperIs(GT_STMT));
15029
15030 SideEffectExtractor extractor(this, flags);
15031
15032 if (ignoreRoot)
15033 {
15034 for (GenTree* op : expr->Operands())
15035 {
15036 extractor.WalkTree(&op, nullptr);
15037 }
15038 }
15039 else
15040 {
15041 extractor.WalkTree(&expr, nullptr);
15042 }
15043
15044 GenTree* list = *pList;
15045
15046 // The extractor returns side effects in execution order but gtBuildCommaList prepends
15047 // to the comma-based side effect list so we have to build the list in reverse order.
15048 // This is also why the list cannot be built while traversing the tree.
15049 // The number of side effects is usually small (<= 4), less than the ArrayStack's
15050 // built-in size, so memory allocation is avoided.
15051 while (!extractor.m_sideEffects.Empty())
15052 {
15053 list = gtBuildCommaList(list, extractor.m_sideEffects.Pop());
15054 }
15055
15056 *pList = list;
15057}
15058
15059/*****************************************************************************
15060 *
15061 * For debugging only - displays a tree node list and makes sure all the
15062 * links are correctly set.
15063 */
15064
15065#ifdef DEBUG
15066
15067void dispNodeList(GenTree* list, bool verbose)
15068{
15069 GenTree* last = nullptr;
15070 GenTree* next;
15071
15072 if (!list)
15073 {
15074 return;
15075 }
15076
15077 for (;;)
15078 {
15079 next = list->gtNext;
15080
15081 if (verbose)
15082 {
15083 printf("%08X -> %08X -> %08X\n", last, list, next);
15084 }
15085
15086 assert(!last || last->gtNext == list);
15087
15088 assert(next == nullptr || next->gtPrev == list);
15089
15090 if (!next)
15091 {
15092 break;
15093 }
15094
15095 last = list;
15096 list = next;
15097 }
15098 printf(""); // null string means flush
15099}
15100
15101/*****************************************************************************
15102 * Callback to assert that the nodes of a qmark-colon subtree are marked
15103 */
15104
15105/* static */
15106Compiler::fgWalkResult Compiler::gtAssertColonCond(GenTree** pTree, fgWalkData* data)
15107{
15108 assert(data->pCallbackData == nullptr);
15109
15110 assert((*pTree)->gtFlags & GTF_COLON_COND);
15111
15112 return WALK_CONTINUE;
15113}
15114#endif // DEBUG
15115
15116/*****************************************************************************
15117 * Callback to mark the nodes of a qmark-colon subtree that are conditionally
15118 * executed.
15119 */
15120
15121/* static */
15122Compiler::fgWalkResult Compiler::gtMarkColonCond(GenTree** pTree, fgWalkData* data)
15123{
15124 assert(data->pCallbackData == nullptr);
15125
15126 (*pTree)->gtFlags |= GTF_COLON_COND;
15127
15128 return WALK_CONTINUE;
15129}
15130
15131/*****************************************************************************
15132 * Callback to clear the conditionally executed flags of nodes that no longer
15133 will be conditionally executed. Note that when we find another colon we must
15134 stop, as the nodes below this one WILL be conditionally executed. This callback
15135 is called when folding a qmark condition (ie the condition is constant).
15136 */
15137
15138/* static */
15139Compiler::fgWalkResult Compiler::gtClearColonCond(GenTree** pTree, fgWalkData* data)
15140{
15141 GenTree* tree = *pTree;
15142
15143 assert(data->pCallbackData == nullptr);
15144
15145 if (tree->OperGet() == GT_COLON)
15146 {
15147 // Nodes below this will be conditionally executed.
15148 return WALK_SKIP_SUBTREES;
15149 }
15150
15151 tree->gtFlags &= ~GTF_COLON_COND;
15152 return WALK_CONTINUE;
15153}
15154
15155struct FindLinkData
15156{
15157 GenTree* nodeToFind;
15158 GenTree** result;
15159};
15160
15161/*****************************************************************************
15162 *
15163 * Callback used by the tree walker to implement fgFindLink()
15164 */
15165static Compiler::fgWalkResult gtFindLinkCB(GenTree** pTree, Compiler::fgWalkData* cbData)
15166{
15167 FindLinkData* data = (FindLinkData*)cbData->pCallbackData;
15168 if (*pTree == data->nodeToFind)
15169 {
15170 data->result = pTree;
15171 return Compiler::WALK_ABORT;
15172 }
15173
15174 return Compiler::WALK_CONTINUE;
15175}
15176
15177GenTree** Compiler::gtFindLink(GenTree* stmt, GenTree* node)
15178{
15179 assert(stmt->gtOper == GT_STMT);
15180
15181 FindLinkData data = {node, nullptr};
15182
15183 fgWalkResult result = fgWalkTreePre(&stmt->gtStmt.gtStmtExpr, gtFindLinkCB, &data);
15184
15185 if (result == WALK_ABORT)
15186 {
15187 assert(data.nodeToFind == *data.result);
15188 return data.result;
15189 }
15190 else
15191 {
15192 return nullptr;
15193 }
15194}
15195
15196/*****************************************************************************
15197 *
15198 * Callback that checks if a tree node has oper type GT_CATCH_ARG
15199 */
15200
15201static Compiler::fgWalkResult gtFindCatchArg(GenTree** pTree, Compiler::fgWalkData* /* data */)
15202{
15203 return ((*pTree)->OperGet() == GT_CATCH_ARG) ? Compiler::WALK_ABORT : Compiler::WALK_CONTINUE;
15204}
15205
15206/*****************************************************************************/
15207bool Compiler::gtHasCatchArg(GenTree* tree)
15208{
15209 if (((tree->gtFlags & GTF_ORDER_SIDEEFF) != 0) && (fgWalkTreePre(&tree, gtFindCatchArg) == WALK_ABORT))
15210 {
15211 return true;
15212 }
15213 return false;
15214}
15215
15216//------------------------------------------------------------------------
15217// gtHasCallOnStack:
15218//
15219// Arguments:
15220// parentStack: a context (stack of parent nodes)
15221//
15222// Return Value:
15223// returns true if any of the parent nodes are a GT_CALL
15224//
15225// Assumptions:
15226// We have a stack of parent nodes. This generally requires that
15227// we are performing a recursive tree walk using struct fgWalkData
15228//
15229//------------------------------------------------------------------------
15230/* static */ bool Compiler::gtHasCallOnStack(GenTreeStack* parentStack)
15231{
15232 for (int i = 0; i < parentStack->Height(); i++)
15233 {
15234 GenTree* node = parentStack->Index(i);
15235 if (node->OperGet() == GT_CALL)
15236 {
15237 return true;
15238 }
15239 }
15240 return false;
15241}
15242
15243//------------------------------------------------------------------------
15244// gtGetTypeProducerKind: determine if a tree produces a runtime type, and
15245// if so, how.
15246//
15247// Arguments:
15248// tree - tree to examine
15249//
15250// Return Value:
15251// TypeProducerKind for the tree.
15252//
15253// Notes:
15254// Checks to see if this tree returns a RuntimeType value, and if so,
15255// how that value is determined.
15256//
15257// Currently handles these cases
15258// 1) The result of Object::GetType
15259// 2) The result of typeof(...)
15260// 3) A null reference
15261// 4) Tree is otherwise known to have type RuntimeType
15262//
15263// The null reference case is surprisingly common because operator
15264// overloading turns the otherwise innocuous
15265//
15266// Type t = ....;
15267// if (t == null)
15268//
15269// into a method call.
15270
15271Compiler::TypeProducerKind Compiler::gtGetTypeProducerKind(GenTree* tree)
15272{
15273 if (tree->gtOper == GT_CALL)
15274 {
15275 if (tree->gtCall.gtCallType == CT_HELPER)
15276 {
15277 if (gtIsTypeHandleToRuntimeTypeHelper(tree->AsCall()))
15278 {
15279 return TPK_Handle;
15280 }
15281 }
15282 else if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC)
15283 {
15284 if (info.compCompHnd->getIntrinsicID(tree->gtCall.gtCallMethHnd) == CORINFO_INTRINSIC_Object_GetType)
15285 {
15286 return TPK_GetType;
15287 }
15288 }
15289 }
15290 else if ((tree->gtOper == GT_INTRINSIC) && (tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType))
15291 {
15292 return TPK_GetType;
15293 }
15294 else if ((tree->gtOper == GT_CNS_INT) && (tree->gtIntCon.gtIconVal == 0))
15295 {
15296 return TPK_Null;
15297 }
15298 else
15299 {
15300 bool isExact = false;
15301 bool isNonNull = false;
15302 CORINFO_CLASS_HANDLE clsHnd = gtGetClassHandle(tree, &isExact, &isNonNull);
15303
15304 if (clsHnd != NO_CLASS_HANDLE && clsHnd == info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE))
15305 {
15306 return TPK_Other;
15307 }
15308 }
15309 return TPK_Unknown;
15310}
15311
15312//------------------------------------------------------------------------
15313// gtIsTypeHandleToRuntimeTypeHelperCall -- see if tree is constructing
15314// a RuntimeType from a handle
15315//
15316// Arguments:
15317// tree - tree to examine
15318//
15319// Return Value:
15320// True if so
15321
15322bool Compiler::gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call)
15323{
15324 return call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE) ||
15325 call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL);
15326}
15327
15328//------------------------------------------------------------------------
15329// gtIsTypeHandleToRuntimeTypeHandleHelperCall -- see if tree is constructing
15330// a RuntimeTypeHandle from a handle
15331//
15332// Arguments:
15333// tree - tree to examine
15334// pHelper - optional pointer to a variable that receives the type of the helper
15335//
15336// Return Value:
15337// True if so
15338
15339bool Compiler::gtIsTypeHandleToRuntimeTypeHandleHelper(GenTreeCall* call, CorInfoHelpFunc* pHelper)
15340{
15341 CorInfoHelpFunc helper = CORINFO_HELP_UNDEF;
15342
15343 if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE))
15344 {
15345 helper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE;
15346 }
15347 else if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL))
15348 {
15349 helper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL;
15350 }
15351
15352 if (pHelper != nullptr)
15353 {
15354 *pHelper = helper;
15355 }
15356
15357 return helper != CORINFO_HELP_UNDEF;
15358}
15359
15360bool Compiler::gtIsActiveCSE_Candidate(GenTree* tree)
15361{
15362 return (optValnumCSE_phase && IS_CSE_INDEX(tree->gtCSEnum));
15363}
15364
15365/*****************************************************************************/
15366
15367struct ComplexityStruct
15368{
15369 unsigned m_numNodes;
15370 unsigned m_nodeLimit;
15371 ComplexityStruct(unsigned nodeLimit) : m_numNodes(0), m_nodeLimit(nodeLimit)
15372 {
15373 }
15374};
15375
15376static Compiler::fgWalkResult ComplexityExceedsWalker(GenTree** pTree, Compiler::fgWalkData* data)
15377{
15378 ComplexityStruct* pComplexity = (ComplexityStruct*)data->pCallbackData;
15379 if (++pComplexity->m_numNodes > pComplexity->m_nodeLimit)
15380 {
15381 return Compiler::WALK_ABORT;
15382 }
15383 else
15384 {
15385 return Compiler::WALK_CONTINUE;
15386 }
15387}
15388
15389bool Compiler::gtComplexityExceeds(GenTree** tree, unsigned limit)
15390{
15391 ComplexityStruct complexity(limit);
15392 if (fgWalkTreePre(tree, &ComplexityExceedsWalker, &complexity) == WALK_ABORT)
15393 {
15394 return true;
15395 }
15396 else
15397 {
15398 return false;
15399 }
15400}
15401
15402bool GenTree::IsPhiNode()
15403{
15404 return (OperGet() == GT_PHI_ARG) || (OperGet() == GT_PHI) || IsPhiDefn();
15405}
15406
15407bool GenTree::IsPhiDefn()
15408{
15409 bool res = ((OperGet() == GT_ASG) && (gtOp.gtOp2 != nullptr) && (gtOp.gtOp2->OperGet() == GT_PHI)) ||
15410 ((OperGet() == GT_STORE_LCL_VAR) && (gtOp.gtOp1 != nullptr) && (gtOp.gtOp1->OperGet() == GT_PHI));
15411 assert(!res || OperGet() == GT_STORE_LCL_VAR || gtOp.gtOp1->OperGet() == GT_LCL_VAR);
15412 return res;
15413}
15414
15415bool GenTree::IsPhiDefnStmt()
15416{
15417 if (OperGet() != GT_STMT)
15418 {
15419 return false;
15420 }
15421 GenTree* asg = gtStmt.gtStmtExpr;
15422 return asg->IsPhiDefn();
15423}
15424
15425// IsPartialLclFld: Check for a GT_LCL_FLD whose type is a different size than the lclVar.
15426//
15427// Arguments:
15428// comp - the Compiler object.
15429//
15430// Return Value:
15431// Returns "true" iff 'this' is a GT_LCL_FLD or GT_STORE_LCL_FLD on which the type
15432// is not the same size as the type of the GT_LCL_VAR
15433
15434bool GenTree::IsPartialLclFld(Compiler* comp)
15435{
15436 return ((gtOper == GT_LCL_FLD) &&
15437 (comp->lvaTable[this->gtLclVarCommon.gtLclNum].lvExactSize != genTypeSize(gtType)));
15438}
15439
15440bool GenTree::DefinesLocal(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, bool* pIsEntire)
15441{
15442 GenTreeBlk* blkNode = nullptr;
15443 if (OperIs(GT_ASG))
15444 {
15445 if (gtOp.gtOp1->IsLocal())
15446 {
15447 GenTreeLclVarCommon* lclVarTree = gtOp.gtOp1->AsLclVarCommon();
15448 *pLclVarTree = lclVarTree;
15449 if (pIsEntire != nullptr)
15450 {
15451 if (lclVarTree->IsPartialLclFld(comp))
15452 {
15453 *pIsEntire = false;
15454 }
15455 else
15456 {
15457 *pIsEntire = true;
15458 }
15459 }
15460 return true;
15461 }
15462 else if (gtOp.gtOp1->OperGet() == GT_IND)
15463 {
15464 GenTree* indArg = gtOp.gtOp1->gtOp.gtOp1;
15465 return indArg->DefinesLocalAddr(comp, genTypeSize(gtOp.gtOp1->TypeGet()), pLclVarTree, pIsEntire);
15466 }
15467 else if (gtOp.gtOp1->OperIsBlk())
15468 {
15469 blkNode = gtOp.gtOp1->AsBlk();
15470 }
15471 }
15472 else if (OperIsBlk())
15473 {
15474 blkNode = this->AsBlk();
15475 }
15476 if (blkNode != nullptr)
15477 {
15478 GenTree* destAddr = blkNode->Addr();
15479 unsigned width = blkNode->gtBlkSize;
15480 // Do we care about whether this assigns the entire variable?
15481 if (pIsEntire != nullptr && width == 0)
15482 {
15483 assert(blkNode->gtOper == GT_DYN_BLK);
15484 GenTree* blockWidth = blkNode->AsDynBlk()->gtDynamicSize;
15485 if (blockWidth->IsCnsIntOrI())
15486 {
15487 if (blockWidth->IsIconHandle())
15488 {
15489 // If it's a handle, it must be a class handle. We only create such block operations
15490 // for initialization of struct types, so the type of the argument(s) will match this
15491 // type, by construction, and be "entire".
15492 assert(blockWidth->IsIconHandle(GTF_ICON_CLASS_HDL));
15493 width = comp->info.compCompHnd->getClassSize(
15494 CORINFO_CLASS_HANDLE(blockWidth->gtIntConCommon.IconValue()));
15495 }
15496 else
15497 {
15498 ssize_t swidth = blockWidth->AsIntConCommon()->IconValue();
15499 assert(swidth >= 0);
15500 // cpblk of size zero exists in the wild (in yacc-generated code in SQL) and is valid IL.
15501 if (swidth == 0)
15502 {
15503 return false;
15504 }
15505 width = unsigned(swidth);
15506 }
15507 }
15508 }
15509 return destAddr->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
15510 }
15511 // Otherwise...
15512 return false;
15513}
15514
15515// Returns true if this GenTree defines a result which is based on the address of a local.
15516bool GenTree::DefinesLocalAddr(Compiler* comp, unsigned width, GenTreeLclVarCommon** pLclVarTree, bool* pIsEntire)
15517{
15518 if (OperGet() == GT_ADDR || OperGet() == GT_LCL_VAR_ADDR)
15519 {
15520 GenTree* addrArg = this;
15521 if (OperGet() == GT_ADDR)
15522 {
15523 addrArg = gtOp.gtOp1;
15524 }
15525
15526 if (addrArg->IsLocal() || addrArg->OperIsLocalAddr())
15527 {
15528 GenTreeLclVarCommon* addrArgLcl = addrArg->AsLclVarCommon();
15529 *pLclVarTree = addrArgLcl;
15530 if (pIsEntire != nullptr)
15531 {
15532 unsigned lclOffset = 0;
15533 if (addrArg->OperIsLocalField())
15534 {
15535 lclOffset = addrArg->gtLclFld.gtLclOffs;
15536 }
15537
15538 if (lclOffset != 0)
15539 {
15540 // We aren't updating the bytes at [0..lclOffset-1] so *pIsEntire should be set to false
15541 *pIsEntire = false;
15542 }
15543 else
15544 {
15545 unsigned lclNum = addrArgLcl->GetLclNum();
15546 unsigned varWidth = comp->lvaLclExactSize(lclNum);
15547 if (comp->lvaTable[lclNum].lvNormalizeOnStore())
15548 {
15549 // It's normalize on store, so use the full storage width -- writing to low bytes won't
15550 // necessarily yield a normalized value.
15551 varWidth = genTypeStSz(var_types(comp->lvaTable[lclNum].lvType)) * sizeof(int);
15552 }
15553 *pIsEntire = (varWidth == width);
15554 }
15555 }
15556 return true;
15557 }
15558 else if (addrArg->OperGet() == GT_IND)
15559 {
15560 // A GT_ADDR of a GT_IND can both be optimized away, recurse using the child of the GT_IND
15561 return addrArg->gtOp.gtOp1->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
15562 }
15563 }
15564 else if (OperGet() == GT_ADD)
15565 {
15566 if (gtOp.gtOp1->IsCnsIntOrI())
15567 {
15568 // If we just adding a zero then we allow an IsEntire match against width
15569 // otherwise we change width to zero to disallow an IsEntire Match
15570 return gtOp.gtOp2->DefinesLocalAddr(comp, gtOp.gtOp1->IsIntegralConst(0) ? width : 0, pLclVarTree,
15571 pIsEntire);
15572 }
15573 else if (gtOp.gtOp2->IsCnsIntOrI())
15574 {
15575 // If we just adding a zero then we allow an IsEntire match against width
15576 // otherwise we change width to zero to disallow an IsEntire Match
15577 return gtOp.gtOp1->DefinesLocalAddr(comp, gtOp.gtOp2->IsIntegralConst(0) ? width : 0, pLclVarTree,
15578 pIsEntire);
15579 }
15580 }
15581 // Post rationalization we could have GT_IND(GT_LEA(..)) trees.
15582 else if (OperGet() == GT_LEA)
15583 {
15584 // This method gets invoked during liveness computation and therefore it is critical
15585 // that we don't miss 'use' of any local. The below logic is making the assumption
15586 // that in case of LEA(base, index, offset) - only base can be a GT_LCL_VAR_ADDR
15587 // and index is not.
15588 CLANG_FORMAT_COMMENT_ANCHOR;
15589
15590#ifdef DEBUG
15591 GenTree* index = gtOp.gtOp2;
15592 if (index != nullptr)
15593 {
15594 assert(!index->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire));
15595 }
15596#endif // DEBUG
15597
15598 // base
15599 GenTree* base = gtOp.gtOp1;
15600 if (base != nullptr)
15601 {
15602 // Lea could have an Indir as its base.
15603 if (base->OperGet() == GT_IND)
15604 {
15605 base = base->gtOp.gtOp1->gtEffectiveVal(/*commas only*/ true);
15606 }
15607 return base->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire);
15608 }
15609 }
15610 // Otherwise...
15611 return false;
15612}
15613
15614//------------------------------------------------------------------------
15615// IsLocalExpr: Determine if this is a LclVarCommon node and return some
15616// additional info about it in the two out parameters.
15617//
15618// Arguments:
15619// comp - The Compiler instance
15620// pLclVarTree - An "out" argument that returns the local tree as a
15621// LclVarCommon, if it is indeed local.
15622// pFldSeq - An "out" argument that returns the value numbering field
15623// sequence for the node, if any.
15624//
15625// Return Value:
15626// Returns true, and sets the out arguments accordingly, if this is
15627// a LclVarCommon node.
15628
15629bool GenTree::IsLocalExpr(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, FieldSeqNode** pFldSeq)
15630{
15631 if (IsLocal()) // Note that this covers "GT_LCL_FLD."
15632 {
15633 *pLclVarTree = AsLclVarCommon();
15634 if (OperGet() == GT_LCL_FLD)
15635 {
15636 // Otherwise, prepend this field to whatever we've already accumulated outside in.
15637 *pFldSeq = comp->GetFieldSeqStore()->Append(AsLclFld()->gtFieldSeq, *pFldSeq);
15638 }
15639 return true;
15640 }
15641 else
15642 {
15643 return false;
15644 }
15645}
15646
15647// If this tree evaluates some sum of a local address and some constants,
15648// return the node for the local being addressed
15649
15650GenTreeLclVarCommon* GenTree::IsLocalAddrExpr()
15651{
15652 if (OperGet() == GT_ADDR)
15653 {
15654 return gtOp.gtOp1->IsLocal() ? gtOp.gtOp1->AsLclVarCommon() : nullptr;
15655 }
15656 else if (OperIsLocalAddr())
15657 {
15658 return this->AsLclVarCommon();
15659 }
15660 else if (OperGet() == GT_ADD)
15661 {
15662 if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
15663 {
15664 return gtOp.gtOp2->IsLocalAddrExpr();
15665 }
15666 else if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
15667 {
15668 return gtOp.gtOp1->IsLocalAddrExpr();
15669 }
15670 }
15671 // Otherwise...
15672 return nullptr;
15673}
15674
15675bool GenTree::IsLocalAddrExpr(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, FieldSeqNode** pFldSeq)
15676{
15677 if (OperGet() == GT_ADDR)
15678 {
15679 assert(!comp->compRationalIRForm);
15680 GenTree* addrArg = gtOp.gtOp1;
15681 if (addrArg->IsLocal()) // Note that this covers "GT_LCL_FLD."
15682 {
15683 *pLclVarTree = addrArg->AsLclVarCommon();
15684 if (addrArg->OperGet() == GT_LCL_FLD)
15685 {
15686 // Otherwise, prepend this field to whatever we've already accumulated outside in.
15687 *pFldSeq = comp->GetFieldSeqStore()->Append(addrArg->AsLclFld()->gtFieldSeq, *pFldSeq);
15688 }
15689 return true;
15690 }
15691 else
15692 {
15693 return false;
15694 }
15695 }
15696 else if (OperIsLocalAddr())
15697 {
15698 *pLclVarTree = this->AsLclVarCommon();
15699 if (this->OperGet() == GT_LCL_FLD_ADDR)
15700 {
15701 *pFldSeq = comp->GetFieldSeqStore()->Append(this->AsLclFld()->gtFieldSeq, *pFldSeq);
15702 }
15703 return true;
15704 }
15705 else if (OperGet() == GT_ADD)
15706 {
15707 if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
15708 {
15709 if (gtOp.gtOp1->AsIntCon()->gtFieldSeq == nullptr)
15710 {
15711 return false;
15712 }
15713 // Otherwise, prepend this field to whatever we've already accumulated outside in.
15714 *pFldSeq = comp->GetFieldSeqStore()->Append(gtOp.gtOp1->AsIntCon()->gtFieldSeq, *pFldSeq);
15715 return gtOp.gtOp2->IsLocalAddrExpr(comp, pLclVarTree, pFldSeq);
15716 }
15717 else if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
15718 {
15719 if (gtOp.gtOp2->AsIntCon()->gtFieldSeq == nullptr)
15720 {
15721 return false;
15722 }
15723 // Otherwise, prepend this field to whatever we've already accumulated outside in.
15724 *pFldSeq = comp->GetFieldSeqStore()->Append(gtOp.gtOp2->AsIntCon()->gtFieldSeq, *pFldSeq);
15725 return gtOp.gtOp1->IsLocalAddrExpr(comp, pLclVarTree, pFldSeq);
15726 }
15727 }
15728 // Otherwise...
15729 return false;
15730}
15731
15732//------------------------------------------------------------------------
15733// IsLclVarUpdateTree: Determine whether this is an assignment tree of the
15734// form Vn = Vn 'oper' 'otherTree' where Vn is a lclVar
15735//
15736// Arguments:
15737// pOtherTree - An "out" argument in which 'otherTree' will be returned.
15738// pOper - An "out" argument in which 'oper' will be returned.
15739//
15740// Return Value:
15741// If the tree is of the above form, the lclNum of the variable being
15742// updated is returned, and 'pOtherTree' and 'pOper' are set.
15743// Otherwise, returns BAD_VAR_NUM.
15744//
15745// Notes:
15746// 'otherTree' can have any shape.
15747// We avoid worrying about whether the op is commutative by only considering the
15748// first operand of the rhs. It is expected that most trees of this form will
15749// already have the lclVar on the lhs.
15750// TODO-CQ: Evaluate whether there are missed opportunities due to this, or
15751// whether gtSetEvalOrder will already have put the lclVar on the lhs in
15752// the cases of interest.
15753
15754unsigned GenTree::IsLclVarUpdateTree(GenTree** pOtherTree, genTreeOps* pOper)
15755{
15756 unsigned lclNum = BAD_VAR_NUM;
15757 if (OperIs(GT_ASG))
15758 {
15759 GenTree* lhs = gtOp.gtOp1;
15760 if (lhs->OperGet() == GT_LCL_VAR)
15761 {
15762 unsigned lhsLclNum = lhs->AsLclVarCommon()->gtLclNum;
15763 GenTree* rhs = gtOp.gtOp2;
15764 if (rhs->OperIsBinary() && (rhs->gtOp.gtOp1->gtOper == GT_LCL_VAR) &&
15765 (rhs->gtOp.gtOp1->AsLclVarCommon()->gtLclNum == lhsLclNum))
15766 {
15767 lclNum = lhsLclNum;
15768 *pOtherTree = rhs->gtOp.gtOp2;
15769 *pOper = rhs->gtOper;
15770 }
15771 }
15772 }
15773 return lclNum;
15774}
15775
15776//------------------------------------------------------------------------
15777// canBeContained: check whether this tree node may be a subcomponent of its parent for purposes
15778// of code generation.
15779//
15780// Return value: returns true if it is possible to contain this node and false otherwise.
15781bool GenTree::canBeContained() const
15782{
15783 assert(IsLIR());
15784
15785 if (gtHasReg())
15786 {
15787 return false;
15788 }
15789
15790 // It is not possible for nodes that do not produce values or that are not containable values
15791 // to be contained.
15792 if (((OperKind() & (GTK_NOVALUE | GTK_NOCONTAIN)) != 0) || (OperIsHWIntrinsic() && !isContainableHWIntrinsic()))
15793 {
15794 return false;
15795 }
15796
15797 return true;
15798}
15799
15800//------------------------------------------------------------------------
15801// isContained: check whether this tree node is a subcomponent of its parent for codegen purposes
15802//
15803// Return Value:
15804// Returns true if there is no code generated explicitly for this node.
15805// Essentially, it will be rolled into the code generation for the parent.
15806//
15807// Assumptions:
15808// This method relies upon the value of the GTF_CONTAINED flag.
15809// Therefore this method is only valid after Lowering.
15810// Also note that register allocation or other subsequent phases may cause
15811// nodes to become contained (or not) and therefore this property may change.
15812//
15813bool GenTree::isContained() const
15814{
15815 assert(IsLIR());
15816 const bool isMarkedContained = ((gtFlags & GTF_CONTAINED) != 0);
15817
15818#ifdef DEBUG
15819 if (!canBeContained())
15820 {
15821 assert(!isMarkedContained);
15822 }
15823
15824 // these actually produce a register (the flags reg, we just don't model it)
15825 // and are a separate instruction from the branch that consumes the result.
15826 // They can only produce a result if the child is a SIMD equality comparison.
15827 else if (OperKind() & GTK_RELOP)
15828 {
15829 // We have to cast away const-ness since AsOp() method is non-const.
15830 GenTree* childNode = const_cast<GenTree*>(this)->AsOp()->gtOp1;
15831 assert((isMarkedContained == false) || childNode->IsSIMDEqualityOrInequality());
15832 }
15833
15834 // these either produce a result in register or set flags reg.
15835 else if (IsSIMDEqualityOrInequality())
15836 {
15837 assert(!isMarkedContained);
15838 }
15839
15840 // if it's contained it can't be unused.
15841 if (isMarkedContained)
15842 {
15843 assert(!IsUnusedValue());
15844 }
15845#endif // DEBUG
15846 return isMarkedContained;
15847}
15848
15849// return true if node is contained and an indir
15850bool GenTree::isContainedIndir() const
15851{
15852 return isIndir() && isContained();
15853}
15854
15855bool GenTree::isIndirAddrMode()
15856{
15857 return isIndir() && AsIndir()->Addr()->OperIsAddrMode() && AsIndir()->Addr()->isContained();
15858}
15859
15860bool GenTree::isIndir() const
15861{
15862 return OperGet() == GT_IND || OperGet() == GT_STOREIND;
15863}
15864
15865bool GenTreeIndir::HasBase()
15866{
15867 return Base() != nullptr;
15868}
15869
15870bool GenTreeIndir::HasIndex()
15871{
15872 return Index() != nullptr;
15873}
15874
15875GenTree* GenTreeIndir::Base()
15876{
15877 GenTree* addr = Addr();
15878
15879 if (isIndirAddrMode())
15880 {
15881 GenTree* result = addr->AsAddrMode()->Base();
15882 if (result != nullptr)
15883 {
15884 result = result->gtEffectiveVal();
15885 }
15886 return result;
15887 }
15888 else
15889 {
15890 return addr; // TODO: why do we return 'addr' here, but we return 'nullptr' in the equivalent Index() case?
15891 }
15892}
15893
15894GenTree* GenTreeIndir::Index()
15895{
15896 if (isIndirAddrMode())
15897 {
15898 GenTree* result = Addr()->AsAddrMode()->Index();
15899 if (result != nullptr)
15900 {
15901 result = result->gtEffectiveVal();
15902 }
15903 return result;
15904 }
15905 else
15906 {
15907 return nullptr;
15908 }
15909}
15910
15911unsigned GenTreeIndir::Scale()
15912{
15913 if (HasIndex())
15914 {
15915 return Addr()->AsAddrMode()->gtScale;
15916 }
15917 else
15918 {
15919 return 1;
15920 }
15921}
15922
15923ssize_t GenTreeIndir::Offset()
15924{
15925 if (isIndirAddrMode())
15926 {
15927 return Addr()->AsAddrMode()->Offset();
15928 }
15929 else if (Addr()->gtOper == GT_CLS_VAR_ADDR)
15930 {
15931 return static_cast<ssize_t>(reinterpret_cast<intptr_t>(Addr()->gtClsVar.gtClsVarHnd));
15932 }
15933 else if (Addr()->IsCnsIntOrI() && Addr()->isContained())
15934 {
15935 return Addr()->AsIntConCommon()->IconValue();
15936 }
15937 else
15938 {
15939 return 0;
15940 }
15941}
15942
15943//------------------------------------------------------------------------
15944// GenTreeIntConCommon::ImmedValNeedsReloc: does this immediate value needs recording a relocation with the VM?
15945//
15946// Arguments:
15947// comp - Compiler instance
15948//
15949// Return Value:
15950// True if this immediate value requires us to record a relocation for it; false otherwise.
15951
15952bool GenTreeIntConCommon::ImmedValNeedsReloc(Compiler* comp)
15953{
15954 return comp->opts.compReloc && (gtOper == GT_CNS_INT) && IsIconHandle();
15955}
15956
15957//------------------------------------------------------------------------
15958// ImmedValCanBeFolded: can this immediate value be folded for op?
15959//
15960// Arguments:
15961// comp - Compiler instance
15962// op - Tree operator
15963//
15964// Return Value:
15965// True if this immediate value can be folded for op; false otherwise.
15966
15967bool GenTreeIntConCommon::ImmedValCanBeFolded(Compiler* comp, genTreeOps op)
15968{
15969 // In general, immediate values that need relocations can't be folded.
15970 // There are cases where we do want to allow folding of handle comparisons
15971 // (e.g., typeof(T) == typeof(int)).
15972 return !ImmedValNeedsReloc(comp) || (op == GT_EQ) || (op == GT_NE);
15973}
15974
15975#ifdef _TARGET_AMD64_
15976// Returns true if this absolute address fits within the base of an addr mode.
15977// On Amd64 this effectively means, whether an absolute indirect address can
15978// be encoded as 32-bit offset relative to IP or zero.
15979bool GenTreeIntConCommon::FitsInAddrBase(Compiler* comp)
15980{
15981#ifdef DEBUG
15982 // Early out if PC-rel encoding of absolute addr is disabled.
15983 if (!comp->opts.compEnablePCRelAddr)
15984 {
15985 return false;
15986 }
15987#endif
15988
15989 if (comp->opts.compReloc)
15990 {
15991 // During Ngen JIT is always asked to generate relocatable code.
15992 // Hence JIT will try to encode only icon handles as pc-relative offsets.
15993 return IsIconHandle() && (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue()));
15994 }
15995 else
15996 {
15997 // During Jitting, we are allowed to generate non-relocatable code.
15998 // On Amd64 we can encode an absolute indirect addr as an offset relative to zero or RIP.
15999 // An absolute indir addr that can fit within 32-bits can ben encoded as an offset relative
16000 // to zero. All other absolute indir addr could be attempted to be encoded as RIP relative
16001 // based on reloc hint provided by VM. RIP relative encoding is preferred over relative
16002 // to zero, because the former is one byte smaller than the latter. For this reason
16003 // we check for reloc hint first and then whether addr fits in 32-bits next.
16004 //
16005 // VM starts off with an initial state to allow both data and code address to be encoded as
16006 // pc-relative offsets. Hence JIT will attempt to encode all absolute addresses as pc-relative
16007 // offsets. It is possible while jitting a method, an address could not be encoded as a
16008 // pc-relative offset. In that case VM will note the overflow and will trigger re-jitting
16009 // of the method with reloc hints turned off for all future methods. Second time around
16010 // jitting will succeed since JIT will not attempt to encode data addresses as pc-relative
16011 // offsets. Note that JIT will always attempt to relocate code addresses (.e.g call addr).
16012 // After an overflow, VM will assume any relocation recorded is for a code address and will
16013 // emit jump thunk if it cannot be encoded as pc-relative offset.
16014 return (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue())) || FitsInI32();
16015 }
16016}
16017
16018// Returns true if this icon value is encoded as addr needs recording a relocation with VM
16019bool GenTreeIntConCommon::AddrNeedsReloc(Compiler* comp)
16020{
16021 if (comp->opts.compReloc)
16022 {
16023 // During Ngen JIT is always asked to generate relocatable code.
16024 // Hence JIT will try to encode only icon handles as pc-relative offsets.
16025 return IsIconHandle() && (IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue()));
16026 }
16027 else
16028 {
16029 return IMAGE_REL_BASED_REL32 == comp->eeGetRelocTypeHint((void*)IconValue());
16030 }
16031}
16032
16033#elif defined(_TARGET_X86_)
16034// Returns true if this absolute address fits within the base of an addr mode.
16035// On x86 all addresses are 4-bytes and can be directly encoded in an addr mode.
16036bool GenTreeIntConCommon::FitsInAddrBase(Compiler* comp)
16037{
16038#ifdef DEBUG
16039 // Early out if PC-rel encoding of absolute addr is disabled.
16040 if (!comp->opts.compEnablePCRelAddr)
16041 {
16042 return false;
16043 }
16044#endif
16045
16046 return IsCnsIntOrI();
16047}
16048
16049// Returns true if this icon value is encoded as addr needs recording a relocation with VM
16050bool GenTreeIntConCommon::AddrNeedsReloc(Compiler* comp)
16051{
16052 // If generating relocatable code, icons should be reported for recording relocatons.
16053 return comp->opts.compReloc && IsIconHandle();
16054}
16055#endif //_TARGET_X86_
16056
16057bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pObj, GenTree** pStatic, FieldSeqNode** pFldSeq)
16058{
16059 FieldSeqNode* newFldSeq = nullptr;
16060 GenTree* baseAddr = nullptr;
16061 bool mustBeStatic = false;
16062
16063 FieldSeqNode* statStructFldSeq = nullptr;
16064 if (TypeGet() == TYP_REF)
16065 {
16066 // Recognize struct static field patterns...
16067 if (OperGet() == GT_IND)
16068 {
16069 GenTree* addr = gtOp.gtOp1;
16070 GenTreeIntCon* icon = nullptr;
16071 if (addr->OperGet() == GT_CNS_INT)
16072 {
16073 icon = addr->AsIntCon();
16074 }
16075 else if (addr->OperGet() == GT_ADD)
16076 {
16077 // op1 should never be a field sequence (or any other kind of handle)
16078 assert((addr->gtOp.gtOp1->gtOper != GT_CNS_INT) || !addr->gtOp.gtOp1->IsIconHandle());
16079 if (addr->gtOp.gtOp2->OperGet() == GT_CNS_INT)
16080 {
16081 icon = addr->gtOp.gtOp2->AsIntCon();
16082 }
16083 }
16084 if (icon != nullptr && !icon->IsIconHandle(GTF_ICON_STR_HDL) // String handles are a source of TYP_REFs.
16085 && icon->gtFieldSeq != nullptr &&
16086 icon->gtFieldSeq->m_next == nullptr // A static field should be a singleton
16087 // TODO-Review: A pseudoField here indicates an issue - this requires investigation
16088 // See test case src\ddsuites\src\clr\x86\CoreMangLib\Dev\Globalization\CalendarRegressions.exe
16089 && !(FieldSeqStore::IsPseudoField(icon->gtFieldSeq->m_fieldHnd)) &&
16090 icon->gtFieldSeq != FieldSeqStore::NotAField()) // Ignore non-fields.
16091 {
16092 statStructFldSeq = icon->gtFieldSeq;
16093 }
16094 else
16095 {
16096 addr = addr->gtEffectiveVal();
16097
16098 // Perhaps it's a direct indirection of a helper call or a cse with a zero offset annotation.
16099 if ((addr->OperGet() == GT_CALL) || (addr->OperGet() == GT_LCL_VAR))
16100 {
16101 FieldSeqNode* zeroFieldSeq = nullptr;
16102 if (comp->GetZeroOffsetFieldMap()->Lookup(addr, &zeroFieldSeq))
16103 {
16104 if (zeroFieldSeq->m_next == nullptr)
16105 {
16106 statStructFldSeq = zeroFieldSeq;
16107 }
16108 }
16109 }
16110 }
16111 }
16112 else if (OperGet() == GT_CLS_VAR)
16113 {
16114 GenTreeClsVar* clsVar = AsClsVar();
16115 if (clsVar->gtFieldSeq != nullptr && clsVar->gtFieldSeq->m_next == nullptr)
16116 {
16117 statStructFldSeq = clsVar->gtFieldSeq;
16118 }
16119 }
16120 else if (OperIsLocal())
16121 {
16122 // If we have a GT_LCL_VAR, it can be result of a CSE substitution
16123 // If it is then the CSE assignment will have a ValueNum that
16124 // describes the RHS of the CSE assignment.
16125 //
16126 // The CSE could be a pointer to a boxed struct
16127 //
16128 GenTreeLclVarCommon* lclVar = AsLclVarCommon();
16129 ValueNum vn = gtVNPair.GetLiberal();
16130 if (vn != ValueNumStore::NoVN)
16131 {
16132 // Is the ValueNum a MapSelect involving a SharedStatic helper?
16133 VNFuncApp funcApp1;
16134 if (comp->vnStore->GetVNFunc(vn, &funcApp1) && (funcApp1.m_func == VNF_MapSelect) &&
16135 (comp->vnStore->IsSharedStatic(funcApp1.m_args[1])))
16136 {
16137 ValueNum mapVN = funcApp1.m_args[0];
16138 // Is this new 'mapVN' ValueNum, a MapSelect involving a handle?
16139 VNFuncApp funcApp2;
16140 if (comp->vnStore->GetVNFunc(mapVN, &funcApp2) && (funcApp2.m_func == VNF_MapSelect) &&
16141 (comp->vnStore->IsVNHandle(funcApp2.m_args[1])))
16142 {
16143 ValueNum fldHndVN = funcApp2.m_args[1];
16144 // Is this new 'fldHndVN' VNhandle a FieldHandle?
16145 unsigned flags = comp->vnStore->GetHandleFlags(fldHndVN);
16146 if (flags == GTF_ICON_FIELD_HDL)
16147 {
16148 CORINFO_FIELD_HANDLE fieldHnd =
16149 CORINFO_FIELD_HANDLE(comp->vnStore->ConstantValue<ssize_t>(fldHndVN));
16150
16151 // Record this field sequence in 'statStructFldSeq' as it is likely to be a Boxed Struct
16152 // field access.
16153 statStructFldSeq = comp->GetFieldSeqStore()->CreateSingleton(fieldHnd);
16154 }
16155 }
16156 }
16157 }
16158 }
16159
16160 if (statStructFldSeq != nullptr)
16161 {
16162 assert(statStructFldSeq->m_next == nullptr);
16163 // Is this a pointer to a boxed struct?
16164 if (comp->gtIsStaticFieldPtrToBoxedStruct(TYP_REF, statStructFldSeq->m_fieldHnd))
16165 {
16166 *pFldSeq = comp->GetFieldSeqStore()->Append(statStructFldSeq, *pFldSeq);
16167 *pObj = nullptr;
16168 *pStatic = this;
16169 return true;
16170 }
16171 }
16172
16173 // Otherwise...
16174 *pObj = this;
16175 *pStatic = nullptr;
16176 return true;
16177 }
16178 else if (OperGet() == GT_ADD)
16179 {
16180 // If one operator is a field sequence/handle, the other operator must not also be a field sequence/handle.
16181 if ((gtOp.gtOp1->OperGet() == GT_CNS_INT) && gtOp.gtOp1->IsIconHandle())
16182 {
16183 assert((gtOp.gtOp2->gtOper != GT_CNS_INT) || !gtOp.gtOp2->IsIconHandle());
16184 newFldSeq = gtOp.gtOp1->AsIntCon()->gtFieldSeq;
16185 baseAddr = gtOp.gtOp2;
16186 }
16187 else if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
16188 {
16189 assert((gtOp.gtOp1->gtOper != GT_CNS_INT) || !gtOp.gtOp1->IsIconHandle());
16190 newFldSeq = gtOp.gtOp2->AsIntCon()->gtFieldSeq;
16191 baseAddr = gtOp.gtOp1;
16192 }
16193 }
16194 else
16195 {
16196 // Check if "this" has a zero-offset annotation.
16197 if (!comp->GetZeroOffsetFieldMap()->Lookup(this, &newFldSeq))
16198 {
16199 // If not, this is not a field address.
16200 return false;
16201 }
16202 else
16203 {
16204 baseAddr = this;
16205 mustBeStatic = true;
16206 }
16207 }
16208
16209 // If not we don't have a field seq, it's not a field address.
16210 if (newFldSeq == nullptr || newFldSeq == FieldSeqStore::NotAField())
16211 {
16212 return false;
16213 }
16214
16215 // Prepend this field to whatever we've already accumulated (outside-in).
16216 *pFldSeq = comp->GetFieldSeqStore()->Append(newFldSeq, *pFldSeq);
16217
16218 // Is it a static or instance field?
16219 if (!FieldSeqStore::IsPseudoField(newFldSeq->m_fieldHnd) &&
16220 comp->info.compCompHnd->isFieldStatic(newFldSeq->m_fieldHnd))
16221 {
16222 // It is a static field. We're done.
16223 *pObj = nullptr;
16224 *pStatic = baseAddr;
16225 return true;
16226 }
16227 else if ((baseAddr != nullptr) && !mustBeStatic)
16228 {
16229 // It's an instance field...but it must be for a struct field, since we've not yet encountered
16230 // a "TYP_REF" address. Analyze the reset of the address.
16231 return baseAddr->gtEffectiveVal()->IsFieldAddr(comp, pObj, pStatic, pFldSeq);
16232 }
16233
16234 // Otherwise...
16235 return false;
16236}
16237
16238bool Compiler::gtIsStaticFieldPtrToBoxedStruct(var_types fieldNodeType, CORINFO_FIELD_HANDLE fldHnd)
16239{
16240 if (fieldNodeType != TYP_REF)
16241 {
16242 return false;
16243 }
16244 noway_assert(fldHnd != nullptr);
16245 CorInfoType cit = info.compCompHnd->getFieldType(fldHnd);
16246 var_types fieldTyp = JITtype2varType(cit);
16247 return fieldTyp != TYP_REF;
16248}
16249
16250#ifdef FEATURE_SIMD
16251//------------------------------------------------------------------------
16252// gtGetSIMDZero: Get a zero value of the appropriate SIMD type.
16253//
16254// Arguments:
16255// var_types - The simdType
16256// baseType - The base type we need
16257// simdHandle - The handle for the SIMD type
16258//
16259// Return Value:
16260// A node generating the appropriate Zero, if we are able to discern it,
16261// otherwise null (note that this shouldn't happen, but callers should
16262// be tolerant of this case).
16263
16264GenTree* Compiler::gtGetSIMDZero(var_types simdType, var_types baseType, CORINFO_CLASS_HANDLE simdHandle)
16265{
16266 bool found = false;
16267 bool isHWSIMD = true;
16268 noway_assert(m_simdHandleCache != nullptr);
16269
16270 // First, determine whether this is Vector<T>.
16271 if (simdType == getSIMDVectorType())
16272 {
16273 switch (baseType)
16274 {
16275 case TYP_FLOAT:
16276 found = (simdHandle == m_simdHandleCache->SIMDFloatHandle);
16277 break;
16278 case TYP_DOUBLE:
16279 found = (simdHandle == m_simdHandleCache->SIMDDoubleHandle);
16280 break;
16281 case TYP_INT:
16282 found = (simdHandle == m_simdHandleCache->SIMDIntHandle);
16283 break;
16284 case TYP_USHORT:
16285 found = (simdHandle == m_simdHandleCache->SIMDUShortHandle);
16286 break;
16287 case TYP_UBYTE:
16288 found = (simdHandle == m_simdHandleCache->SIMDUByteHandle);
16289 break;
16290 case TYP_SHORT:
16291 found = (simdHandle == m_simdHandleCache->SIMDShortHandle);
16292 break;
16293 case TYP_BYTE:
16294 found = (simdHandle == m_simdHandleCache->SIMDByteHandle);
16295 break;
16296 case TYP_LONG:
16297 found = (simdHandle == m_simdHandleCache->SIMDLongHandle);
16298 break;
16299 case TYP_UINT:
16300 found = (simdHandle == m_simdHandleCache->SIMDUIntHandle);
16301 break;
16302 case TYP_ULONG:
16303 found = (simdHandle == m_simdHandleCache->SIMDULongHandle);
16304 break;
16305 default:
16306 break;
16307 }
16308 if (found)
16309 {
16310 isHWSIMD = false;
16311 }
16312 }
16313
16314 if (!found)
16315 {
16316 // We must still have isHWSIMD set to true, and the only non-HW types left are the fixed types.
16317 switch (simdType)
16318 {
16319 case TYP_SIMD8:
16320 switch (baseType)
16321 {
16322 case TYP_FLOAT:
16323 if (simdHandle == m_simdHandleCache->SIMDVector2Handle)
16324 {
16325 isHWSIMD = false;
16326 }
16327#if defined(_TARGET_ARM64_) && defined(FEATURE_HW_INTRINSICS)
16328 else
16329 {
16330 assert(simdHandle == m_simdHandleCache->Vector64FloatHandle);
16331 }
16332 break;
16333 case TYP_INT:
16334 assert(simdHandle == m_simdHandleCache->Vector64IntHandle);
16335 break;
16336 case TYP_USHORT:
16337 assert(simdHandle == m_simdHandleCache->Vector64UShortHandle);
16338 break;
16339 case TYP_UBYTE:
16340 assert(simdHandle == m_simdHandleCache->Vector64UByteHandle);
16341 break;
16342 case TYP_SHORT:
16343 assert(simdHandle == m_simdHandleCache->Vector64ShortHandle);
16344 break;
16345 case TYP_BYTE:
16346 assert(simdHandle == m_simdHandleCache->Vector64ByteHandle);
16347 break;
16348 case TYP_UINT:
16349 assert(simdHandle == m_simdHandleCache->Vector64UIntHandle);
16350 break;
16351#endif // defined(_TARGET_ARM64_) && defined(FEATURE_HW_INTRINSICS)
16352 default:
16353 break;
16354 }
16355 break;
16356
16357 case TYP_SIMD12:
16358 assert((baseType == TYP_FLOAT) && (simdHandle == m_simdHandleCache->SIMDVector3Handle));
16359 isHWSIMD = false;
16360 break;
16361
16362 case TYP_SIMD16:
16363 switch (baseType)
16364 {
16365 case TYP_FLOAT:
16366 if (simdHandle == m_simdHandleCache->SIMDVector4Handle)
16367 {
16368 isHWSIMD = false;
16369 }
16370#if defined(FEATURE_HW_INTRINSICS)
16371 else
16372 {
16373 assert(simdHandle == m_simdHandleCache->Vector128FloatHandle);
16374 }
16375 break;
16376 case TYP_DOUBLE:
16377 assert(simdHandle == m_simdHandleCache->Vector128DoubleHandle);
16378 break;
16379 case TYP_INT:
16380 assert(simdHandle == m_simdHandleCache->Vector128IntHandle);
16381 break;
16382 case TYP_USHORT:
16383 assert(simdHandle == m_simdHandleCache->Vector128UShortHandle);
16384 break;
16385 case TYP_UBYTE:
16386 assert(simdHandle == m_simdHandleCache->Vector128UByteHandle);
16387 break;
16388 case TYP_SHORT:
16389 assert(simdHandle == m_simdHandleCache->Vector128ShortHandle);
16390 break;
16391 case TYP_BYTE:
16392 assert(simdHandle == m_simdHandleCache->Vector128ByteHandle);
16393 break;
16394 case TYP_LONG:
16395 assert(simdHandle == m_simdHandleCache->Vector128LongHandle);
16396 break;
16397 case TYP_UINT:
16398 assert(simdHandle == m_simdHandleCache->Vector128UIntHandle);
16399 break;
16400 case TYP_ULONG:
16401 assert(simdHandle == m_simdHandleCache->Vector128ULongHandle);
16402 break;
16403#endif // defined(FEATURE_HW_INTRINSICS)
16404
16405 default:
16406 break;
16407 }
16408 break;
16409
16410#if defined(_TARGET_XARCH4_) && defined(FEATURE_HW_INTRINSICS)
16411 case TYP_SIMD32:
16412 switch (baseType)
16413 {
16414 case TYP_FLOAT:
16415 assert(simdHandle == m_simdHandleCache->Vector256FloatHandle);
16416 break;
16417 case TYP_DOUBLE:
16418 assert(simdHandle == m_simdHandleCache->Vector256DoubleHandle);
16419 break;
16420 case TYP_INT:
16421 assert(simdHandle == m_simdHandleCache->Vector256IntHandle);
16422 break;
16423 case TYP_USHORT:
16424 assert(simdHandle == m_simdHandleCache->Vector256UShortHandle);
16425 break;
16426 case TYP_UBYTE:
16427 assert(simdHandle == m_simdHandleCache->Vector256UByteHandle);
16428 break;
16429 case TYP_SHORT:
16430 assert(simdHandle == m_simdHandleCache->Vector256ShortHandle);
16431 break;
16432 case TYP_BYTE:
16433 assert(simdHandle == m_simdHandleCache->Vector256ByteHandle);
16434 break;
16435 case TYP_LONG:
16436 assert(simdHandle == m_simdHandleCache->Vector256LongHandle);
16437 break;
16438 case TYP_UINT:
16439 assert(simdHandle == m_simdHandleCache->Vector256UIntHandle);
16440 break;
16441 case TYP_ULONG:
16442 assert(simdHandle == m_simdHandleCache->Vector256ULongHandle);
16443 break;
16444 default:
16445 break;
16446 }
16447 break;
16448#endif // _TARGET_XARCH_ && FEATURE_HW_INTRINSICS
16449 default:
16450 break;
16451 }
16452 }
16453
16454 unsigned size = genTypeSize(simdType);
16455 if (isHWSIMD)
16456 {
16457#if defined(_TARGET_XARCH_) && defined(FEATURE_HW_INTRINSICS)
16458 switch (simdType)
16459 {
16460 case TYP_SIMD16:
16461 if (compSupports(InstructionSet_SSE))
16462 {
16463 // We only return the HWIntrinsicNode if SSE is supported, since it is possible for
16464 // the user to disable the SSE HWIntrinsic support via the COMPlus configuration knobs
16465 // even though the hardware vector types are still available.
16466 return gtNewSimdHWIntrinsicNode(simdType, NI_Base_Vector128_Zero, baseType, size);
16467 }
16468 return nullptr;
16469 case TYP_SIMD32:
16470 if (compSupports(InstructionSet_AVX))
16471 {
16472 // We only return the HWIntrinsicNode if AVX is supported, since it is possible for
16473 // the user to disable the AVX HWIntrinsic support via the COMPlus configuration knobs
16474 // even though the hardware vector types are still available.
16475 return gtNewSimdHWIntrinsicNode(simdType, NI_Base_Vector256_Zero, baseType, size);
16476 }
16477 return nullptr;
16478 default:
16479 break;
16480 }
16481#endif // _TARGET_XARCH_ && FEATURE_HW_INTRINSICS
16482 JITDUMP("Coudn't find the matching SIMD type for %s<%s> in gtGetSIMDZero\n", varTypeName(simdType),
16483 varTypeName(baseType));
16484 }
16485 else
16486 {
16487 return gtNewSIMDVectorZero(simdType, baseType, size);
16488 }
16489 return nullptr;
16490}
16491#endif // FEATURE_SIMD
16492
16493CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleIfPresent(GenTree* tree)
16494{
16495 CORINFO_CLASS_HANDLE structHnd = NO_CLASS_HANDLE;
16496 tree = tree->gtEffectiveVal();
16497 if (varTypeIsStruct(tree->gtType))
16498 {
16499 switch (tree->gtOper)
16500 {
16501 default:
16502 break;
16503 case GT_MKREFANY:
16504 structHnd = impGetRefAnyClass();
16505 break;
16506 case GT_OBJ:
16507 structHnd = tree->gtObj.gtClass;
16508 break;
16509 case GT_CALL:
16510 structHnd = tree->gtCall.gtRetClsHnd;
16511 break;
16512 case GT_RET_EXPR:
16513 structHnd = tree->gtRetExpr.gtRetClsHnd;
16514 break;
16515 case GT_ARGPLACE:
16516 structHnd = tree->gtArgPlace.gtArgPlaceClsHnd;
16517 break;
16518 case GT_INDEX:
16519 structHnd = tree->gtIndex.gtStructElemClass;
16520 break;
16521 case GT_INDEX_ADDR:
16522 structHnd = tree->AsIndexAddr()->gtStructElemClass;
16523 break;
16524 case GT_FIELD:
16525 info.compCompHnd->getFieldType(tree->gtField.gtFldHnd, &structHnd);
16526 break;
16527 case GT_ASG:
16528 structHnd = gtGetStructHandleIfPresent(tree->gtGetOp1());
16529 break;
16530 case GT_LCL_FLD:
16531#ifdef FEATURE_SIMD
16532 if (varTypeIsSIMD(tree))
16533 {
16534 structHnd = gtGetStructHandleForSIMD(tree->gtType, TYP_FLOAT);
16535 }
16536#endif
16537 break;
16538 case GT_LCL_VAR:
16539 structHnd = lvaTable[tree->AsLclVarCommon()->gtLclNum].lvVerTypeInfo.GetClassHandle();
16540 break;
16541 case GT_RETURN:
16542 structHnd = gtGetStructHandleIfPresent(tree->gtOp.gtOp1);
16543 break;
16544 case GT_IND:
16545#ifdef FEATURE_SIMD
16546 if (varTypeIsSIMD(tree))
16547 {
16548 structHnd = gtGetStructHandleForSIMD(tree->gtType, TYP_FLOAT);
16549 }
16550 else
16551#endif
16552 {
16553 ArrayInfo arrInfo;
16554 if (TryGetArrayInfo(tree->AsIndir(), &arrInfo))
16555 {
16556 structHnd = EncodeElemType(arrInfo.m_elemType, arrInfo.m_elemStructType);
16557 }
16558 }
16559 break;
16560#ifdef FEATURE_SIMD
16561 case GT_SIMD:
16562 structHnd = gtGetStructHandleForSIMD(tree->gtType, tree->AsSIMD()->gtSIMDBaseType);
16563 break;
16564#endif // FEATURE_SIMD
16565#ifdef FEATURE_HW_INTRINSICS
16566 case GT_HWIntrinsic:
16567 structHnd = gtGetStructHandleForHWSIMD(tree->gtType, tree->AsHWIntrinsic()->gtSIMDBaseType);
16568 break;
16569#endif
16570 break;
16571 }
16572 }
16573 return structHnd;
16574}
16575
16576CORINFO_CLASS_HANDLE Compiler::gtGetStructHandle(GenTree* tree)
16577{
16578 CORINFO_CLASS_HANDLE structHnd = gtGetStructHandleIfPresent(tree);
16579 assert(structHnd != NO_CLASS_HANDLE);
16580 return structHnd;
16581}
16582
16583//------------------------------------------------------------------------
16584// gtGetClassHandle: find class handle for a ref type
16585//
16586// Arguments:
16587// tree -- tree to find handle for
16588// pIsExact [out] -- whether handle is exact type
16589// pIsNonNull [out] -- whether tree value is known not to be null
16590//
16591// Return Value:
16592// nullptr if class handle is unknown,
16593// otherwise the class handle.
16594// *pIsExact set true if tree type is known to be exactly the handle type,
16595// otherwise actual type may be a subtype.
16596// *pIsNonNull set true if tree value is known not to be null,
16597// otherwise a null value is possible.
16598
16599CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, bool* pIsNonNull)
16600{
16601 // Set default values for our out params.
16602 *pIsNonNull = false;
16603 *pIsExact = false;
16604 CORINFO_CLASS_HANDLE objClass = nullptr;
16605
16606 // Bail out if we're just importing and not generating code, since
16607 // the jit uses TYP_REF for CORINFO_TYPE_VAR locals and args, but
16608 // these may not be ref types.
16609 if (compIsForImportOnly())
16610 {
16611 return objClass;
16612 }
16613
16614 // Bail out if the tree is not a ref type.
16615 var_types treeType = tree->TypeGet();
16616 if (treeType != TYP_REF)
16617 {
16618 return objClass;
16619 }
16620
16621 // Tunnel through commas.
16622 GenTree* obj = tree->gtEffectiveVal(false);
16623 const genTreeOps objOp = obj->OperGet();
16624
16625 switch (objOp)
16626 {
16627 case GT_COMMA:
16628 {
16629 // gtEffectiveVal above means we shouldn't see commas here.
16630 assert(!"unexpected GT_COMMA");
16631 break;
16632 }
16633
16634 case GT_LCL_VAR:
16635 {
16636 // For locals, pick up type info from the local table.
16637 const unsigned objLcl = obj->AsLclVar()->GetLclNum();
16638
16639 objClass = lvaTable[objLcl].lvClassHnd;
16640 *pIsExact = lvaTable[objLcl].lvClassIsExact;
16641 break;
16642 }
16643
16644 case GT_FIELD:
16645 {
16646 // For fields, get the type from the field handle.
16647 CORINFO_FIELD_HANDLE fieldHnd = obj->gtField.gtFldHnd;
16648
16649 if (fieldHnd != nullptr)
16650 {
16651 objClass = gtGetFieldClassHandle(fieldHnd, pIsExact, pIsNonNull);
16652 }
16653
16654 break;
16655 }
16656
16657 case GT_RET_EXPR:
16658 {
16659 // If we see a RET_EXPR, recurse through to examine the
16660 // return value expression.
16661 GenTree* retExpr = tree->gtRetExpr.gtInlineCandidate;
16662 objClass = gtGetClassHandle(retExpr, pIsExact, pIsNonNull);
16663 break;
16664 }
16665
16666 case GT_CALL:
16667 {
16668 GenTreeCall* call = tree->AsCall();
16669 if (call->IsInlineCandidate())
16670 {
16671 // For inline candidates, we've already cached the return
16672 // type class handle in the inline info.
16673 InlineCandidateInfo* inlInfo = call->gtInlineCandidateInfo;
16674 assert(inlInfo != nullptr);
16675
16676 // Grab it as our first cut at a return type.
16677 assert(inlInfo->methInfo.args.retType == CORINFO_TYPE_CLASS);
16678 objClass = inlInfo->methInfo.args.retTypeClass;
16679
16680 // If the method is shared, the above may not capture
16681 // the most precise return type information (that is,
16682 // it may represent a shared return type and as such,
16683 // have instances of __Canon). See if we can use the
16684 // context to get at something more definite.
16685 //
16686 // For now, we do this here on demand rather than when
16687 // processing the call, but we could/should apply
16688 // similar sharpening to the argument and local types
16689 // of the inlinee.
16690 const unsigned retClassFlags = info.compCompHnd->getClassAttribs(objClass);
16691 if (retClassFlags & CORINFO_FLG_SHAREDINST)
16692 {
16693 CORINFO_CONTEXT_HANDLE context = inlInfo->exactContextHnd;
16694
16695 if (context != nullptr)
16696 {
16697 CORINFO_CLASS_HANDLE exactClass = nullptr;
16698
16699 if (((size_t)context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
16700 {
16701 exactClass = (CORINFO_CLASS_HANDLE)((size_t)context & ~CORINFO_CONTEXTFLAGS_MASK);
16702 }
16703 else
16704 {
16705 CORINFO_METHOD_HANDLE exactMethod =
16706 (CORINFO_METHOD_HANDLE)((size_t)context & ~CORINFO_CONTEXTFLAGS_MASK);
16707 exactClass = info.compCompHnd->getMethodClass(exactMethod);
16708 }
16709
16710 // Grab the signature in this context.
16711 CORINFO_SIG_INFO sig;
16712 eeGetMethodSig(call->gtCallMethHnd, &sig, exactClass);
16713 assert(sig.retType == CORINFO_TYPE_CLASS);
16714 objClass = sig.retTypeClass;
16715 }
16716 }
16717 }
16718 else if (call->gtCallType == CT_USER_FUNC)
16719 {
16720 // For user calls, we can fetch the approximate return
16721 // type info from the method handle. Unfortunately
16722 // we've lost the exact context, so this is the best
16723 // we can do for now.
16724 CORINFO_METHOD_HANDLE method = call->gtCallMethHnd;
16725 CORINFO_CLASS_HANDLE exactClass = nullptr;
16726 CORINFO_SIG_INFO sig;
16727 eeGetMethodSig(method, &sig, exactClass);
16728 if (sig.retType == CORINFO_TYPE_VOID)
16729 {
16730 // This is a constructor call.
16731 const unsigned methodFlags = info.compCompHnd->getMethodAttribs(method);
16732 assert((methodFlags & CORINFO_FLG_CONSTRUCTOR) != 0);
16733 objClass = info.compCompHnd->getMethodClass(method);
16734 *pIsExact = true;
16735 *pIsNonNull = true;
16736 }
16737 else
16738 {
16739 assert(sig.retType == CORINFO_TYPE_CLASS);
16740 objClass = sig.retTypeClass;
16741 }
16742 }
16743 else if (call->gtCallType == CT_HELPER)
16744 {
16745 objClass = gtGetHelperCallClassHandle(call, pIsExact, pIsNonNull);
16746 }
16747
16748 break;
16749 }
16750
16751 case GT_INTRINSIC:
16752 {
16753 GenTreeIntrinsic* intrinsic = obj->AsIntrinsic();
16754
16755 if (intrinsic->gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType)
16756 {
16757 CORINFO_CLASS_HANDLE runtimeType = info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE);
16758 assert(runtimeType != NO_CLASS_HANDLE);
16759
16760 objClass = runtimeType;
16761 *pIsExact = false;
16762 *pIsNonNull = true;
16763 }
16764
16765 break;
16766 }
16767
16768 case GT_CNS_STR:
16769 {
16770 // For literal strings, we know the class and that the
16771 // value is not null.
16772 objClass = impGetStringClass();
16773 *pIsExact = true;
16774 *pIsNonNull = true;
16775 break;
16776 }
16777
16778 case GT_IND:
16779 {
16780 GenTreeIndir* indir = obj->AsIndir();
16781
16782 if (indir->HasBase() && !indir->HasIndex())
16783 {
16784 // indir(addr(lcl)) --> lcl
16785 //
16786 // This comes up during constrained callvirt on ref types.
16787
16788 GenTree* base = indir->Base();
16789 GenTreeLclVarCommon* lcl = base->IsLocalAddrExpr();
16790
16791 if ((lcl != nullptr) && (base->OperGet() != GT_ADD))
16792 {
16793 const unsigned objLcl = lcl->GetLclNum();
16794 objClass = lvaTable[objLcl].lvClassHnd;
16795 *pIsExact = lvaTable[objLcl].lvClassIsExact;
16796 }
16797 else if (base->OperGet() == GT_ARR_ELEM)
16798 {
16799 // indir(arr_elem(...)) -> array element type
16800
16801 GenTree* array = base->AsArrElem()->gtArrObj;
16802
16803 objClass = gtGetArrayElementClassHandle(array);
16804 *pIsExact = false;
16805 *pIsNonNull = false;
16806 }
16807 else if (base->OperGet() == GT_ADD)
16808 {
16809 // This could be a static field access.
16810 //
16811 // See if op1 is a static field base helper call
16812 // and if so, op2 will have the field info.
16813 GenTree* op1 = base->gtOp.gtOp1;
16814 GenTree* op2 = base->gtOp.gtOp2;
16815
16816 const bool op1IsStaticFieldBase = gtIsStaticGCBaseHelperCall(op1);
16817
16818 if (op1IsStaticFieldBase && (op2->OperGet() == GT_CNS_INT))
16819 {
16820 FieldSeqNode* fieldSeq = op2->AsIntCon()->gtFieldSeq;
16821
16822 if (fieldSeq != nullptr)
16823 {
16824 while (fieldSeq->m_next != nullptr)
16825 {
16826 fieldSeq = fieldSeq->m_next;
16827 }
16828
16829 assert(!fieldSeq->IsPseudoField());
16830
16831 // No benefit to calling gtGetFieldClassHandle here, as
16832 // the exact field being accessed can vary.
16833 CORINFO_FIELD_HANDLE fieldHnd = fieldSeq->m_fieldHnd;
16834 CORINFO_CLASS_HANDLE fieldClass = nullptr;
16835 CorInfoType fieldCorType = info.compCompHnd->getFieldType(fieldHnd, &fieldClass);
16836
16837 assert(fieldCorType == CORINFO_TYPE_CLASS);
16838 objClass = fieldClass;
16839 }
16840 }
16841 }
16842 }
16843
16844 break;
16845 }
16846
16847 case GT_BOX:
16848 {
16849 // Box should just wrap a local var reference which has
16850 // the type we're looking for. Also box only represents a
16851 // non-nullable value type so result cannot be null.
16852 GenTreeBox* box = obj->AsBox();
16853 GenTree* boxTemp = box->BoxOp();
16854 assert(boxTemp->IsLocal());
16855 const unsigned boxTempLcl = boxTemp->AsLclVar()->GetLclNum();
16856 objClass = lvaTable[boxTempLcl].lvClassHnd;
16857 *pIsExact = lvaTable[boxTempLcl].lvClassIsExact;
16858 *pIsNonNull = true;
16859 break;
16860 }
16861
16862 case GT_INDEX:
16863 {
16864 GenTree* array = obj->AsIndex()->Arr();
16865
16866 objClass = gtGetArrayElementClassHandle(array);
16867 *pIsExact = false;
16868 *pIsNonNull = false;
16869 break;
16870 }
16871
16872 default:
16873 {
16874 break;
16875 }
16876 }
16877
16878 return objClass;
16879}
16880
16881//------------------------------------------------------------------------
16882// gtGetHelperCallClassHandle: find class handle for return value of a
16883// helper call
16884//
16885// Arguments:
16886// call - helper call to examine
16887// pIsExact - [OUT] true if type is known exactly
16888// pIsNonNull - [OUT] true if return value is not null
16889//
16890// Return Value:
16891// nullptr if helper call result is not a ref class, or the class handle
16892// is unknown, otherwise the class handle.
16893
16894CORINFO_CLASS_HANDLE Compiler::gtGetHelperCallClassHandle(GenTreeCall* call, bool* pIsExact, bool* pIsNonNull)
16895{
16896 assert(call->gtCallType == CT_HELPER);
16897
16898 *pIsNonNull = false;
16899 *pIsExact = false;
16900 CORINFO_CLASS_HANDLE objClass = nullptr;
16901 const CorInfoHelpFunc helper = eeGetHelperNum(call->gtCallMethHnd);
16902
16903 switch (helper)
16904 {
16905 case CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE:
16906 case CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL:
16907 {
16908 // Note for some runtimes these helpers return exact types.
16909 //
16910 // But in those cases the types are also sealed, so there's no
16911 // need to claim exactness here.
16912 const bool helperResultNonNull = (helper == CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE);
16913 CORINFO_CLASS_HANDLE runtimeType = info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE);
16914
16915 assert(runtimeType != NO_CLASS_HANDLE);
16916
16917 objClass = runtimeType;
16918 *pIsNonNull = helperResultNonNull;
16919 break;
16920 }
16921
16922 case CORINFO_HELP_CHKCASTCLASS:
16923 case CORINFO_HELP_CHKCASTANY:
16924 case CORINFO_HELP_CHKCASTARRAY:
16925 case CORINFO_HELP_CHKCASTINTERFACE:
16926 case CORINFO_HELP_CHKCASTCLASS_SPECIAL:
16927 case CORINFO_HELP_ISINSTANCEOFINTERFACE:
16928 case CORINFO_HELP_ISINSTANCEOFARRAY:
16929 case CORINFO_HELP_ISINSTANCEOFCLASS:
16930 case CORINFO_HELP_ISINSTANCEOFANY:
16931 {
16932 // Fetch the class handle from the helper call arglist
16933 GenTreeArgList* args = call->gtCallArgs;
16934 GenTree* typeArg = args->Current();
16935 CORINFO_CLASS_HANDLE castHnd = gtGetHelperArgClassHandle(typeArg);
16936
16937 // We generally assume the type being cast to is the best type
16938 // for the result, unless it is an interface type.
16939 //
16940 // TODO-CQ: when we have default interface methods then
16941 // this might not be the best assumption. We could also
16942 // explore calling something like mergeClasses to identify
16943 // the more specific class. A similar issue arises when
16944 // typing the temp in impCastClassOrIsInstToTree, when we
16945 // expand the cast inline.
16946 if (castHnd != nullptr)
16947 {
16948 DWORD attrs = info.compCompHnd->getClassAttribs(castHnd);
16949
16950 if ((attrs & CORINFO_FLG_INTERFACE) != 0)
16951 {
16952 castHnd = nullptr;
16953 }
16954 }
16955
16956 // If we don't have a good estimate for the type we can use the
16957 // type from the value being cast instead.
16958 if (castHnd == nullptr)
16959 {
16960 GenTree* valueArg = args->Rest()->Current();
16961 castHnd = gtGetClassHandle(valueArg, pIsExact, pIsNonNull);
16962 }
16963
16964 // We don't know at jit time if the cast will succeed or fail, but if it
16965 // fails at runtime then an exception is thrown for cast helpers, or the
16966 // result is set null for instance helpers.
16967 //
16968 // So it safe to claim the result has the cast type.
16969 // Note we don't know for sure that it is exactly this type.
16970 if (castHnd != nullptr)
16971 {
16972 objClass = castHnd;
16973 }
16974
16975 break;
16976 }
16977
16978 default:
16979 break;
16980 }
16981
16982 return objClass;
16983}
16984
16985//------------------------------------------------------------------------
16986// gtGetArrayElementClassHandle: find class handle for elements of an array
16987// of ref types
16988//
16989// Arguments:
16990// array -- array to find handle for
16991//
16992// Return Value:
16993// nullptr if element class handle is unknown, otherwise the class handle.
16994
16995CORINFO_CLASS_HANDLE Compiler::gtGetArrayElementClassHandle(GenTree* array)
16996{
16997 bool isArrayExact = false;
16998 bool isArrayNonNull = false;
16999 CORINFO_CLASS_HANDLE arrayClassHnd = gtGetClassHandle(array, &isArrayExact, &isArrayNonNull);
17000
17001 if (arrayClassHnd != nullptr)
17002 {
17003 // We know the class of the reference
17004 DWORD attribs = info.compCompHnd->getClassAttribs(arrayClassHnd);
17005
17006 if ((attribs & CORINFO_FLG_ARRAY) != 0)
17007 {
17008 // We know for sure it is an array
17009 CORINFO_CLASS_HANDLE elemClassHnd = nullptr;
17010 CorInfoType arrayElemType = info.compCompHnd->getChildType(arrayClassHnd, &elemClassHnd);
17011
17012 if (arrayElemType == CORINFO_TYPE_CLASS)
17013 {
17014 // We know it is an array of ref types
17015 return elemClassHnd;
17016 }
17017 }
17018 }
17019
17020 return nullptr;
17021}
17022
17023//------------------------------------------------------------------------
17024// gtGetFieldClassHandle: find class handle for a field
17025//
17026// Arguments:
17027// fieldHnd - field handle for field in question
17028// pIsExact - [OUT] true if type is known exactly
17029// pIsNonNull - [OUT] true if field value is not null
17030//
17031// Return Value:
17032// nullptr if helper call result is not a ref class, or the class handle
17033// is unknown, otherwise the class handle.
17034//
17035// May examine runtime state of static field instances.
17036
17037CORINFO_CLASS_HANDLE Compiler::gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldHnd, bool* pIsExact, bool* pIsNonNull)
17038{
17039 CORINFO_CLASS_HANDLE fieldClass = nullptr;
17040 CorInfoType fieldCorType = info.compCompHnd->getFieldType(fieldHnd, &fieldClass);
17041
17042 if (fieldCorType == CORINFO_TYPE_CLASS)
17043 {
17044 // Optionally, look at the actual type of the field's value
17045 bool queryForCurrentClass = true;
17046 INDEBUG(queryForCurrentClass = (JitConfig.JitQueryCurrentStaticFieldClass() > 0););
17047
17048 if (queryForCurrentClass)
17049 {
17050
17051#if DEBUG
17052 const char* fieldClassName = nullptr;
17053 const char* fieldName = eeGetFieldName(fieldHnd, &fieldClassName);
17054 JITDUMP("Querying runtime about current class of field %s.%s (declared as %s)\n", fieldClassName, fieldName,
17055 eeGetClassName(fieldClass));
17056#endif // DEBUG
17057
17058 // Is this a fully initialized init-only static field?
17059 //
17060 // Note we're not asking for speculative results here, yet.
17061 CORINFO_CLASS_HANDLE currentClass = info.compCompHnd->getStaticFieldCurrentClass(fieldHnd);
17062
17063 if (currentClass != NO_CLASS_HANDLE)
17064 {
17065 // Yes! We know the class exactly and can rely on this to always be true.
17066 fieldClass = currentClass;
17067 *pIsExact = true;
17068 *pIsNonNull = true;
17069 JITDUMP("Runtime reports field is init-only and initialized and has class %s\n",
17070 eeGetClassName(fieldClass));
17071 }
17072 else
17073 {
17074 JITDUMP("Field's current class not available\n");
17075 }
17076 }
17077 }
17078
17079 return fieldClass;
17080}
17081
17082//------------------------------------------------------------------------
17083// gtIsGCStaticBaseHelperCall: true if tree is fetching the gc static base
17084// for a subsequent static field access
17085//
17086// Arguments:
17087// tree - tree to consider
17088//
17089// Return Value:
17090// true if the tree is a suitable helper call
17091//
17092// Notes:
17093// Excludes R2R helpers as they specify the target field in a way
17094// that is opaque to the jit.
17095
17096bool Compiler::gtIsStaticGCBaseHelperCall(GenTree* tree)
17097{
17098 if (tree->OperGet() != GT_CALL)
17099 {
17100 return false;
17101 }
17102
17103 GenTreeCall* call = tree->AsCall();
17104
17105 if (call->gtCallType != CT_HELPER)
17106 {
17107 return false;
17108 }
17109
17110 const CorInfoHelpFunc helper = eeGetHelperNum(call->gtCallMethHnd);
17111
17112 switch (helper)
17113 {
17114 // We are looking for a REF type so only need to check for the GC base helpers
17115 case CORINFO_HELP_GETGENERICS_GCSTATIC_BASE:
17116 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE:
17117 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR:
17118 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS:
17119 case CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE:
17120 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE:
17121 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR:
17122 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS:
17123 return true;
17124 default:
17125 break;
17126 }
17127
17128 return false;
17129}
17130
17131void GenTree::ParseArrayAddress(
17132 Compiler* comp, ArrayInfo* arrayInfo, GenTree** pArr, ValueNum* pInxVN, FieldSeqNode** pFldSeq)
17133{
17134 *pArr = nullptr;
17135 ValueNum inxVN = ValueNumStore::NoVN;
17136 target_ssize_t offset = 0;
17137 FieldSeqNode* fldSeq = nullptr;
17138
17139 ParseArrayAddressWork(comp, 1, pArr, &inxVN, &offset, &fldSeq);
17140
17141 // If we didn't find an array reference (perhaps it is the constant null?) we will give up.
17142 if (*pArr == nullptr)
17143 {
17144 return;
17145 }
17146
17147 // OK, new we have to figure out if any part of the "offset" is a constant contribution to the index.
17148 // First, sum the offsets of any fields in fldSeq.
17149 unsigned fieldOffsets = 0;
17150 FieldSeqNode* fldSeqIter = fldSeq;
17151 // Also, find the first non-pseudo field...
17152 assert(*pFldSeq == nullptr);
17153 while (fldSeqIter != nullptr)
17154 {
17155 if (fldSeqIter == FieldSeqStore::NotAField())
17156 {
17157 // TODO-Review: A NotAField here indicates a failure to properly maintain the field sequence
17158 // See test case self_host_tests_x86\jit\regression\CLR-x86-JIT\v1-m12-beta2\ b70992\ b70992.exe
17159 // Safest thing to do here is to drop back to MinOpts
17160 CLANG_FORMAT_COMMENT_ANCHOR;
17161
17162#ifdef DEBUG
17163 if (comp->opts.optRepeat)
17164 {
17165 // We don't guarantee preserving these annotations through the entire optimizer, so
17166 // just conservatively return null if under optRepeat.
17167 *pArr = nullptr;
17168 return;
17169 }
17170#endif // DEBUG
17171 noway_assert(!"fldSeqIter is NotAField() in ParseArrayAddress");
17172 }
17173
17174 if (!FieldSeqStore::IsPseudoField(fldSeqIter->m_fieldHnd))
17175 {
17176 if (*pFldSeq == nullptr)
17177 {
17178 *pFldSeq = fldSeqIter;
17179 }
17180 CORINFO_CLASS_HANDLE fldCls = nullptr;
17181 noway_assert(fldSeqIter->m_fieldHnd != nullptr);
17182 CorInfoType cit = comp->info.compCompHnd->getFieldType(fldSeqIter->m_fieldHnd, &fldCls);
17183 fieldOffsets += comp->compGetTypeSize(cit, fldCls);
17184 }
17185 fldSeqIter = fldSeqIter->m_next;
17186 }
17187
17188 // Is there some portion of the "offset" beyond the first-elem offset and the struct field suffix we just computed?
17189 if (!FitsIn<target_ssize_t>(fieldOffsets + arrayInfo->m_elemOffset) ||
17190 !FitsIn<target_ssize_t>(arrayInfo->m_elemSize))
17191 {
17192 // This seems unlikely, but no harm in being safe...
17193 *pInxVN = comp->GetValueNumStore()->VNForExpr(nullptr, TYP_INT);
17194 return;
17195 }
17196 // Otherwise...
17197 target_ssize_t offsetAccountedFor = static_cast<target_ssize_t>(fieldOffsets + arrayInfo->m_elemOffset);
17198 target_ssize_t elemSize = static_cast<target_ssize_t>(arrayInfo->m_elemSize);
17199
17200 target_ssize_t constIndOffset = offset - offsetAccountedFor;
17201 // This should be divisible by the element size...
17202 assert((constIndOffset % elemSize) == 0);
17203 target_ssize_t constInd = constIndOffset / elemSize;
17204
17205 ValueNumStore* vnStore = comp->GetValueNumStore();
17206
17207 if (inxVN == ValueNumStore::NoVN)
17208 {
17209 // Must be a constant index.
17210 *pInxVN = vnStore->VNForPtrSizeIntCon(constInd);
17211 }
17212 else
17213 {
17214 //
17215 // Perform ((inxVN / elemSizeVN) + vnForConstInd)
17216 //
17217
17218 // The value associated with the index value number (inxVN) is the offset into the array,
17219 // which has been scaled by element size. We need to recover the array index from that offset
17220 if (vnStore->IsVNConstant(inxVN))
17221 {
17222 target_ssize_t index = vnStore->CoercedConstantValue<target_ssize_t>(inxVN);
17223 noway_assert(elemSize > 0 && ((index % elemSize) == 0));
17224 *pInxVN = vnStore->VNForPtrSizeIntCon((index / elemSize) + constInd);
17225 }
17226 else
17227 {
17228 bool canFoldDiv = false;
17229
17230 // If the index VN is a MUL by elemSize, see if we can eliminate it instead of adding
17231 // the division by elemSize.
17232 VNFuncApp funcApp;
17233 if (vnStore->GetVNFunc(inxVN, &funcApp) && funcApp.m_func == (VNFunc)GT_MUL)
17234 {
17235 ValueNum vnForElemSize = vnStore->VNForLongCon(elemSize);
17236
17237 // One of the multiply operand is elemSize, so the resulting
17238 // index VN should simply be the other operand.
17239 if (funcApp.m_args[1] == vnForElemSize)
17240 {
17241 *pInxVN = funcApp.m_args[0];
17242 canFoldDiv = true;
17243 }
17244 else if (funcApp.m_args[0] == vnForElemSize)
17245 {
17246 *pInxVN = funcApp.m_args[1];
17247 canFoldDiv = true;
17248 }
17249 }
17250
17251 // Perform ((inxVN / elemSizeVN) + vnForConstInd)
17252 if (!canFoldDiv)
17253 {
17254 ValueNum vnForElemSize = vnStore->VNForPtrSizeIntCon(elemSize);
17255 ValueNum vnForScaledInx =
17256 vnStore->VNForFunc(TYP_I_IMPL, GetVNFuncForOper(GT_DIV, VOK_Default), inxVN, vnForElemSize);
17257 *pInxVN = vnForScaledInx;
17258 }
17259
17260 if (constInd != 0)
17261 {
17262 ValueNum vnForConstInd = comp->GetValueNumStore()->VNForPtrSizeIntCon(constInd);
17263 VNFunc vnFunc = GetVNFuncForOper(GT_ADD, VOK_Default);
17264
17265 *pInxVN = comp->GetValueNumStore()->VNForFunc(TYP_I_IMPL, vnFunc, *pInxVN, vnForConstInd);
17266 }
17267 }
17268 }
17269}
17270
17271void GenTree::ParseArrayAddressWork(Compiler* comp,
17272 target_ssize_t inputMul,
17273 GenTree** pArr,
17274 ValueNum* pInxVN,
17275 target_ssize_t* pOffset,
17276 FieldSeqNode** pFldSeq)
17277{
17278 if (TypeGet() == TYP_REF)
17279 {
17280 // This must be the array pointer.
17281 *pArr = this;
17282 assert(inputMul == 1); // Can't multiply the array pointer by anything.
17283 }
17284 else
17285 {
17286 switch (OperGet())
17287 {
17288 case GT_CNS_INT:
17289 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, gtIntCon.gtFieldSeq);
17290 assert(!gtIntCon.ImmedValNeedsReloc(comp));
17291 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntCon::gtIconVal had target_ssize_t
17292 // type.
17293 *pOffset += (inputMul * (target_ssize_t)(gtIntCon.gtIconVal));
17294 return;
17295
17296 case GT_ADD:
17297 case GT_SUB:
17298 gtOp.gtOp1->ParseArrayAddressWork(comp, inputMul, pArr, pInxVN, pOffset, pFldSeq);
17299 if (OperGet() == GT_SUB)
17300 {
17301 inputMul = -inputMul;
17302 }
17303 gtOp.gtOp2->ParseArrayAddressWork(comp, inputMul, pArr, pInxVN, pOffset, pFldSeq);
17304 return;
17305
17306 case GT_MUL:
17307 {
17308 // If one op is a constant, continue parsing down.
17309 target_ssize_t subMul = 0;
17310 GenTree* nonConst = nullptr;
17311 if (gtOp.gtOp1->IsCnsIntOrI())
17312 {
17313 // If the other arg is an int constant, and is a "not-a-field", choose
17314 // that as the multiplier, thus preserving constant index offsets...
17315 if (gtOp.gtOp2->OperGet() == GT_CNS_INT &&
17316 gtOp.gtOp2->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField())
17317 {
17318 assert(!gtOp.gtOp2->gtIntCon.ImmedValNeedsReloc(comp));
17319 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntConCommon::gtIconVal had
17320 // target_ssize_t type.
17321 subMul = (target_ssize_t)gtOp.gtOp2->gtIntConCommon.IconValue();
17322 nonConst = gtOp.gtOp1;
17323 }
17324 else
17325 {
17326 assert(!gtOp.gtOp1->gtIntCon.ImmedValNeedsReloc(comp));
17327 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntConCommon::gtIconVal had
17328 // target_ssize_t type.
17329 subMul = (target_ssize_t)gtOp.gtOp1->gtIntConCommon.IconValue();
17330 nonConst = gtOp.gtOp2;
17331 }
17332 }
17333 else if (gtOp.gtOp2->IsCnsIntOrI())
17334 {
17335 assert(!gtOp.gtOp2->gtIntCon.ImmedValNeedsReloc(comp));
17336 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntConCommon::gtIconVal had
17337 // target_ssize_t type.
17338 subMul = (target_ssize_t)gtOp.gtOp2->gtIntConCommon.IconValue();
17339 nonConst = gtOp.gtOp1;
17340 }
17341 if (nonConst != nullptr)
17342 {
17343 nonConst->ParseArrayAddressWork(comp, inputMul * subMul, pArr, pInxVN, pOffset, pFldSeq);
17344 return;
17345 }
17346 // Otherwise, exit the switch, treat as a contribution to the index.
17347 }
17348 break;
17349
17350 case GT_LSH:
17351 // If one op is a constant, continue parsing down.
17352 if (gtOp.gtOp2->IsCnsIntOrI())
17353 {
17354 assert(!gtOp.gtOp2->gtIntCon.ImmedValNeedsReloc(comp));
17355 // TODO-CrossBitness: we wouldn't need the cast below if GenTreeIntCon::gtIconVal had target_ssize_t
17356 // type.
17357 target_ssize_t subMul = target_ssize_t{1} << (target_ssize_t)gtOp.gtOp2->gtIntConCommon.IconValue();
17358 gtOp.gtOp1->ParseArrayAddressWork(comp, inputMul * subMul, pArr, pInxVN, pOffset, pFldSeq);
17359 return;
17360 }
17361 // Otherwise, exit the switch, treat as a contribution to the index.
17362 break;
17363
17364 case GT_COMMA:
17365 // We don't care about exceptions for this purpose.
17366 if ((gtOp.gtOp1->OperGet() == GT_ARR_BOUNDS_CHECK) || gtOp.gtOp1->IsNothingNode())
17367 {
17368 gtOp.gtOp2->ParseArrayAddressWork(comp, inputMul, pArr, pInxVN, pOffset, pFldSeq);
17369 return;
17370 }
17371 break;
17372
17373 default:
17374 break;
17375 }
17376 // If we didn't return above, must be a contribution to the non-constant part of the index VN.
17377 ValueNum vn = comp->GetValueNumStore()->VNLiberalNormalValue(gtVNPair);
17378 if (inputMul != 1)
17379 {
17380 ValueNum mulVN = comp->GetValueNumStore()->VNForLongCon(inputMul);
17381 vn = comp->GetValueNumStore()->VNForFunc(TypeGet(), GetVNFuncForOper(GT_MUL, VOK_Default), mulVN, vn);
17382 }
17383 if (*pInxVN == ValueNumStore::NoVN)
17384 {
17385 *pInxVN = vn;
17386 }
17387 else
17388 {
17389 *pInxVN =
17390 comp->GetValueNumStore()->VNForFunc(TypeGet(), GetVNFuncForOper(GT_ADD, VOK_Default), *pInxVN, vn);
17391 }
17392 }
17393}
17394
17395bool GenTree::ParseArrayElemForm(Compiler* comp, ArrayInfo* arrayInfo, FieldSeqNode** pFldSeq)
17396{
17397 if (OperIsIndir())
17398 {
17399 if (gtFlags & GTF_IND_ARR_INDEX)
17400 {
17401 bool b = comp->GetArrayInfoMap()->Lookup(this, arrayInfo);
17402 assert(b);
17403 return true;
17404 }
17405
17406 // Otherwise...
17407 GenTree* addr = AsIndir()->Addr();
17408 return addr->ParseArrayElemAddrForm(comp, arrayInfo, pFldSeq);
17409 }
17410 else
17411 {
17412 return false;
17413 }
17414}
17415
17416bool GenTree::ParseArrayElemAddrForm(Compiler* comp, ArrayInfo* arrayInfo, FieldSeqNode** pFldSeq)
17417{
17418 switch (OperGet())
17419 {
17420 case GT_ADD:
17421 {
17422 GenTree* arrAddr = nullptr;
17423 GenTree* offset = nullptr;
17424 if (gtOp.gtOp1->TypeGet() == TYP_BYREF)
17425 {
17426 arrAddr = gtOp.gtOp1;
17427 offset = gtOp.gtOp2;
17428 }
17429 else if (gtOp.gtOp2->TypeGet() == TYP_BYREF)
17430 {
17431 arrAddr = gtOp.gtOp2;
17432 offset = gtOp.gtOp1;
17433 }
17434 else
17435 {
17436 return false;
17437 }
17438 if (!offset->ParseOffsetForm(comp, pFldSeq))
17439 {
17440 return false;
17441 }
17442 return arrAddr->ParseArrayElemAddrForm(comp, arrayInfo, pFldSeq);
17443 }
17444
17445 case GT_ADDR:
17446 {
17447 GenTree* addrArg = gtOp.gtOp1;
17448 if (addrArg->OperGet() != GT_IND)
17449 {
17450 return false;
17451 }
17452 else
17453 {
17454 // The "Addr" node might be annotated with a zero-offset field sequence.
17455 FieldSeqNode* zeroOffsetFldSeq = nullptr;
17456 if (comp->GetZeroOffsetFieldMap()->Lookup(this, &zeroOffsetFldSeq))
17457 {
17458 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, zeroOffsetFldSeq);
17459 }
17460 return addrArg->ParseArrayElemForm(comp, arrayInfo, pFldSeq);
17461 }
17462 }
17463
17464 default:
17465 return false;
17466 }
17467}
17468
17469bool GenTree::ParseOffsetForm(Compiler* comp, FieldSeqNode** pFldSeq)
17470{
17471 switch (OperGet())
17472 {
17473 case GT_CNS_INT:
17474 {
17475 GenTreeIntCon* icon = AsIntCon();
17476 *pFldSeq = comp->GetFieldSeqStore()->Append(*pFldSeq, icon->gtFieldSeq);
17477 return true;
17478 }
17479
17480 case GT_ADD:
17481 if (!gtOp.gtOp1->ParseOffsetForm(comp, pFldSeq))
17482 {
17483 return false;
17484 }
17485 return gtOp.gtOp2->ParseOffsetForm(comp, pFldSeq);
17486
17487 default:
17488 return false;
17489 }
17490}
17491
17492void GenTree::LabelIndex(Compiler* comp, bool isConst)
17493{
17494 switch (OperGet())
17495 {
17496 case GT_CNS_INT:
17497 // If we got here, this is a contribution to the constant part of the index.
17498 if (isConst)
17499 {
17500 gtIntCon.gtFieldSeq =
17501 comp->GetFieldSeqStore()->CreateSingleton(FieldSeqStore::ConstantIndexPseudoField);
17502 }
17503 return;
17504
17505 case GT_LCL_VAR:
17506 gtFlags |= GTF_VAR_ARR_INDEX;
17507 return;
17508
17509 case GT_ADD:
17510 case GT_SUB:
17511 gtOp.gtOp1->LabelIndex(comp, isConst);
17512 gtOp.gtOp2->LabelIndex(comp, isConst);
17513 break;
17514
17515 case GT_CAST:
17516 gtOp.gtOp1->LabelIndex(comp, isConst);
17517 break;
17518
17519 case GT_ARR_LENGTH:
17520 gtFlags |= GTF_ARRLEN_ARR_IDX;
17521 return;
17522
17523 default:
17524 // For all other operators, peel off one constant; and then label the other if it's also a constant.
17525 if (OperIsArithmetic() || OperIsCompare())
17526 {
17527 if (gtOp.gtOp2->OperGet() == GT_CNS_INT)
17528 {
17529 gtOp.gtOp1->LabelIndex(comp, isConst);
17530 break;
17531 }
17532 else if (gtOp.gtOp1->OperGet() == GT_CNS_INT)
17533 {
17534 gtOp.gtOp2->LabelIndex(comp, isConst);
17535 break;
17536 }
17537 // Otherwise continue downward on both, labeling vars.
17538 gtOp.gtOp1->LabelIndex(comp, false);
17539 gtOp.gtOp2->LabelIndex(comp, false);
17540 }
17541 break;
17542 }
17543}
17544
17545// Note that the value of the below field doesn't matter; it exists only to provide a distinguished address.
17546//
17547// static
17548FieldSeqNode FieldSeqStore::s_notAField(nullptr, nullptr);
17549
17550// FieldSeqStore methods.
17551FieldSeqStore::FieldSeqStore(CompAllocator alloc) : m_alloc(alloc), m_canonMap(new (alloc) FieldSeqNodeCanonMap(alloc))
17552{
17553}
17554
17555FieldSeqNode* FieldSeqStore::CreateSingleton(CORINFO_FIELD_HANDLE fieldHnd)
17556{
17557 FieldSeqNode fsn(fieldHnd, nullptr);
17558 FieldSeqNode* res = nullptr;
17559 if (m_canonMap->Lookup(fsn, &res))
17560 {
17561 return res;
17562 }
17563 else
17564 {
17565 res = m_alloc.allocate<FieldSeqNode>(1);
17566 *res = fsn;
17567 m_canonMap->Set(fsn, res);
17568 return res;
17569 }
17570}
17571
17572FieldSeqNode* FieldSeqStore::Append(FieldSeqNode* a, FieldSeqNode* b)
17573{
17574 if (a == nullptr)
17575 {
17576 return b;
17577 }
17578 else if (a == NotAField())
17579 {
17580 return NotAField();
17581 }
17582 else if (b == nullptr)
17583 {
17584 return a;
17585 }
17586 else if (b == NotAField())
17587 {
17588 return NotAField();
17589 // Extremely special case for ConstantIndex pseudo-fields -- appending consecutive such
17590 // together collapse to one.
17591 }
17592 else if (a->m_next == nullptr && a->m_fieldHnd == ConstantIndexPseudoField &&
17593 b->m_fieldHnd == ConstantIndexPseudoField)
17594 {
17595 return b;
17596 }
17597 else
17598 {
17599 FieldSeqNode* tmp = Append(a->m_next, b);
17600 FieldSeqNode fsn(a->m_fieldHnd, tmp);
17601 FieldSeqNode* res = nullptr;
17602 if (m_canonMap->Lookup(fsn, &res))
17603 {
17604 return res;
17605 }
17606 else
17607 {
17608 res = m_alloc.allocate<FieldSeqNode>(1);
17609 *res = fsn;
17610 m_canonMap->Set(fsn, res);
17611 return res;
17612 }
17613 }
17614}
17615
17616// Static vars.
17617int FieldSeqStore::FirstElemPseudoFieldStruct;
17618int FieldSeqStore::ConstantIndexPseudoFieldStruct;
17619
17620CORINFO_FIELD_HANDLE FieldSeqStore::FirstElemPseudoField =
17621 (CORINFO_FIELD_HANDLE)&FieldSeqStore::FirstElemPseudoFieldStruct;
17622CORINFO_FIELD_HANDLE FieldSeqStore::ConstantIndexPseudoField =
17623 (CORINFO_FIELD_HANDLE)&FieldSeqStore::ConstantIndexPseudoFieldStruct;
17624
17625bool FieldSeqNode::IsFirstElemFieldSeq()
17626{
17627 // this must be non-null per ISO C++
17628 return m_fieldHnd == FieldSeqStore::FirstElemPseudoField;
17629}
17630
17631bool FieldSeqNode::IsConstantIndexFieldSeq()
17632{
17633 // this must be non-null per ISO C++
17634 return m_fieldHnd == FieldSeqStore::ConstantIndexPseudoField;
17635}
17636
17637bool FieldSeqNode::IsPseudoField()
17638{
17639 if (this == nullptr)
17640 {
17641 return false;
17642 }
17643 return m_fieldHnd == FieldSeqStore::FirstElemPseudoField || m_fieldHnd == FieldSeqStore::ConstantIndexPseudoField;
17644}
17645
17646#ifdef FEATURE_SIMD
17647GenTreeSIMD* Compiler::gtNewSIMDNode(
17648 var_types type, GenTree* op1, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size)
17649{
17650 assert(op1 != nullptr);
17651 SetOpLclRelatedToSIMDIntrinsic(op1);
17652
17653 return new (this, GT_SIMD) GenTreeSIMD(type, op1, simdIntrinsicID, baseType, size);
17654}
17655
17656GenTreeSIMD* Compiler::gtNewSIMDNode(
17657 var_types type, GenTree* op1, GenTree* op2, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size)
17658{
17659 assert(op1 != nullptr);
17660 SetOpLclRelatedToSIMDIntrinsic(op1);
17661 SetOpLclRelatedToSIMDIntrinsic(op2);
17662
17663 return new (this, GT_SIMD) GenTreeSIMD(type, op1, op2, simdIntrinsicID, baseType, size);
17664}
17665
17666//-------------------------------------------------------------------
17667// SetOpLclRelatedToSIMDIntrinsic: Determine if the tree has a local var that needs to be set
17668// as used by a SIMD intrinsic, and if so, set that local var appropriately.
17669//
17670// Arguments:
17671// op - The tree, to be an operand of a new GT_SIMD node, to check.
17672//
17673void Compiler::SetOpLclRelatedToSIMDIntrinsic(GenTree* op)
17674{
17675 if (op != nullptr)
17676 {
17677 if (op->OperIsLocal())
17678 {
17679 setLclRelatedToSIMDIntrinsic(op);
17680 }
17681 else if ((op->OperGet() == GT_OBJ) && (op->gtOp.gtOp1->OperGet() == GT_ADDR) &&
17682 op->gtOp.gtOp1->gtOp.gtOp1->OperIsLocal())
17683 {
17684 setLclRelatedToSIMDIntrinsic(op->gtOp.gtOp1->gtOp.gtOp1);
17685 }
17686 }
17687}
17688
17689bool GenTree::isCommutativeSIMDIntrinsic()
17690{
17691 assert(gtOper == GT_SIMD);
17692 switch (AsSIMD()->gtSIMDIntrinsicID)
17693 {
17694 case SIMDIntrinsicAdd:
17695 case SIMDIntrinsicBitwiseAnd:
17696 case SIMDIntrinsicBitwiseOr:
17697 case SIMDIntrinsicBitwiseXor:
17698 case SIMDIntrinsicEqual:
17699 case SIMDIntrinsicMax:
17700 case SIMDIntrinsicMin:
17701 case SIMDIntrinsicMul:
17702 case SIMDIntrinsicOpEquality:
17703 case SIMDIntrinsicOpInEquality:
17704 return true;
17705 default:
17706 return false;
17707 }
17708}
17709#endif // FEATURE_SIMD
17710
17711#ifdef FEATURE_HW_INTRINSICS
17712bool GenTree::isCommutativeHWIntrinsic() const
17713{
17714 assert(gtOper == GT_HWIntrinsic);
17715
17716#ifdef _TARGET_XARCH_
17717 return HWIntrinsicInfo::IsCommutative(AsHWIntrinsic()->gtHWIntrinsicId);
17718#else
17719 return false;
17720#endif // _TARGET_XARCH_
17721}
17722
17723bool GenTree::isContainableHWIntrinsic() const
17724{
17725 assert(gtOper == GT_HWIntrinsic);
17726
17727#ifdef _TARGET_XARCH_
17728 switch (AsHWIntrinsic()->gtHWIntrinsicId)
17729 {
17730 case NI_SSE_LoadAlignedVector128:
17731 case NI_SSE_LoadScalarVector128:
17732 case NI_SSE_LoadVector128:
17733 case NI_SSE2_LoadAlignedVector128:
17734 case NI_SSE2_LoadScalarVector128:
17735 case NI_SSE2_LoadVector128:
17736 case NI_AVX_LoadAlignedVector256:
17737 case NI_AVX_LoadVector256:
17738 {
17739 return true;
17740 }
17741
17742 default:
17743 {
17744 return false;
17745 }
17746 }
17747#else
17748 return false;
17749#endif // _TARGET_XARCH_
17750}
17751
17752bool GenTree::isRMWHWIntrinsic(Compiler* comp)
17753{
17754 assert(gtOper == GT_HWIntrinsic);
17755 assert(comp != nullptr);
17756
17757#ifdef _TARGET_XARCH_
17758 if (!comp->canUseVexEncoding())
17759 {
17760 return HWIntrinsicInfo::HasRMWSemantics(AsHWIntrinsic()->gtHWIntrinsicId);
17761 }
17762
17763 switch (AsHWIntrinsic()->gtHWIntrinsicId)
17764 {
17765 // TODO-XArch-Cleanup: Move this switch block to be table driven.
17766
17767 case NI_SSE42_Crc32:
17768 case NI_SSE42_X64_Crc32:
17769 case NI_FMA_MultiplyAdd:
17770 case NI_FMA_MultiplyAddNegated:
17771 case NI_FMA_MultiplyAddNegatedScalar:
17772 case NI_FMA_MultiplyAddScalar:
17773 case NI_FMA_MultiplyAddSubtract:
17774 case NI_FMA_MultiplySubtract:
17775 case NI_FMA_MultiplySubtractAdd:
17776 case NI_FMA_MultiplySubtractNegated:
17777 case NI_FMA_MultiplySubtractNegatedScalar:
17778 case NI_FMA_MultiplySubtractScalar:
17779 {
17780 return true;
17781 }
17782
17783 default:
17784 {
17785 return false;
17786 }
17787 }
17788#else
17789 return false;
17790#endif // _TARGET_XARCH_
17791}
17792
17793GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type,
17794 NamedIntrinsic hwIntrinsicID,
17795 var_types baseType,
17796 unsigned size)
17797{
17798 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, hwIntrinsicID, baseType, size);
17799}
17800
17801GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(
17802 var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned simdSize)
17803{
17804 SetOpLclRelatedToSIMDIntrinsic(op1);
17805
17806 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, hwIntrinsicID, baseType, simdSize);
17807}
17808
17809GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(
17810 var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned simdSize)
17811{
17812 SetOpLclRelatedToSIMDIntrinsic(op1);
17813 SetOpLclRelatedToSIMDIntrinsic(op2);
17814
17815 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, op2, hwIntrinsicID, baseType, simdSize);
17816}
17817
17818GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type,
17819 GenTree* op1,
17820 GenTree* op2,
17821 GenTree* op3,
17822 NamedIntrinsic hwIntrinsicID,
17823 var_types baseType,
17824 unsigned size)
17825{
17826 SetOpLclRelatedToSIMDIntrinsic(op1);
17827 SetOpLclRelatedToSIMDIntrinsic(op2);
17828 SetOpLclRelatedToSIMDIntrinsic(op3);
17829
17830 return new (this, GT_HWIntrinsic)
17831 GenTreeHWIntrinsic(type, gtNewArgList(op1, op2, op3), hwIntrinsicID, baseType, size);
17832}
17833
17834GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type,
17835 GenTree* op1,
17836 GenTree* op2,
17837 GenTree* op3,
17838 GenTree* op4,
17839 NamedIntrinsic hwIntrinsicID,
17840 var_types baseType,
17841 unsigned size)
17842{
17843 SetOpLclRelatedToSIMDIntrinsic(op1);
17844 SetOpLclRelatedToSIMDIntrinsic(op2);
17845 SetOpLclRelatedToSIMDIntrinsic(op3);
17846 SetOpLclRelatedToSIMDIntrinsic(op4);
17847
17848 return new (this, GT_HWIntrinsic)
17849 GenTreeHWIntrinsic(type, gtNewArgList(op1, op2, op3, op4), hwIntrinsicID, baseType, size);
17850}
17851
17852GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID)
17853{
17854 SetOpLclRelatedToSIMDIntrinsic(op1);
17855
17856 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, hwIntrinsicID, TYP_UNKNOWN, 0);
17857}
17858
17859GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type,
17860 GenTree* op1,
17861 GenTree* op2,
17862 NamedIntrinsic hwIntrinsicID)
17863{
17864 SetOpLclRelatedToSIMDIntrinsic(op1);
17865 SetOpLclRelatedToSIMDIntrinsic(op2);
17866
17867 return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, op2, hwIntrinsicID, TYP_UNKNOWN, 0);
17868}
17869
17870GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(
17871 var_types type, GenTree* op1, GenTree* op2, GenTree* op3, NamedIntrinsic hwIntrinsicID)
17872{
17873 SetOpLclRelatedToSIMDIntrinsic(op1);
17874 SetOpLclRelatedToSIMDIntrinsic(op2);
17875 SetOpLclRelatedToSIMDIntrinsic(op3);
17876
17877 return new (this, GT_HWIntrinsic)
17878 GenTreeHWIntrinsic(type, gtNewArgList(op1, op2, op3), hwIntrinsicID, TYP_UNKNOWN, 0);
17879}
17880
17881//---------------------------------------------------------------------------------------
17882// gtNewMustThrowException:
17883// create a throw node (calling into JIT helper) that must be thrown.
17884// The result would be a comma node: COMMA(jithelperthrow(void), x) where x's type should be specified.
17885//
17886// Arguments
17887// helper - JIT helper ID
17888// type - return type of the node
17889//
17890// Return Value
17891// pointer to the throw node
17892//
17893GenTree* Compiler::gtNewMustThrowException(unsigned helper, var_types type, CORINFO_CLASS_HANDLE clsHnd)
17894{
17895 GenTreeCall* node = gtNewHelperCallNode(helper, TYP_VOID);
17896 node->gtCallMoreFlags |= GTF_CALL_M_DOES_NOT_RETURN;
17897 if (type != TYP_VOID)
17898 {
17899 unsigned dummyTemp = lvaGrabTemp(true DEBUGARG("dummy temp of must thrown exception"));
17900 if (type == TYP_STRUCT)
17901 {
17902 lvaSetStruct(dummyTemp, clsHnd, false);
17903 type = lvaTable[dummyTemp].lvType; // struct type is normalized
17904 }
17905 else
17906 {
17907 lvaTable[dummyTemp].lvType = type;
17908 }
17909 GenTree* dummyNode = gtNewLclvNode(dummyTemp, type);
17910 return gtNewOperNode(GT_COMMA, type, node, dummyNode);
17911 }
17912 return node;
17913}
17914
17915// Returns true for the HW Instrinsic instructions that have MemoryLoad semantics, false otherwise
17916bool GenTreeHWIntrinsic::OperIsMemoryLoad()
17917{
17918#ifdef _TARGET_XARCH_
17919 // Some xarch instructions have MemoryLoad sematics
17920 HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(gtHWIntrinsicId);
17921 if (category == HW_Category_MemoryLoad)
17922 {
17923 return true;
17924 }
17925 else if (HWIntrinsicInfo::MaybeMemoryLoad(gtHWIntrinsicId))
17926 {
17927 // Some AVX intrinsic (without HW_Category_MemoryLoad) also have MemoryLoad semantics
17928 if (category == HW_Category_SIMDScalar)
17929 {
17930 // Avx2.BroadcastScalarToVector128/256 have vector and pointer overloads both, e.g.,
17931 // Vector128<byte> BroadcastScalarToVector128(Vector128<byte> value)
17932 // Vector128<byte> BroadcastScalarToVector128(byte* source)
17933 // So, we need to check the argument's type is memory-reference (TYP_I_IMPL) or not
17934 assert(HWIntrinsicInfo::lookupNumArgs(this) == 1);
17935 return (gtHWIntrinsicId == NI_AVX2_BroadcastScalarToVector128 ||
17936 gtHWIntrinsicId == NI_AVX2_BroadcastScalarToVector256) &&
17937 gtOp.gtOp1->TypeGet() == TYP_I_IMPL;
17938 }
17939 else if (category == HW_Category_IMM)
17940 {
17941 // Do we have less than 3 operands?
17942 if (HWIntrinsicInfo::lookupNumArgs(this) < 3)
17943 {
17944 return false;
17945 }
17946 else // We have 3 or more operands/args
17947 {
17948 // All the Avx2.Gather* are "load" instructions
17949 if (HWIntrinsicInfo::isAVX2GatherIntrinsic(gtHWIntrinsicId))
17950 {
17951 return true;
17952 }
17953
17954 GenTreeArgList* argList = gtOp.gtOp1->AsArgList();
17955
17956 // Avx/Avx2.InsertVector128 have vector and pointer overloads both, e.g.,
17957 // Vector256<sbyte> InsertVector128(Vector256<sbyte> value, Vector128<sbyte> data, byte index)
17958 // Vector256<sbyte> InsertVector128(Vector256<sbyte> value, sbyte* address, byte index)
17959 // So, we need to check the second argument's type is memory-reference (TYP_I_IMPL) or not
17960 if ((gtHWIntrinsicId == NI_AVX_InsertVector128 || gtHWIntrinsicId == NI_AVX2_InsertVector128) &&
17961 (argList->Rest()->Current()->TypeGet() == TYP_I_IMPL)) // Is the type of the second arg TYP_I_IMPL?
17962 {
17963 // This is Avx/Avx2.InsertVector128
17964 return true;
17965 }
17966 }
17967 }
17968 }
17969#endif // _TARGET_XARCH_
17970 return false;
17971}
17972
17973// Returns true for the HW Instrinsic instructions that have MemoryStore semantics, false otherwise
17974bool GenTreeHWIntrinsic::OperIsMemoryStore()
17975{
17976#ifdef _TARGET_XARCH_
17977 // Some xarch instructions have MemoryStore sematics
17978 HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(gtHWIntrinsicId);
17979 if (category == HW_Category_MemoryStore)
17980 {
17981 return true;
17982 }
17983 else if (HWIntrinsicInfo::MaybeMemoryStore(gtHWIntrinsicId) &&
17984 (category == HW_Category_IMM || category == HW_Category_Scalar))
17985 {
17986 // Some AVX intrinsic (without HW_Category_MemoryStore) also have MemoryStore semantics
17987
17988 // Avx/Avx2.InsertVector128 have vector and pointer overloads both, e.g.,
17989 // Vector128<sbyte> ExtractVector128(Vector256<sbyte> value, byte index)
17990 // void ExtractVector128(sbyte* address, Vector256<sbyte> value, byte index)
17991 // Bmi2/Bmi2.X64.MultiplyNoFlags may return the lower half result by a out argument
17992 // unsafe ulong MultiplyNoFlags(ulong left, ulong right, ulong* low)
17993 //
17994 // So, the 3-argument form is MemoryStore
17995 if (HWIntrinsicInfo::lookupNumArgs(this) == 3)
17996 {
17997 switch (gtHWIntrinsicId)
17998 {
17999 case NI_AVX_ExtractVector128:
18000 case NI_AVX2_ExtractVector128:
18001 case NI_BMI2_MultiplyNoFlags:
18002 case NI_BMI2_X64_MultiplyNoFlags:
18003 return true;
18004 default:
18005 return false;
18006 }
18007 }
18008 }
18009#endif // _TARGET_XARCH_
18010 return false;
18011}
18012
18013// Returns true for the HW Instrinsic instructions that have MemoryLoad semantics, false otherwise
18014bool GenTreeHWIntrinsic::OperIsMemoryLoadOrStore()
18015{
18016#ifdef _TARGET_XARCH_
18017 return OperIsMemoryLoad() || OperIsMemoryStore();
18018#endif // _TARGET_XARCH_
18019 return false;
18020}
18021
18022#endif // FEATURE_HW_INTRINSICS
18023
18024//---------------------------------------------------------------------------------------
18025// InitializeStructReturnType:
18026// Initialize the Return Type Descriptor for a method that returns a struct type
18027//
18028// Arguments
18029// comp - Compiler Instance
18030// retClsHnd - VM handle to the struct type returned by the method
18031//
18032// Return Value
18033// None
18034//
18035void ReturnTypeDesc::InitializeStructReturnType(Compiler* comp, CORINFO_CLASS_HANDLE retClsHnd)
18036{
18037 assert(!m_inited);
18038
18039#if FEATURE_MULTIREG_RET
18040
18041 assert(retClsHnd != NO_CLASS_HANDLE);
18042 unsigned structSize = comp->info.compCompHnd->getClassSize(retClsHnd);
18043
18044 Compiler::structPassingKind howToReturnStruct;
18045 var_types returnType = comp->getReturnTypeForStruct(retClsHnd, &howToReturnStruct, structSize);
18046
18047 switch (howToReturnStruct)
18048 {
18049 case Compiler::SPK_EnclosingType:
18050 m_isEnclosingType = true;
18051 __fallthrough;
18052
18053 case Compiler::SPK_PrimitiveType:
18054 {
18055 assert(returnType != TYP_UNKNOWN);
18056 assert(!varTypeIsStruct(returnType));
18057 m_regType[0] = returnType;
18058 break;
18059 }
18060
18061 case Compiler::SPK_ByValueAsHfa:
18062 {
18063 assert(varTypeIsStruct(returnType));
18064 var_types hfaType = comp->GetHfaType(retClsHnd);
18065
18066 // We should have an hfa struct type
18067 assert(varTypeIsFloating(hfaType));
18068
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)));
18071
18072 // The size of this struct should be evenly divisible by elemSize
18073 assert((structSize % elemSize) == 0);
18074
18075 unsigned hfaCount = (structSize / elemSize);
18076 for (unsigned i = 0; i < hfaCount; ++i)
18077 {
18078 m_regType[i] = hfaType;
18079 }
18080
18081 if (comp->compFloatingPointUsed == false)
18082 {
18083 comp->compFloatingPointUsed = true;
18084 }
18085 break;
18086 }
18087
18088 case Compiler::SPK_ByValue:
18089 {
18090 assert(varTypeIsStruct(returnType));
18091
18092#ifdef UNIX_AMD64_ABI
18093
18094 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
18095 comp->eeGetSystemVAmd64PassStructInRegisterDescriptor(retClsHnd, &structDesc);
18096
18097 assert(structDesc.passedInRegisters);
18098 for (int i = 0; i < structDesc.eightByteCount; i++)
18099 {
18100 assert(i < MAX_RET_REG_COUNT);
18101 m_regType[i] = comp->GetEightByteType(structDesc, i);
18102 }
18103
18104#elif defined(_TARGET_ARM64_)
18105
18106 // a non-HFA struct returned using two registers
18107 //
18108 assert((structSize > TARGET_POINTER_SIZE) && (structSize <= (2 * TARGET_POINTER_SIZE)));
18109
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)
18113 {
18114 m_regType[i] = comp->getJitGCType(gcPtrs[i]);
18115 }
18116
18117#else // _TARGET_XXX_
18118
18119 // This target needs support here!
18120 //
18121 NYI("Unsupported TARGET returning a TYP_STRUCT in InitializeStructReturnType");
18122
18123#endif // UNIX_AMD64_ABI
18124
18125 break; // for case SPK_ByValue
18126 }
18127
18128 case Compiler::SPK_ByReference:
18129
18130 // We are returning using the return buffer argument
18131 // There are no return registers
18132 break;
18133
18134 default:
18135
18136 unreached(); // By the contract of getReturnTypeForStruct we should never get here.
18137
18138 } // end of switch (howToReturnStruct)
18139
18140#endif // FEATURE_MULTIREG_RET
18141
18142#ifdef DEBUG
18143 m_inited = true;
18144#endif
18145}
18146
18147//---------------------------------------------------------------------------------------
18148// InitializeLongReturnType:
18149// Initialize the Return Type Descriptor for a method that returns a TYP_LONG
18150//
18151// Arguments
18152// comp - Compiler Instance
18153//
18154// Return Value
18155// None
18156//
18157void ReturnTypeDesc::InitializeLongReturnType(Compiler* comp)
18158{
18159#if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
18160
18161 // Setups up a ReturnTypeDesc for returning a long using two registers
18162 //
18163 assert(MAX_RET_REG_COUNT >= 2);
18164 m_regType[0] = TYP_INT;
18165 m_regType[1] = TYP_INT;
18166
18167#else // not (_TARGET_X86_ or _TARGET_ARM_)
18168
18169 m_regType[0] = TYP_LONG;
18170
18171#endif // _TARGET_X86_ or _TARGET_ARM_
18172
18173#ifdef DEBUG
18174 m_inited = true;
18175#endif
18176}
18177
18178//-------------------------------------------------------------------
18179// GetABIReturnReg: Return ith return register as per target ABI
18180//
18181// Arguments:
18182// idx - Index of the return register.
18183// The first return register has an index of 0 and so on.
18184//
18185// Return Value:
18186// Returns ith return register as per target ABI.
18187//
18188// Notes:
18189// x86 and ARM return long in multiple registers.
18190// ARM and ARM64 return HFA struct in multiple registers.
18191//
18192regNumber ReturnTypeDesc::GetABIReturnReg(unsigned idx)
18193{
18194 unsigned count = GetReturnRegCount();
18195 assert(idx < count);
18196
18197 regNumber resultReg = REG_NA;
18198
18199#ifdef UNIX_AMD64_ABI
18200 var_types regType0 = GetReturnRegType(0);
18201
18202 if (idx == 0)
18203 {
18204 if (varTypeIsIntegralOrI(regType0))
18205 {
18206 resultReg = REG_INTRET;
18207 }
18208 else
18209 {
18210 noway_assert(varTypeIsFloating(regType0));
18211 resultReg = REG_FLOATRET;
18212 }
18213 }
18214 else if (idx == 1)
18215 {
18216 var_types regType1 = GetReturnRegType(1);
18217
18218 if (varTypeIsIntegralOrI(regType1))
18219 {
18220 if (varTypeIsIntegralOrI(regType0))
18221 {
18222 resultReg = REG_INTRET_1;
18223 }
18224 else
18225 {
18226 resultReg = REG_INTRET;
18227 }
18228 }
18229 else
18230 {
18231 noway_assert(varTypeIsFloating(regType1));
18232
18233 if (varTypeIsFloating(regType0))
18234 {
18235 resultReg = REG_FLOATRET_1;
18236 }
18237 else
18238 {
18239 resultReg = REG_FLOATRET;
18240 }
18241 }
18242 }
18243
18244#elif defined(_TARGET_X86_)
18245
18246 if (idx == 0)
18247 {
18248 resultReg = REG_LNGRET_LO;
18249 }
18250 else if (idx == 1)
18251 {
18252 resultReg = REG_LNGRET_HI;
18253 }
18254
18255#elif defined(_TARGET_ARM_)
18256
18257 var_types regType = GetReturnRegType(idx);
18258 if (varTypeIsIntegralOrI(regType))
18259 {
18260 // Ints are returned in one return register.
18261 // Longs are returned in two return registers.
18262 if (idx == 0)
18263 {
18264 resultReg = REG_LNGRET_LO;
18265 }
18266 else if (idx == 1)
18267 {
18268 resultReg = REG_LNGRET_HI;
18269 }
18270 }
18271 else
18272 {
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)
18278 {
18279 resultReg = (regNumber)((unsigned)(REG_FLOATRET) + idx * 2); // d0, d1, d2 or d3
18280 }
18281 else
18282 {
18283 resultReg = (regNumber)((unsigned)(REG_FLOATRET) + idx); // f0, f1, f2 or f3
18284 }
18285 }
18286
18287#elif defined(_TARGET_ARM64_)
18288
18289 var_types regType = GetReturnRegType(idx);
18290 if (varTypeIsIntegralOrI(regType))
18291 {
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
18294 }
18295 else
18296 {
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
18299 }
18300
18301#endif // TARGET_XXX
18302
18303 assert(resultReg != REG_NA);
18304 return resultReg;
18305}
18306
18307//--------------------------------------------------------------------------------
18308// GetABIReturnRegs: get the mask of return registers as per target arch ABI.
18309//
18310// Arguments:
18311// None
18312//
18313// Return Value:
18314// reg mask of return registers in which the return type is returned.
18315//
18316// Note:
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.
18319//
18320// static
18321regMaskTP ReturnTypeDesc::GetABIReturnRegs()
18322{
18323 regMaskTP resultMask = RBM_NONE;
18324
18325 unsigned count = GetReturnRegCount();
18326 for (unsigned i = 0; i < count; ++i)
18327 {
18328 resultMask |= genRegMask(GetABIReturnReg(i));
18329 }
18330
18331 return resultMask;
18332}
18333
18334//------------------------------------------------------------------------
18335// The following functions manage the gtRsvdRegs set of temporary registers
18336// created by LSRA during code generation.
18337
18338//------------------------------------------------------------------------
18339// AvailableTempRegCount: return the number of available temporary registers in the (optional) given set
18340// (typically, RBM_ALLINT or RBM_ALLFLOAT).
18341//
18342// Arguments:
18343// mask - (optional) Check for available temporary registers only in this set.
18344//
18345// Return Value:
18346// Count of available temporary registers in given set.
18347//
18348unsigned GenTree::AvailableTempRegCount(regMaskTP mask /* = (regMaskTP)-1 */) const
18349{
18350 return genCountBits(gtRsvdRegs & mask);
18351}
18352
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.
18358//
18359// Arguments:
18360// mask - (optional) Get an available temporary register only in this set.
18361//
18362// Return Value:
18363// Available temporary register in given mask.
18364//
18365regNumber GenTree::GetSingleTempReg(regMaskTP mask /* = (regMaskTP)-1 */)
18366{
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.
18371 return tempReg;
18372}
18373
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.
18379//
18380// Arguments:
18381// mask - (optional) Extract an available temporary register only in this set.
18382//
18383// Return Value:
18384// Available temporary register in given mask.
18385//
18386regNumber GenTree::ExtractTempReg(regMaskTP mask /* = (regMaskTP)-1 */)
18387{
18388 regMaskTP availableSet = gtRsvdRegs & mask;
18389 assert(genCountBits(availableSet) >= 1);
18390 regMaskTP tempRegMask = genFindLowestBit(availableSet);
18391 gtRsvdRegs &= ~tempRegMask;
18392 return genRegNumFromMask(tempRegMask);
18393}
18394