Merge pull request #8588 from litian2025/AVX_SSE
[platform/upstream/coreclr.git] / src / jit / compiler.cpp
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
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7 XX                                                                           XX
8 XX                          Compiler                                         XX
9 XX                                                                           XX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12 */
13 #include "jitpch.h"
14 #ifdef _MSC_VER
15 #pragma hdrstop
16 #endif // _MSC_VER
17 #include "hostallocator.h"
18 #include "emit.h"
19 #include "ssabuilder.h"
20 #include "valuenum.h"
21 #include "rangecheck.h"
22
23 #ifndef LEGACY_BACKEND
24 #include "lower.h"
25 #endif // !LEGACY_BACKEND
26
27 #include "jittelemetry.h"
28
29 #if defined(DEBUG)
30 // Column settings for COMPlus_JitDumpIR.  We could(should) make these programmable.
31 #define COLUMN_OPCODE 30
32 #define COLUMN_OPERANDS (COLUMN_OPCODE + 25)
33 #define COLUMN_KINDS 110
34 #define COLUMN_FLAGS (COLUMN_KINDS + 32)
35 #endif
36
37 #if defined(DEBUG)
38 unsigned Compiler::jitTotalMethodCompiled = 0;
39 #endif // defined(DEBUG)
40
41 #if defined(DEBUG)
42 LONG Compiler::jitNestingLevel = 0;
43 #endif // defined(DEBUG)
44
45 #ifdef ALT_JIT
46 // static
47 bool                Compiler::s_pAltJitExcludeAssembliesListInitialized = false;
48 AssemblyNamesList2* Compiler::s_pAltJitExcludeAssembliesList            = nullptr;
49 #endif // ALT_JIT
50
51 /*****************************************************************************
52  *
53  *  Little helpers to grab the current cycle counter value; this is done
54  *  differently based on target architecture, host toolchain, etc. The
55  *  main thing is to keep the overhead absolutely minimal; in fact, on
56  *  x86/x64 we use RDTSC even though it's not thread-safe; GetThreadCycles
57  *  (which is monotonous) is just too expensive.
58  */
59 #ifdef FEATURE_JIT_METHOD_PERF
60
61 #if defined(_HOST_X86_) || defined(_HOST_AMD64_)
62
63 #if defined(_MSC_VER)
64
65 #include <intrin.h>
66 inline bool _our_GetThreadCycles(unsigned __int64* cycleOut)
67 {
68     *cycleOut = __rdtsc();
69     return true;
70 }
71
72 #elif defined(__clang__)
73
74 inline bool _our_GetThreadCycles(unsigned __int64* cycleOut)
75 {
76     uint64_t cycles;
77     asm volatile("rdtsc" : "=A"(cycles));
78     *cycleOut = cycles;
79     return true;
80 }
81
82 #else // neither _MSC_VER nor __clang__
83
84 // The following *might* work - might as well try.
85 #define _our_GetThreadCycles(cp) GetThreadCycles(cp)
86
87 #endif
88
89 #elif defined(_HOST_ARM_) || defined(_HOST_ARM64_)
90
91 // If this doesn't work please see ../gc/gc.cpp for additional ARM
92 // info (and possible solutions).
93 #define _our_GetThreadCycles(cp) GetThreadCycles(cp)
94
95 #else // not x86/x64 and not ARM
96
97 // Don't know what this target is, but let's give it a try; if
98 // someone really wants to make this work, please add the right
99 // code here.
100 #define _our_GetThreadCycles(cp) GetThreadCycles(cp)
101
102 #endif // which host OS
103
104 #endif // FEATURE_JIT_METHOD_PERF
105 /*****************************************************************************/
106 inline unsigned getCurTime()
107 {
108     SYSTEMTIME tim;
109
110     GetSystemTime(&tim);
111
112     return (((tim.wHour * 60) + tim.wMinute) * 60 + tim.wSecond) * 1000 + tim.wMilliseconds;
113 }
114
115 /*****************************************************************************/
116 #ifdef DEBUG
117 /*****************************************************************************/
118
119 static FILE* jitSrcFilePtr;
120
121 static unsigned jitCurSrcLine;
122
123 void Compiler::JitLogEE(unsigned level, const char* fmt, ...)
124 {
125     va_list args;
126
127     if (verbose)
128     {
129         va_start(args, fmt);
130         vflogf(jitstdout, fmt, args);
131         va_end(args);
132     }
133
134     va_start(args, fmt);
135     vlogf(level, fmt, args);
136     va_end(args);
137 }
138
139 void Compiler::compDspSrcLinesByLineNum(unsigned line, bool seek)
140 {
141     if (!jitSrcFilePtr)
142     {
143         return;
144     }
145
146     if (jitCurSrcLine == line)
147     {
148         return;
149     }
150
151     if (jitCurSrcLine > line)
152     {
153         if (!seek)
154         {
155             return;
156         }
157
158         if (fseek(jitSrcFilePtr, 0, SEEK_SET) != 0)
159         {
160             printf("Compiler::compDspSrcLinesByLineNum:  fseek returned an error.\n");
161         }
162         jitCurSrcLine = 0;
163     }
164
165     if (!seek)
166     {
167         printf(";\n");
168     }
169
170     do
171     {
172         char   temp[128];
173         size_t llen;
174
175         if (!fgets(temp, sizeof(temp), jitSrcFilePtr))
176         {
177             return;
178         }
179
180         if (seek)
181         {
182             continue;
183         }
184
185         llen = strlen(temp);
186         if (llen && temp[llen - 1] == '\n')
187         {
188             temp[llen - 1] = 0;
189         }
190
191         printf(";   %s\n", temp);
192     } while (++jitCurSrcLine < line);
193
194     if (!seek)
195     {
196         printf(";\n");
197     }
198 }
199
200 /*****************************************************************************/
201
202 void Compiler::compDspSrcLinesByNativeIP(UNATIVE_OFFSET curIP)
203 {
204     static IPmappingDsc* nextMappingDsc;
205     static unsigned      lastLine;
206
207     if (!opts.dspLines)
208     {
209         return;
210     }
211
212     if (curIP == 0)
213     {
214         if (genIPmappingList)
215         {
216             nextMappingDsc = genIPmappingList;
217             lastLine       = jitGetILoffs(nextMappingDsc->ipmdILoffsx);
218
219             unsigned firstLine = jitGetILoffs(nextMappingDsc->ipmdILoffsx);
220
221             unsigned earlierLine = (firstLine < 5) ? 0 : firstLine - 5;
222
223             compDspSrcLinesByLineNum(earlierLine, true); // display previous 5 lines
224             compDspSrcLinesByLineNum(firstLine, false);
225         }
226         else
227         {
228             nextMappingDsc = nullptr;
229         }
230
231         return;
232     }
233
234     if (nextMappingDsc)
235     {
236         UNATIVE_OFFSET offset = nextMappingDsc->ipmdNativeLoc.CodeOffset(genEmitter);
237
238         if (offset <= curIP)
239         {
240             IL_OFFSET nextOffs = jitGetILoffs(nextMappingDsc->ipmdILoffsx);
241
242             if (lastLine < nextOffs)
243             {
244                 compDspSrcLinesByLineNum(nextOffs);
245             }
246             else
247             {
248                 // This offset corresponds to a previous line. Rewind to that line
249
250                 compDspSrcLinesByLineNum(nextOffs - 2, true);
251                 compDspSrcLinesByLineNum(nextOffs);
252             }
253
254             lastLine       = nextOffs;
255             nextMappingDsc = nextMappingDsc->ipmdNext;
256         }
257     }
258 }
259
260 /*****************************************************************************/
261 #endif // DEBUG
262
263 /*****************************************************************************/
264 #if defined(DEBUG) || MEASURE_NODE_SIZE || MEASURE_BLOCK_SIZE || DISPLAY_SIZES || CALL_ARG_STATS
265
266 static unsigned genMethodCnt;  // total number of methods JIT'ted
267 unsigned        genMethodICnt; // number of interruptible methods
268 unsigned        genMethodNCnt; // number of non-interruptible methods
269 static unsigned genSmallMethodsNeedingExtraMemoryCnt = 0;
270
271 #endif
272
273 /*****************************************************************************/
274 #if MEASURE_NODE_SIZE
275 NodeSizeStats genNodeSizeStats;
276 NodeSizeStats genNodeSizeStatsPerFunc;
277
278 unsigned  genTreeNcntHistBuckets[] = {10, 20, 30, 40, 50, 100, 200, 300, 400, 500, 1000, 5000, 10000, 0};
279 Histogram genTreeNcntHist(HostAllocator::getHostAllocator(), genTreeNcntHistBuckets);
280
281 unsigned  genTreeNsizHistBuckets[] = {1000, 5000, 10000, 50000, 100000, 500000, 1000000, 0};
282 Histogram genTreeNsizHist(HostAllocator::getHostAllocator(), genTreeNsizHistBuckets);
283 #endif // MEASURE_NODE_SIZE
284
285 /*****************************************************************************/
286 #if MEASURE_MEM_ALLOC
287
288 unsigned  memSizeHistBuckets[] = {20, 50, 75, 100, 150, 250, 500, 1000, 5000, 0};
289 Histogram memAllocHist(HostAllocator::getHostAllocator(), memSizeHistBuckets);
290 Histogram memUsedHist(HostAllocator::getHostAllocator(), memSizeHistBuckets);
291
292 #endif // MEASURE_MEM_ALLOC
293
294 /*****************************************************************************
295  *
296  *  Variables to keep track of total code amounts.
297  */
298
299 #if DISPLAY_SIZES
300
301 size_t grossVMsize; // Total IL code size
302 size_t grossNCsize; // Native code + data size
303 size_t totalNCsize; // Native code + data + GC info size (TODO-Cleanup: GC info size only accurate for JIT32_GCENCODER)
304 size_t gcHeaderISize; // GC header      size: interruptible methods
305 size_t gcPtrMapISize; // GC pointer map size: interruptible methods
306 size_t gcHeaderNSize; // GC header      size: non-interruptible methods
307 size_t gcPtrMapNSize; // GC pointer map size: non-interruptible methods
308
309 #endif // DISPLAY_SIZES
310
311 /*****************************************************************************
312  *
313  *  Variables to keep track of argument counts.
314  */
315
316 #if CALL_ARG_STATS
317
318 unsigned argTotalCalls;
319 unsigned argHelperCalls;
320 unsigned argStaticCalls;
321 unsigned argNonVirtualCalls;
322 unsigned argVirtualCalls;
323
324 unsigned argTotalArgs; // total number of args for all calls (including objectPtr)
325 unsigned argTotalDWordArgs;
326 unsigned argTotalLongArgs;
327 unsigned argTotalFloatArgs;
328 unsigned argTotalDoubleArgs;
329
330 unsigned argTotalRegArgs;
331 unsigned argTotalTemps;
332 unsigned argTotalLclVar;
333 unsigned argTotalDeferred;
334 unsigned argTotalConst;
335
336 unsigned argTotalObjPtr;
337 unsigned argTotalGTF_ASGinArgs;
338
339 unsigned argMaxTempsPerMethod;
340
341 unsigned  argCntBuckets[] = {0, 1, 2, 3, 4, 5, 6, 10, 0};
342 Histogram argCntTable(HostAllocator::getHostAllocator(), argCntBuckets);
343
344 unsigned  argDWordCntBuckets[] = {0, 1, 2, 3, 4, 5, 6, 10, 0};
345 Histogram argDWordCntTable(HostAllocator::getHostAllocator(), argDWordCntBuckets);
346
347 unsigned  argDWordLngCntBuckets[] = {0, 1, 2, 3, 4, 5, 6, 10, 0};
348 Histogram argDWordLngCntTable(HostAllocator::getHostAllocator(), argDWordLngCntBuckets);
349
350 unsigned  argTempsCntBuckets[] = {0, 1, 2, 3, 4, 5, 6, 10, 0};
351 Histogram argTempsCntTable(HostAllocator::getHostAllocator(), argTempsCntBuckets);
352
353 #endif // CALL_ARG_STATS
354
355 /*****************************************************************************
356  *
357  *  Variables to keep track of basic block counts.
358  */
359
360 #if COUNT_BASIC_BLOCKS
361
362 //          --------------------------------------------------
363 //          Basic block count frequency table:
364 //          --------------------------------------------------
365 //              <=         1 ===>  26872 count ( 56% of total)
366 //               2 ..      2 ===>    669 count ( 58% of total)
367 //               3 ..      3 ===>   4687 count ( 68% of total)
368 //               4 ..      5 ===>   5101 count ( 78% of total)
369 //               6 ..     10 ===>   5575 count ( 90% of total)
370 //              11 ..     20 ===>   3028 count ( 97% of total)
371 //              21 ..     50 ===>   1108 count ( 99% of total)
372 //              51 ..    100 ===>    182 count ( 99% of total)
373 //             101 ..   1000 ===>     34 count (100% of total)
374 //            1001 ..  10000 ===>      0 count (100% of total)
375 //          --------------------------------------------------
376
377 unsigned  bbCntBuckets[] = {1, 2, 3, 5, 10, 20, 50, 100, 1000, 10000, 0};
378 Histogram bbCntTable(HostAllocator::getHostAllocator(), bbCntBuckets);
379
380 /* Histogram for the IL opcode size of methods with a single basic block */
381
382 unsigned  bbSizeBuckets[] = {1, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 0};
383 Histogram bbOneBBSizeTable(HostAllocator::getHostAllocator(), bbSizeBuckets);
384
385 #endif // COUNT_BASIC_BLOCKS
386
387 /*****************************************************************************
388  *
389  *  Used by optFindNaturalLoops to gather statistical information such as
390  *   - total number of natural loops
391  *   - number of loops with 1, 2, ... exit conditions
392  *   - number of loops that have an iterator (for like)
393  *   - number of loops that have a constant iterator
394  */
395
396 #if COUNT_LOOPS
397
398 unsigned totalLoopMethods;        // counts the total number of methods that have natural loops
399 unsigned maxLoopsPerMethod;       // counts the maximum number of loops a method has
400 unsigned totalLoopOverflows;      // # of methods that identified more loops than we can represent
401 unsigned totalLoopCount;          // counts the total number of natural loops
402 unsigned totalUnnatLoopCount;     // counts the total number of (not-necessarily natural) loops
403 unsigned totalUnnatLoopOverflows; // # of methods that identified more unnatural loops than we can represent
404 unsigned iterLoopCount;           // counts the # of loops with an iterator (for like)
405 unsigned simpleTestLoopCount;     // counts the # of loops with an iterator and a simple loop condition (iter < const)
406 unsigned constIterLoopCount;      // counts the # of loops with a constant iterator (for like)
407 bool     hasMethodLoops;          // flag to keep track if we already counted a method as having loops
408 unsigned loopsThisMethod;         // counts the number of loops in the current method
409 bool     loopOverflowThisMethod;  // True if we exceeded the max # of loops in the method.
410
411 /* Histogram for number of loops in a method */
412
413 unsigned  loopCountBuckets[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0};
414 Histogram loopCountTable(HostAllocator::getHostAllocator(), loopCountBuckets);
415
416 /* Histogram for number of loop exits */
417
418 unsigned  loopExitCountBuckets[] = {0, 1, 2, 3, 4, 5, 6, 0};
419 Histogram loopExitCountTable(HostAllocator::getHostAllocator(), loopExitCountBuckets);
420
421 #endif // COUNT_LOOPS
422
423 //------------------------------------------------------------------------
424 // getJitGCType: Given the VM's CorInfoGCType convert it to the JIT's var_types
425 //
426 // Arguments:
427 //    gcType    - an enum value that originally came from an element
428 //                of the BYTE[] returned from getClassGClayout()
429 //
430 // Return Value:
431 //    The corresponsing enum value from the JIT's var_types
432 //
433 // Notes:
434 //   The gcLayout of each field of a struct is returned from getClassGClayout()
435 //   as a BYTE[] but each BYTE element is actually a CorInfoGCType value
436 //   Note when we 'know' that there is only one element in theis array
437 //   the JIT will often pass the address of a single BYTE, instead of a BYTE[]
438 //
439
440 var_types Compiler::getJitGCType(BYTE gcType)
441 {
442     var_types     result      = TYP_UNKNOWN;
443     CorInfoGCType corInfoType = (CorInfoGCType)gcType;
444
445     if (corInfoType == TYPE_GC_NONE)
446     {
447         result = TYP_I_IMPL;
448     }
449     else if (corInfoType == TYPE_GC_REF)
450     {
451         result = TYP_REF;
452     }
453     else if (corInfoType == TYPE_GC_BYREF)
454     {
455         result = TYP_BYREF;
456     }
457     else
458     {
459         noway_assert(!"Bad value of 'gcType'");
460     }
461     return result;
462 }
463
464 #if FEATURE_MULTIREG_ARGS
465 //---------------------------------------------------------------------------
466 // getStructGcPtrsFromOp: Given a GenTree node of TYP_STRUCT that represents
467 //                        a pass by value argument, return the gcPtr layout
468 //                        for the pointers sized fields
469 // Arguments:
470 //    op         - the operand of TYP_STRUCT that is passed by value
471 //    gcPtrsOut  - an array of BYTES that are written by this method
472 //                 they will contain the VM's CorInfoGCType values
473 //                 for each pointer sized field
474 // Return Value:
475 //     Two [or more] values are written into the gcPtrs array
476 //
477 // Note that for ARM64 there will alwys be exactly two pointer sized fields
478
479 void Compiler::getStructGcPtrsFromOp(GenTreePtr op, BYTE* gcPtrsOut)
480 {
481     assert(op->TypeGet() == TYP_STRUCT);
482
483 #ifdef _TARGET_ARM64_
484     if (op->OperGet() == GT_OBJ)
485     {
486         CORINFO_CLASS_HANDLE objClass = op->gtObj.gtClass;
487
488         int structSize = info.compCompHnd->getClassSize(objClass);
489         assert(structSize <= 2 * TARGET_POINTER_SIZE);
490
491         BYTE gcPtrsTmp[2] = {TYPE_GC_NONE, TYPE_GC_NONE};
492
493         info.compCompHnd->getClassGClayout(objClass, &gcPtrsTmp[0]);
494
495         gcPtrsOut[0] = gcPtrsTmp[0];
496         gcPtrsOut[1] = gcPtrsTmp[1];
497     }
498     else if (op->OperGet() == GT_LCL_VAR)
499     {
500         GenTreeLclVarCommon* varNode = op->AsLclVarCommon();
501         unsigned             varNum  = varNode->gtLclNum;
502         assert(varNum < lvaCount);
503         LclVarDsc* varDsc = &lvaTable[varNum];
504
505         // At this point any TYP_STRUCT LclVar must be a 16-byte pass by value argument
506         assert(varDsc->lvSize() == 2 * TARGET_POINTER_SIZE);
507
508         gcPtrsOut[0] = varDsc->lvGcLayout[0];
509         gcPtrsOut[1] = varDsc->lvGcLayout[1];
510     }
511     else
512 #endif
513     {
514         noway_assert(!"Unsupported Oper for getStructGcPtrsFromOp");
515     }
516 }
517 #endif // FEATURE_MULTIREG_ARGS
518
519 #ifdef ARM_SOFTFP
520 //---------------------------------------------------------------------------
521 // IsSingleFloat32Struct:
522 //    Check if the given struct type contains only one float32 value type
523 //
524 // Arguments:
525 //    clsHnd     - the handle for the struct type
526 //
527 // Return Value:
528 //    true if the given struct type contains only one float32 value type,
529 //    false otherwise.
530 //
531
532 bool Compiler::isSingleFloat32Struct(CORINFO_CLASS_HANDLE clsHnd)
533 {
534     for (;;)
535     {
536         // all of class chain must be of value type and must have only one field
537         if (!info.compCompHnd->isValueClass(clsHnd) || info.compCompHnd->getClassNumInstanceFields(clsHnd) != 1)
538         {
539             return false;
540         }
541
542         CORINFO_CLASS_HANDLE* pClsHnd   = &clsHnd;
543         CORINFO_FIELD_HANDLE  fldHnd    = info.compCompHnd->getFieldInClass(clsHnd, 0);
544         CorInfoType           fieldType = info.compCompHnd->getFieldType(fldHnd, pClsHnd);
545
546         switch (fieldType)
547         {
548             case CORINFO_TYPE_VALUECLASS:
549                 clsHnd = *pClsHnd;
550                 break;
551
552             case CORINFO_TYPE_FLOAT:
553                 return true;
554
555             default:
556                 return false;
557         }
558     }
559 }
560 #endif // ARM_SOFTFP
561
562 //-----------------------------------------------------------------------------
563 // getPrimitiveTypeForStruct:
564 //     Get the "primitive" type that is is used for a struct
565 //     of size 'structSize'.
566 //     We examine 'clsHnd' to check the GC layout of the struct and
567 //     return TYP_REF for structs that simply wrap an object.
568 //     If the struct is a one element HFA, we will return the
569 //     proper floating point type.
570 //
571 // Arguments:
572 //    structSize - the size of the struct type, cannot be zero
573 //    clsHnd     - the handle for the struct type, used when may have
574 //                 an HFA or if we need the GC layout for an object ref.
575 //
576 // Return Value:
577 //    The primitive type (i.e. byte, short, int, long, ref, float, double)
578 //    used to pass or return structs of this size.
579 //    If we shouldn't use a "primitive" type then TYP_UNKNOWN is returned.
580 // Notes:
581 //    For 32-bit targets (X86/ARM32) the 64-bit TYP_LONG type is not
582 //    considered a primitive type by this method.
583 //    So a struct that wraps a 'long' is passed and returned in the
584 //    same way as any other 8-byte struct
585 //    For ARM32 if we have an HFA struct that wraps a 64-bit double
586 //    we will return TYP_DOUBLE.
587 //
588 var_types Compiler::getPrimitiveTypeForStruct(unsigned structSize, CORINFO_CLASS_HANDLE clsHnd)
589 {
590     assert(structSize != 0);
591
592     var_types useType;
593
594     switch (structSize)
595     {
596         case 1:
597             useType = TYP_BYTE;
598             break;
599
600         case 2:
601             useType = TYP_SHORT;
602             break;
603
604 #ifndef _TARGET_XARCH_
605         case 3:
606             useType = TYP_INT;
607             break;
608
609 #endif // _TARGET_XARCH_
610
611 #ifdef _TARGET_64BIT_
612         case 4:
613             if (IsHfa(clsHnd))
614             {
615                 // A structSize of 4 with IsHfa, it must be an HFA of one float
616                 useType = TYP_FLOAT;
617             }
618             else
619             {
620                 useType = TYP_INT;
621             }
622             break;
623
624 #ifndef _TARGET_XARCH_
625         case 5:
626         case 6:
627         case 7:
628             useType = TYP_I_IMPL;
629             break;
630
631 #endif // _TARGET_XARCH_
632 #endif // _TARGET_64BIT_
633
634         case TARGET_POINTER_SIZE:
635 #ifdef ARM_SOFTFP
636             // For ARM_SOFTFP, HFA is unsupported so we need to check in another way
637             // This matters only for size-4 struct cause bigger structs would be processed with RetBuf
638             if (isSingleFloat32Struct(clsHnd))
639 #else  // !ARM_SOFTFP
640             if (IsHfa(clsHnd))
641 #endif // ARM_SOFTFP
642             {
643 #ifdef _TARGET_64BIT_
644                 var_types hfaType = GetHfaType(clsHnd);
645
646                 // A structSize of 8 with IsHfa, we have two possiblities:
647                 // An HFA of one double or an HFA of two floats
648                 //
649                 // Check and exclude the case of an HFA of two floats
650                 if (hfaType == TYP_DOUBLE)
651                 {
652                     // We have an HFA of one double
653                     useType = TYP_DOUBLE;
654                 }
655                 else
656                 {
657                     assert(hfaType == TYP_FLOAT);
658
659                     // We have an HFA of two floats
660                     // This should be passed or returned in two FP registers
661                     useType = TYP_UNKNOWN;
662                 }
663 #else  // a 32BIT target
664                 // A structSize of 4 with IsHfa, it must be an HFA of one float
665                 useType = TYP_FLOAT;
666 #endif // _TARGET_64BIT_
667             }
668             else
669             {
670                 BYTE gcPtr = 0;
671                 // Check if this pointer-sized struct is wrapping a GC object
672                 info.compCompHnd->getClassGClayout(clsHnd, &gcPtr);
673                 useType = getJitGCType(gcPtr);
674             }
675             break;
676
677 #ifdef _TARGET_ARM_
678         case 8:
679             if (IsHfa(clsHnd))
680             {
681                 var_types hfaType = GetHfaType(clsHnd);
682
683                 // A structSize of 8 with IsHfa, we have two possiblities:
684                 // An HFA of one double or an HFA of two floats
685                 //
686                 // Check and exclude the case of an HFA of two floats
687                 if (hfaType == TYP_DOUBLE)
688                 {
689                     // We have an HFA of one double
690                     useType = TYP_DOUBLE;
691                 }
692                 else
693                 {
694                     assert(hfaType == TYP_FLOAT);
695
696                     // We have an HFA of two floats
697                     // This should be passed or returned in two FP registers
698                     useType = TYP_UNKNOWN;
699                 }
700             }
701             else
702             {
703                 // We don't have an HFA
704                 useType = TYP_UNKNOWN;
705             }
706             break;
707 #endif // _TARGET_ARM_
708
709         default:
710             useType = TYP_UNKNOWN;
711             break;
712     }
713
714     return useType;
715 }
716
717 //-----------------------------------------------------------------------------
718 // getArgTypeForStruct:
719 //     Get the type that is used to pass values of the given struct type.
720 //     If you have already retrieved the struct size then it should be
721 //     passed as the optional third argument, as this allows us to avoid
722 //     an extra call to getClassSize(clsHnd)
723 //
724 // Arguments:
725 //    clsHnd       - the handle for the struct type
726 //    wbPassStruct - An "out" argument with information about how
727 //                   the struct is to be passed
728 //    structSize   - the size of the struct type,
729 //                   or zero if we should call getClassSize(clsHnd)
730 //
731 // Return Value:
732 //    For wbPassStruct you can pass a 'nullptr' and nothing will be written
733 //     or returned for that out parameter.
734 //    When *wbPassStruct is SPK_PrimitiveType this method's return value
735 //       is the primitive type used to pass the struct.
736 //    When *wbPassStruct is SPK_ByReference this method's return value
737 //       is always TYP_UNKNOWN and the struct type is passed by reference to a copy
738 //    When *wbPassStruct is SPK_ByValue or SPK_ByValueAsHfa this method's return value
739 //       is always TYP_STRUCT and the struct type is passed by value either
740 //       using multiple registers or on the stack.
741 //
742 // Assumptions:
743 //    The size must be the size of the given type.
744 //    The given class handle must be for a value type (struct).
745 //
746 // Notes:
747 //    About HFA types:
748 //        When the clsHnd is a one element HFA type we return the appropriate
749 //         floating point primitive type and *wbPassStruct is SPK_PrimitiveType
750 //        If there are two or more elements in the HFA type then the this method's
751 //         return value is TYP_STRUCT and *wbPassStruct is SPK_ByValueAsHfa
752 //
753 var_types Compiler::getArgTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
754                                         structPassingKind*   wbPassStruct,
755                                         unsigned             structSize /* = 0 */)
756 {
757     var_types         useType         = TYP_UNKNOWN;
758     structPassingKind howToPassStruct = SPK_Unknown; // We must change this before we return
759
760     if (structSize == 0)
761     {
762         structSize = info.compCompHnd->getClassSize(clsHnd);
763     }
764     assert(structSize > 0);
765
766 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
767
768     // An 8-byte struct may need to be passed in a floating point register
769     // So we always consult the struct "Classifier" routine
770     //
771     SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
772     eeGetSystemVAmd64PassStructInRegisterDescriptor(clsHnd, &structDesc);
773
774     // If we have one eightByteCount then we can set 'useType' based on that
775     if (structDesc.eightByteCount == 1)
776     {
777         // Set 'useType' to the type of the first eightbyte item
778         useType = GetEightByteType(structDesc, 0);
779     }
780
781 #elif defined(_TARGET_X86_)
782
783     // On x86 we never pass structs as primitive types (unless the VM unwraps them for us)
784     useType = TYP_UNKNOWN;
785
786 #else // all other targets
787
788     // The largest primitive type is 8 bytes (TYP_DOUBLE)
789     // so we can skip calling getPrimitiveTypeForStruct when we
790     // have a struct that is larger than that.
791     //
792     if (structSize <= sizeof(double))
793     {
794         // We set the "primitive" useType based upon the structSize
795         // and also examine the clsHnd to see if it is an HFA of count one
796         useType = getPrimitiveTypeForStruct(structSize, clsHnd);
797     }
798
799 #endif // all other targets
800
801     // Did we change this struct type into a simple "primitive" type?
802     //
803     if (useType != TYP_UNKNOWN)
804     {
805         // Yes, we should use the "primitive" type in 'useType'
806         howToPassStruct = SPK_PrimitiveType;
807     }
808     else // We can't replace the struct with a "primitive" type
809     {
810         // See if we can pass this struct by value, possibly in multiple registers
811         // or if we should pass it by reference to a copy
812         //
813         if (structSize <= MAX_PASS_MULTIREG_BYTES)
814         {
815             // Structs that are HFA's are passed by value in multiple registers
816             if (IsHfa(clsHnd))
817             {
818                 // HFA's of count one should have been handled by getPrimitiveTypeForStruct
819                 assert(GetHfaCount(clsHnd) >= 2);
820
821                 // setup wbPassType and useType indicate that this is passed by value as an HFA
822                 //  using multiple registers
823                 //  (when all of the parameters registers are used, then the stack will be used)
824                 howToPassStruct = SPK_ByValueAsHfa;
825                 useType         = TYP_STRUCT;
826             }
827             else // Not an HFA struct type
828             {
829
830 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
831
832                 // The case of (structDesc.eightByteCount == 1) should have already been handled
833                 if (structDesc.eightByteCount > 1)
834                 {
835                     // setup wbPassType and useType indicate that this is passed by value in multiple registers
836                     //  (when all of the parameters registers are used, then the stack will be used)
837                     howToPassStruct = SPK_ByValue;
838                     useType         = TYP_STRUCT;
839                 }
840                 else
841                 {
842                     assert(structDesc.eightByteCount == 0);
843                     // Otherwise we pass this struct by reference to a copy
844                     // setup wbPassType and useType indicate that this is passed using one register
845                     //  (by reference to a copy)
846                     howToPassStruct = SPK_ByReference;
847                     useType         = TYP_UNKNOWN;
848                 }
849
850 #elif defined(_TARGET_ARM64_)
851
852                 // Structs that are pointer sized or smaller should have been handled by getPrimitiveTypeForStruct
853                 assert(structSize > TARGET_POINTER_SIZE);
854
855                 // On ARM64 structs that are 9-16 bytes are passed by value in multiple registers
856                 //
857                 if (structSize <= (TARGET_POINTER_SIZE * 2))
858                 {
859                     // setup wbPassType and useType indicate that this is passed by value in multiple registers
860                     //  (when all of the parameters registers are used, then the stack will be used)
861                     howToPassStruct = SPK_ByValue;
862                     useType         = TYP_STRUCT;
863                 }
864                 else // a structSize that is 17-32 bytes in size
865                 {
866                     // Otherwise we pass this struct by reference to a copy
867                     // setup wbPassType and useType indicate that this is passed using one register
868                     //  (by reference to a copy)
869                     howToPassStruct = SPK_ByReference;
870                     useType         = TYP_UNKNOWN;
871                 }
872
873 #elif defined(_TARGET_X86_) || defined(_TARGET_ARM_)
874
875                 // Otherwise we pass this struct by value on the stack
876                 // setup wbPassType and useType indicate that this is passed by value according to the X86/ARM32 ABI
877                 howToPassStruct = SPK_ByValue;
878                 useType         = TYP_STRUCT;
879
880 #else //  _TARGET_XXX_
881
882                 noway_assert(!"Unhandled TARGET in getArgTypeForStruct (with FEATURE_MULTIREG_ARGS=1)");
883
884 #endif //  _TARGET_XXX_
885             }
886         }
887         else // (structSize > MAX_PASS_MULTIREG_BYTES)
888         {
889             // We have a (large) struct that can't be replaced with a "primitive" type
890             // and can't be passed in multiple registers
891             CLANG_FORMAT_COMMENT_ANCHOR;
892
893 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
894
895             // Otherwise we pass this struct by value on the stack
896             // setup wbPassType and useType indicate that this is passed by value according to the X86/ARM32 ABI
897             howToPassStruct = SPK_ByValue;
898             useType         = TYP_STRUCT;
899
900 #elif defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
901
902             // Otherwise we pass this struct by reference to a copy
903             // setup wbPassType and useType indicate that this is passed using one register (by reference to a copy)
904             howToPassStruct = SPK_ByReference;
905             useType         = TYP_UNKNOWN;
906
907 #else //  _TARGET_XXX_
908
909             noway_assert(!"Unhandled TARGET in getArgTypeForStruct");
910
911 #endif //  _TARGET_XXX_
912         }
913     }
914
915     // 'howToPassStruct' must be set to one of the valid values before we return
916     assert(howToPassStruct != SPK_Unknown);
917     if (wbPassStruct != nullptr)
918     {
919         *wbPassStruct = howToPassStruct;
920     }
921     return useType;
922 }
923
924 //-----------------------------------------------------------------------------
925 // getReturnTypeForStruct:
926 //     Get the type that is used to return values of the given struct type.
927 //     If you have already retrieved the struct size then it should be
928 //     passed as the optional third argument, as this allows us to avoid
929 //     an extra call to getClassSize(clsHnd)
930 //
931 // Arguments:
932 //    clsHnd         - the handle for the struct type
933 //    wbReturnStruct - An "out" argument with information about how
934 //                     the struct is to be returned
935 //    structSize     - the size of the struct type,
936 //                     or zero if we should call getClassSize(clsHnd)
937 //
938 // Return Value:
939 //    For wbReturnStruct you can pass a 'nullptr' and nothing will be written
940 //     or returned for that out parameter.
941 //    When *wbReturnStruct is SPK_PrimitiveType this method's return value
942 //       is the primitive type used to return the struct.
943 //    When *wbReturnStruct is SPK_ByReference this method's return value
944 //       is always TYP_UNKNOWN and the struct type is returned using a return buffer
945 //    When *wbReturnStruct is SPK_ByValue or SPK_ByValueAsHfa this method's return value
946 //       is always TYP_STRUCT and the struct type is returned using multiple registers.
947 //
948 // Assumptions:
949 //    The size must be the size of the given type.
950 //    The given class handle must be for a value type (struct).
951 //
952 // Notes:
953 //    About HFA types:
954 //        When the clsHnd is a one element HFA type then this method's return
955 //          value is the appropriate floating point primitive type and
956 //          *wbReturnStruct is SPK_PrimitiveType.
957 //        If there are two or more elements in the HFA type and the target supports
958 //          multireg return types then the return value is TYP_STRUCT and
959 //          *wbReturnStruct is SPK_ByValueAsHfa.
960 //        Additionally if there are two or more elements in the HFA type and
961 //          the target doesn't support multreg return types then it is treated
962 //          as if it wasn't an HFA type.
963 //    About returning TYP_STRUCT:
964 //        Whenever this method's return value is TYP_STRUCT it always means
965 //         that multiple registers are used to return this struct.
966 //
967 var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
968                                            structPassingKind*   wbReturnStruct /* = nullptr */,
969                                            unsigned             structSize /* = 0 */)
970 {
971     var_types         useType           = TYP_UNKNOWN;
972     structPassingKind howToReturnStruct = SPK_Unknown; // We must change this before we return
973
974     assert(clsHnd != NO_CLASS_HANDLE);
975
976     if (structSize == 0)
977     {
978         structSize = info.compCompHnd->getClassSize(clsHnd);
979     }
980     assert(structSize > 0);
981
982 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
983
984     // An 8-byte struct may need to be returned in a floating point register
985     // So we always consult the struct "Classifier" routine
986     //
987     SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
988     eeGetSystemVAmd64PassStructInRegisterDescriptor(clsHnd, &structDesc);
989
990     // If we have one eightByteCount then we can set 'useType' based on that
991     if (structDesc.eightByteCount == 1)
992     {
993         // Set 'useType' to the type of the first eightbyte item
994         useType = GetEightByteType(structDesc, 0);
995         assert(structDesc.passedInRegisters == true);
996     }
997
998 #else // not UNIX_AMD64
999
1000     // The largest primitive type is 8 bytes (TYP_DOUBLE)
1001     // so we can skip calling getPrimitiveTypeForStruct when we
1002     // have a struct that is larger than that.
1003     //
1004     if (structSize <= sizeof(double))
1005     {
1006         // We set the "primitive" useType based upon the structSize
1007         // and also examine the clsHnd to see if it is an HFA of count one
1008         useType = getPrimitiveTypeForStruct(structSize, clsHnd);
1009     }
1010
1011 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
1012
1013 #ifdef _TARGET_64BIT_
1014     // Note this handles an odd case when FEATURE_MULTIREG_RET is disabled and HFAs are enabled
1015     //
1016     // getPrimitiveTypeForStruct will return TYP_UNKNOWN for a struct that is an HFA of two floats
1017     // because when HFA are enabled, normally we would use two FP registers to pass or return it
1018     //
1019     // But if we don't have support for multiple register return types, we have to change this.
1020     // Since we what we have an 8-byte struct (float + float)  we change useType to TYP_I_IMPL
1021     // so that the struct is returned instead using an 8-byte integer register.
1022     //
1023     if ((FEATURE_MULTIREG_RET == 0) && (useType == TYP_UNKNOWN) && (structSize == (2 * sizeof(float))) && IsHfa(clsHnd))
1024     {
1025         useType = TYP_I_IMPL;
1026     }
1027 #endif
1028
1029     // Did we change this struct type into a simple "primitive" type?
1030     //
1031     if (useType != TYP_UNKNOWN)
1032     {
1033         // Yes, we should use the "primitive" type in 'useType'
1034         howToReturnStruct = SPK_PrimitiveType;
1035     }
1036     else // We can't replace the struct with a "primitive" type
1037     {
1038         // See if we can return this struct by value, possibly in multiple registers
1039         // or if we should return it using a return buffer register
1040         //
1041         if ((FEATURE_MULTIREG_RET == 1) && (structSize <= MAX_RET_MULTIREG_BYTES))
1042         {
1043             // Structs that are HFA's are returned in multiple registers
1044             if (IsHfa(clsHnd))
1045             {
1046                 // HFA's of count one should have been handled by getPrimitiveTypeForStruct
1047                 assert(GetHfaCount(clsHnd) >= 2);
1048
1049                 // setup wbPassType and useType indicate that this is returned by value as an HFA
1050                 //  using multiple registers
1051                 howToReturnStruct = SPK_ByValueAsHfa;
1052                 useType           = TYP_STRUCT;
1053             }
1054             else // Not an HFA struct type
1055             {
1056
1057 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
1058
1059                 // The case of (structDesc.eightByteCount == 1) should have already been handled
1060                 if (structDesc.eightByteCount > 1)
1061                 {
1062                     // setup wbPassType and useType indicate that this is returned by value in multiple registers
1063                     howToReturnStruct = SPK_ByValue;
1064                     useType           = TYP_STRUCT;
1065                     assert(structDesc.passedInRegisters == true);
1066                 }
1067                 else
1068                 {
1069                     assert(structDesc.eightByteCount == 0);
1070                     // Otherwise we return this struct using a return buffer
1071                     // setup wbPassType and useType indicate that this is return using a return buffer register
1072                     //  (reference to a return buffer)
1073                     howToReturnStruct = SPK_ByReference;
1074                     useType           = TYP_UNKNOWN;
1075                     assert(structDesc.passedInRegisters == false);
1076                 }
1077
1078 #elif defined(_TARGET_ARM64_)
1079
1080                 // Structs that are pointer sized or smaller should have been handled by getPrimitiveTypeForStruct
1081                 assert(structSize > TARGET_POINTER_SIZE);
1082
1083                 // On ARM64 structs that are 9-16 bytes are returned by value in multiple registers
1084                 //
1085                 if (structSize <= (TARGET_POINTER_SIZE * 2))
1086                 {
1087                     // setup wbPassType and useType indicate that this is return by value in multiple registers
1088                     howToReturnStruct = SPK_ByValue;
1089                     useType           = TYP_STRUCT;
1090                 }
1091                 else // a structSize that is 17-32 bytes in size
1092                 {
1093                     // Otherwise we return this struct using a return buffer
1094                     // setup wbPassType and useType indicate that this is returned using a return buffer register
1095                     //  (reference to a return buffer)
1096                     howToReturnStruct = SPK_ByReference;
1097                     useType           = TYP_UNKNOWN;
1098                 }
1099
1100 #elif defined(_TARGET_ARM_) || defined(_TARGET_X86_)
1101
1102                 // Otherwise we return this struct using a return buffer
1103                 // setup wbPassType and useType indicate that this is returned using a return buffer register
1104                 //  (reference to a return buffer)
1105                 howToReturnStruct = SPK_ByReference;
1106                 useType           = TYP_UNKNOWN;
1107
1108 #else //  _TARGET_XXX_
1109
1110                 noway_assert(!"Unhandled TARGET in getReturnTypeForStruct (with FEATURE_MULTIREG_ARGS=1)");
1111
1112 #endif //  _TARGET_XXX_
1113             }
1114         }
1115         else // (structSize > MAX_RET_MULTIREG_BYTES) || (FEATURE_MULTIREG_RET == 0)
1116         {
1117             // We have a (large) struct that can't be replaced with a "primitive" type
1118             // and can't be returned in multiple registers
1119
1120             // We return this struct using a return buffer register
1121             // setup wbPassType and useType indicate that this is returned using a return buffer register
1122             //  (reference to a return buffer)
1123             howToReturnStruct = SPK_ByReference;
1124             useType           = TYP_UNKNOWN;
1125         }
1126     }
1127
1128     // 'howToReturnStruct' must be set to one of the valid values before we return
1129     assert(howToReturnStruct != SPK_Unknown);
1130     if (wbReturnStruct != nullptr)
1131     {
1132         *wbReturnStruct = howToReturnStruct;
1133     }
1134     return useType;
1135 }
1136
1137 /*****************************************************************************
1138  * variables to keep track of how many iterations we go in a dataflow pass
1139  */
1140
1141 #if DATAFLOW_ITER
1142
1143 unsigned CSEiterCount; // counts the # of iteration for the CSE dataflow
1144 unsigned CFiterCount;  // counts the # of iteration for the Const Folding dataflow
1145
1146 #endif // DATAFLOW_ITER
1147
1148 #if MEASURE_BLOCK_SIZE
1149 size_t genFlowNodeSize;
1150 size_t genFlowNodeCnt;
1151 #endif // MEASURE_BLOCK_SIZE
1152
1153 /*****************************************************************************/
1154 // We keep track of methods we've already compiled.
1155
1156 /*****************************************************************************
1157  *  Declare the statics
1158  */
1159
1160 #ifdef DEBUG
1161 /* static */
1162 unsigned Compiler::s_compMethodsCount = 0; // to produce unique label names
1163 #endif
1164
1165 #if MEASURE_MEM_ALLOC
1166 /* static */
1167 bool Compiler::s_dspMemStats = false;
1168 #endif
1169
1170 #ifndef PROFILING_SUPPORTED
1171 const bool Compiler::Options::compNoPInvokeInlineCB = false;
1172 #endif
1173
1174 /*****************************************************************************
1175  *
1176  *  One time initialization code
1177  */
1178
1179 /* static */
1180 void Compiler::compStartup()
1181 {
1182 #if DISPLAY_SIZES
1183     grossVMsize = grossNCsize = totalNCsize = 0;
1184 #endif // DISPLAY_SIZES
1185
1186     // Initialize the JIT's allocator.
1187     ArenaAllocator::startup();
1188
1189     /* Initialize the table of tree node sizes */
1190
1191     GenTree::InitNodeSize();
1192
1193 #ifdef JIT32_GCENCODER
1194     // Initialize the GC encoder lookup table
1195
1196     GCInfo::gcInitEncoderLookupTable();
1197 #endif
1198
1199     /* Initialize the emitter */
1200
1201     emitter::emitInit();
1202
1203     // Static vars of ValueNumStore
1204     ValueNumStore::InitValueNumStoreStatics();
1205
1206     compDisplayStaticSizes(jitstdout);
1207 }
1208
1209 /*****************************************************************************
1210  *
1211  *  One time finalization code
1212  */
1213
1214 /* static */
1215 void Compiler::compShutdown()
1216 {
1217 #ifdef ALT_JIT
1218     if (s_pAltJitExcludeAssembliesList != nullptr)
1219     {
1220         s_pAltJitExcludeAssembliesList->~AssemblyNamesList2(); // call the destructor
1221         s_pAltJitExcludeAssembliesList = nullptr;
1222     }
1223 #endif // ALT_JIT
1224
1225     ArenaAllocator::shutdown();
1226
1227     /* Shut down the emitter */
1228
1229     emitter::emitDone();
1230
1231 #if defined(DEBUG) || defined(INLINE_DATA)
1232     // Finish reading and/or writing inline xml
1233     InlineStrategy::FinalizeXml();
1234 #endif // defined(DEBUG) || defined(INLINE_DATA)
1235
1236 #if defined(DEBUG) || MEASURE_NODE_SIZE || MEASURE_BLOCK_SIZE || DISPLAY_SIZES || CALL_ARG_STATS
1237     if (genMethodCnt == 0)
1238     {
1239         return;
1240     }
1241 #endif
1242
1243 #if NODEBASH_STATS
1244     GenTree::ReportOperBashing(jitstdout);
1245 #endif
1246
1247     // Where should we write our statistics output?
1248     FILE* fout = jitstdout;
1249
1250 #ifdef FEATURE_JIT_METHOD_PERF
1251     if (compJitTimeLogFilename != nullptr)
1252     {
1253         FILE* jitTimeLogFile = _wfopen(compJitTimeLogFilename, W("a"));
1254         if (jitTimeLogFile != nullptr)
1255         {
1256             CompTimeSummaryInfo::s_compTimeSummary.Print(jitTimeLogFile);
1257             fclose(jitTimeLogFile);
1258         }
1259     }
1260 #endif // FEATURE_JIT_METHOD_PERF
1261
1262 #if FUNC_INFO_LOGGING
1263     if (compJitFuncInfoFile != nullptr)
1264     {
1265         fclose(compJitFuncInfoFile);
1266         compJitFuncInfoFile = nullptr;
1267     }
1268 #endif // FUNC_INFO_LOGGING
1269
1270 #if COUNT_RANGECHECKS
1271     if (optRangeChkAll > 0)
1272     {
1273         fprintf(fout, "Removed %u of %u range checks\n", optRangeChkRmv, optRangeChkAll);
1274     }
1275 #endif // COUNT_RANGECHECKS
1276
1277 #if COUNT_AST_OPERS
1278
1279     // Add up all the counts so that we can show percentages of total
1280     unsigned gtc = 0;
1281     for (unsigned op = 0; op < GT_COUNT; op++)
1282         gtc += GenTree::s_gtNodeCounts[op];
1283
1284     if (gtc > 0)
1285     {
1286         unsigned rem_total = gtc;
1287         unsigned rem_large = 0;
1288         unsigned rem_small = 0;
1289
1290         unsigned tot_large = 0;
1291         unsigned tot_small = 0;
1292
1293         fprintf(fout, "\nGenTree operator counts (approximate):\n\n");
1294
1295         for (unsigned op = 0; op < GT_COUNT; op++)
1296         {
1297             unsigned siz = GenTree::s_gtTrueSizes[op];
1298             unsigned cnt = GenTree::s_gtNodeCounts[op];
1299             double   pct = 100.0 * cnt / gtc;
1300
1301             if (siz > TREE_NODE_SZ_SMALL)
1302                 tot_large += cnt;
1303             else
1304                 tot_small += cnt;
1305
1306             // Let's not show anything below a threshold
1307             if (pct >= 0.5)
1308             {
1309                 fprintf(fout, "    GT_%-17s   %7u (%4.1lf%%) %3u bytes each\n", GenTree::OpName((genTreeOps)op), cnt,
1310                         pct, siz);
1311                 rem_total -= cnt;
1312             }
1313             else
1314             {
1315                 if (siz > TREE_NODE_SZ_SMALL)
1316                     rem_large += cnt;
1317                 else
1318                     rem_small += cnt;
1319             }
1320         }
1321         if (rem_total > 0)
1322         {
1323             fprintf(fout, "    All other GT_xxx ...   %7u (%4.1lf%%) ... %4.1lf%% small + %4.1lf%% large\n", rem_total,
1324                     100.0 * rem_total / gtc, 100.0 * rem_small / gtc, 100.0 * rem_large / gtc);
1325         }
1326         fprintf(fout, "    -----------------------------------------------------\n");
1327         fprintf(fout, "    Total    .......   %11u --ALL-- ... %4.1lf%% small + %4.1lf%% large\n", gtc,
1328                 100.0 * tot_small / gtc, 100.0 * tot_large / gtc);
1329         fprintf(fout, "\n");
1330     }
1331
1332 #endif // COUNT_AST_OPERS
1333
1334 #if DISPLAY_SIZES
1335
1336     if (grossVMsize && grossNCsize)
1337     {
1338         fprintf(fout, "\n");
1339         fprintf(fout, "--------------------------------------\n");
1340         fprintf(fout, "Function and GC info size stats\n");
1341         fprintf(fout, "--------------------------------------\n");
1342
1343         fprintf(fout, "[%7u VM, %8u %6s %4u%%] %s\n", grossVMsize, grossNCsize, Target::g_tgtCPUName,
1344                 100 * grossNCsize / grossVMsize, "Total (excluding GC info)");
1345
1346         fprintf(fout, "[%7u VM, %8u %6s %4u%%] %s\n", grossVMsize, totalNCsize, Target::g_tgtCPUName,
1347                 100 * totalNCsize / grossVMsize, "Total (including GC info)");
1348
1349         if (gcHeaderISize || gcHeaderNSize)
1350         {
1351             fprintf(fout, "\n");
1352
1353             fprintf(fout, "GC tables   : [%7uI,%7uN] %7u byt  (%u%% of IL, %u%% of %s).\n",
1354                     gcHeaderISize + gcPtrMapISize, gcHeaderNSize + gcPtrMapNSize, totalNCsize - grossNCsize,
1355                     100 * (totalNCsize - grossNCsize) / grossVMsize, 100 * (totalNCsize - grossNCsize) / grossNCsize,
1356                     Target::g_tgtCPUName);
1357
1358             fprintf(fout, "GC headers  : [%7uI,%7uN] %7u byt, [%4.1fI,%4.1fN] %4.1f byt/meth\n", gcHeaderISize,
1359                     gcHeaderNSize, gcHeaderISize + gcHeaderNSize, (float)gcHeaderISize / (genMethodICnt + 0.001),
1360                     (float)gcHeaderNSize / (genMethodNCnt + 0.001),
1361                     (float)(gcHeaderISize + gcHeaderNSize) / genMethodCnt);
1362
1363             fprintf(fout, "GC ptr maps : [%7uI,%7uN] %7u byt, [%4.1fI,%4.1fN] %4.1f byt/meth\n", gcPtrMapISize,
1364                     gcPtrMapNSize, gcPtrMapISize + gcPtrMapNSize, (float)gcPtrMapISize / (genMethodICnt + 0.001),
1365                     (float)gcPtrMapNSize / (genMethodNCnt + 0.001),
1366                     (float)(gcPtrMapISize + gcPtrMapNSize) / genMethodCnt);
1367         }
1368         else
1369         {
1370             fprintf(fout, "\n");
1371
1372             fprintf(fout, "GC tables   take up %u bytes (%u%% of instr, %u%% of %6s code).\n",
1373                     totalNCsize - grossNCsize, 100 * (totalNCsize - grossNCsize) / grossVMsize,
1374                     100 * (totalNCsize - grossNCsize) / grossNCsize, Target::g_tgtCPUName);
1375         }
1376
1377 #ifdef DEBUG
1378 #if DOUBLE_ALIGN
1379         fprintf(fout, "%u out of %u methods generated with double-aligned stack\n",
1380                 Compiler::s_lvaDoubleAlignedProcsCount, genMethodCnt);
1381 #endif
1382 #endif
1383     }
1384
1385 #endif // DISPLAY_SIZES
1386
1387 #if CALL_ARG_STATS
1388     compDispCallArgStats(fout);
1389 #endif
1390
1391 #if COUNT_BASIC_BLOCKS
1392     fprintf(fout, "--------------------------------------------------\n");
1393     fprintf(fout, "Basic block count frequency table:\n");
1394     fprintf(fout, "--------------------------------------------------\n");
1395     bbCntTable.dump(fout);
1396     fprintf(fout, "--------------------------------------------------\n");
1397
1398     fprintf(fout, "\n");
1399
1400     fprintf(fout, "--------------------------------------------------\n");
1401     fprintf(fout, "IL method size frequency table for methods with a single basic block:\n");
1402     fprintf(fout, "--------------------------------------------------\n");
1403     bbOneBBSizeTable.dump(fout);
1404     fprintf(fout, "--------------------------------------------------\n");
1405 #endif // COUNT_BASIC_BLOCKS
1406
1407 #if COUNT_LOOPS
1408
1409     fprintf(fout, "\n");
1410     fprintf(fout, "---------------------------------------------------\n");
1411     fprintf(fout, "Loop stats\n");
1412     fprintf(fout, "---------------------------------------------------\n");
1413     fprintf(fout, "Total number of methods with loops is %5u\n", totalLoopMethods);
1414     fprintf(fout, "Total number of              loops is %5u\n", totalLoopCount);
1415     fprintf(fout, "Maximum number of loops per method is %5u\n", maxLoopsPerMethod);
1416     fprintf(fout, "# of methods overflowing nat loop table is %5u\n", totalLoopOverflows);
1417     fprintf(fout, "Total number of 'unnatural' loops is %5u\n", totalUnnatLoopCount);
1418     fprintf(fout, "# of methods overflowing unnat loop limit is %5u\n", totalUnnatLoopOverflows);
1419     fprintf(fout, "Total number of loops with an         iterator is %5u\n", iterLoopCount);
1420     fprintf(fout, "Total number of loops with a simple   iterator is %5u\n", simpleTestLoopCount);
1421     fprintf(fout, "Total number of loops with a constant iterator is %5u\n", constIterLoopCount);
1422
1423     fprintf(fout, "--------------------------------------------------\n");
1424     fprintf(fout, "Loop count frequency table:\n");
1425     fprintf(fout, "--------------------------------------------------\n");
1426     loopCountTable.dump(fout);
1427     fprintf(fout, "--------------------------------------------------\n");
1428     fprintf(fout, "Loop exit count frequency table:\n");
1429     fprintf(fout, "--------------------------------------------------\n");
1430     loopExitCountTable.dump(fout);
1431     fprintf(fout, "--------------------------------------------------\n");
1432
1433 #endif // COUNT_LOOPS
1434
1435 #if DATAFLOW_ITER
1436
1437     fprintf(fout, "---------------------------------------------------\n");
1438     fprintf(fout, "Total number of iterations in the CSE dataflow loop is %5u\n", CSEiterCount);
1439     fprintf(fout, "Total number of iterations in the  CF dataflow loop is %5u\n", CFiterCount);
1440
1441 #endif // DATAFLOW_ITER
1442
1443 #if MEASURE_NODE_SIZE
1444
1445     fprintf(fout, "\n");
1446     fprintf(fout, "---------------------------------------------------\n");
1447     fprintf(fout, "GenTree node allocation stats\n");
1448     fprintf(fout, "---------------------------------------------------\n");
1449
1450     fprintf(fout, "Allocated %6u tree nodes (%7u bytes total, avg %4u bytes per method)\n",
1451             genNodeSizeStats.genTreeNodeCnt, genNodeSizeStats.genTreeNodeSize,
1452             genNodeSizeStats.genTreeNodeSize / genMethodCnt);
1453
1454     fprintf(fout, "Allocated %7u bytes of unused tree node space (%3.2f%%)\n",
1455             genNodeSizeStats.genTreeNodeSize - genNodeSizeStats.genTreeNodeActualSize,
1456             (float)(100 * (genNodeSizeStats.genTreeNodeSize - genNodeSizeStats.genTreeNodeActualSize)) /
1457                 genNodeSizeStats.genTreeNodeSize);
1458
1459     fprintf(fout, "\n");
1460     fprintf(fout, "---------------------------------------------------\n");
1461     fprintf(fout, "Distribution of per-method GenTree node counts:\n");
1462     genTreeNcntHist.dump(fout);
1463
1464     fprintf(fout, "\n");
1465     fprintf(fout, "---------------------------------------------------\n");
1466     fprintf(fout, "Distribution of per-method GenTree node  allocations (in bytes):\n");
1467     genTreeNsizHist.dump(fout);
1468
1469 #endif // MEASURE_NODE_SIZE
1470
1471 #if MEASURE_BLOCK_SIZE
1472
1473     fprintf(fout, "\n");
1474     fprintf(fout, "---------------------------------------------------\n");
1475     fprintf(fout, "BasicBlock and flowList/BasicBlockList allocation stats\n");
1476     fprintf(fout, "---------------------------------------------------\n");
1477
1478     fprintf(fout, "Allocated %6u basic blocks (%7u bytes total, avg %4u bytes per method)\n", BasicBlock::s_Count,
1479             BasicBlock::s_Size, BasicBlock::s_Size / genMethodCnt);
1480     fprintf(fout, "Allocated %6u flow nodes (%7u bytes total, avg %4u bytes per method)\n", genFlowNodeCnt,
1481             genFlowNodeSize, genFlowNodeSize / genMethodCnt);
1482
1483 #endif // MEASURE_BLOCK_SIZE
1484
1485 #if MEASURE_MEM_ALLOC
1486
1487     if (s_dspMemStats)
1488     {
1489         fprintf(fout, "\nAll allocations:\n");
1490         s_aggMemStats.Print(jitstdout);
1491
1492         fprintf(fout, "\nLargest method:\n");
1493         s_maxCompMemStats.Print(jitstdout);
1494
1495         fprintf(fout, "\n");
1496         fprintf(fout, "---------------------------------------------------\n");
1497         fprintf(fout, "Distribution of total memory allocated per method (in KB):\n");
1498         memAllocHist.dump(fout);
1499
1500         fprintf(fout, "\n");
1501         fprintf(fout, "---------------------------------------------------\n");
1502         fprintf(fout, "Distribution of total memory used      per method (in KB):\n");
1503         memUsedHist.dump(fout);
1504     }
1505
1506 #endif // MEASURE_MEM_ALLOC
1507
1508 #if LOOP_HOIST_STATS
1509 #ifdef DEBUG // Always display loop stats in retail
1510     if (JitConfig.DisplayLoopHoistStats() != 0)
1511 #endif // DEBUG
1512     {
1513         PrintAggregateLoopHoistStats(jitstdout);
1514     }
1515 #endif // LOOP_HOIST_STATS
1516
1517 #if MEASURE_PTRTAB_SIZE
1518
1519     fprintf(fout, "\n");
1520     fprintf(fout, "---------------------------------------------------\n");
1521     fprintf(fout, "GC pointer table stats\n");
1522     fprintf(fout, "---------------------------------------------------\n");
1523
1524     fprintf(fout, "Reg pointer descriptor size (internal): %8u (avg %4u per method)\n", GCInfo::s_gcRegPtrDscSize,
1525             GCInfo::s_gcRegPtrDscSize / genMethodCnt);
1526
1527     fprintf(fout, "Total pointer table size: %8u (avg %4u per method)\n", GCInfo::s_gcTotalPtrTabSize,
1528             GCInfo::s_gcTotalPtrTabSize / genMethodCnt);
1529
1530 #endif // MEASURE_PTRTAB_SIZE
1531
1532 #if MEASURE_NODE_SIZE || MEASURE_BLOCK_SIZE || MEASURE_PTRTAB_SIZE || DISPLAY_SIZES
1533
1534     if (genMethodCnt != 0)
1535     {
1536         fprintf(fout, "\n");
1537         fprintf(fout, "A total of %6u methods compiled", genMethodCnt);
1538 #if DISPLAY_SIZES
1539         if (genMethodICnt || genMethodNCnt)
1540         {
1541             fprintf(fout, " (%u interruptible, %u non-interruptible)", genMethodICnt, genMethodNCnt);
1542         }
1543 #endif // DISPLAY_SIZES
1544         fprintf(fout, ".\n");
1545     }
1546
1547 #endif // MEASURE_NODE_SIZE || MEASURE_BLOCK_SIZE || MEASURE_PTRTAB_SIZE || DISPLAY_SIZES
1548
1549 #if EMITTER_STATS
1550     emitterStats(fout);
1551 #endif
1552
1553 #if MEASURE_FATAL
1554     fprintf(fout, "\n");
1555     fprintf(fout, "---------------------------------------------------\n");
1556     fprintf(fout, "Fatal errors stats\n");
1557     fprintf(fout, "---------------------------------------------------\n");
1558     fprintf(fout, "   badCode:             %u\n", fatal_badCode);
1559     fprintf(fout, "   noWay:               %u\n", fatal_noWay);
1560     fprintf(fout, "   NOMEM:               %u\n", fatal_NOMEM);
1561     fprintf(fout, "   noWayAssertBody:     %u\n", fatal_noWayAssertBody);
1562 #ifdef DEBUG
1563     fprintf(fout, "   noWayAssertBodyArgs: %u\n", fatal_noWayAssertBodyArgs);
1564 #endif // DEBUG
1565     fprintf(fout, "   NYI:                 %u\n", fatal_NYI);
1566 #endif // MEASURE_FATAL
1567 }
1568
1569 /*****************************************************************************
1570  *  Display static data structure sizes.
1571  */
1572
1573 /* static */
1574 void Compiler::compDisplayStaticSizes(FILE* fout)
1575 {
1576
1577 #if MEASURE_NODE_SIZE
1578     GenTree::DumpNodeSizes(fout);
1579 #endif
1580
1581 #if MEASURE_BLOCK_SIZE
1582
1583     BasicBlock* bbDummy = nullptr;
1584
1585     fprintf(fout, "\n");
1586     fprintf(fout, "Offset / size of bbNext                = %3u / %3u\n", offsetof(BasicBlock, bbNext),
1587             sizeof(bbDummy->bbNext));
1588     fprintf(fout, "Offset / size of bbNum                 = %3u / %3u\n", offsetof(BasicBlock, bbNum),
1589             sizeof(bbDummy->bbNum));
1590     fprintf(fout, "Offset / size of bbPostOrderNum        = %3u / %3u\n", offsetof(BasicBlock, bbPostOrderNum),
1591             sizeof(bbDummy->bbPostOrderNum));
1592     fprintf(fout, "Offset / size of bbRefs                = %3u / %3u\n", offsetof(BasicBlock, bbRefs),
1593             sizeof(bbDummy->bbRefs));
1594     fprintf(fout, "Offset / size of bbFlags               = %3u / %3u\n", offsetof(BasicBlock, bbFlags),
1595             sizeof(bbDummy->bbFlags));
1596     fprintf(fout, "Offset / size of bbWeight              = %3u / %3u\n", offsetof(BasicBlock, bbWeight),
1597             sizeof(bbDummy->bbWeight));
1598     fprintf(fout, "Offset / size of bbJumpKind            = %3u / %3u\n", offsetof(BasicBlock, bbJumpKind),
1599             sizeof(bbDummy->bbJumpKind));
1600     fprintf(fout, "Offset / size of bbJumpOffs            = %3u / %3u\n", offsetof(BasicBlock, bbJumpOffs),
1601             sizeof(bbDummy->bbJumpOffs));
1602     fprintf(fout, "Offset / size of bbJumpDest            = %3u / %3u\n", offsetof(BasicBlock, bbJumpDest),
1603             sizeof(bbDummy->bbJumpDest));
1604     fprintf(fout, "Offset / size of bbJumpSwt             = %3u / %3u\n", offsetof(BasicBlock, bbJumpSwt),
1605             sizeof(bbDummy->bbJumpSwt));
1606     fprintf(fout, "Offset / size of bbEntryState          = %3u / %3u\n", offsetof(BasicBlock, bbEntryState),
1607             sizeof(bbDummy->bbEntryState));
1608     fprintf(fout, "Offset / size of bbStkTempsIn          = %3u / %3u\n", offsetof(BasicBlock, bbStkTempsIn),
1609             sizeof(bbDummy->bbStkTempsIn));
1610     fprintf(fout, "Offset / size of bbStkTempsOut         = %3u / %3u\n", offsetof(BasicBlock, bbStkTempsOut),
1611             sizeof(bbDummy->bbStkTempsOut));
1612     fprintf(fout, "Offset / size of bbTryIndex            = %3u / %3u\n", offsetof(BasicBlock, bbTryIndex),
1613             sizeof(bbDummy->bbTryIndex));
1614     fprintf(fout, "Offset / size of bbHndIndex            = %3u / %3u\n", offsetof(BasicBlock, bbHndIndex),
1615             sizeof(bbDummy->bbHndIndex));
1616     fprintf(fout, "Offset / size of bbCatchTyp            = %3u / %3u\n", offsetof(BasicBlock, bbCatchTyp),
1617             sizeof(bbDummy->bbCatchTyp));
1618     fprintf(fout, "Offset / size of bbStkDepth            = %3u / %3u\n", offsetof(BasicBlock, bbStkDepth),
1619             sizeof(bbDummy->bbStkDepth));
1620     fprintf(fout, "Offset / size of bbFPinVars            = %3u / %3u\n", offsetof(BasicBlock, bbFPinVars),
1621             sizeof(bbDummy->bbFPinVars));
1622     fprintf(fout, "Offset / size of bbPreds               = %3u / %3u\n", offsetof(BasicBlock, bbPreds),
1623             sizeof(bbDummy->bbPreds));
1624     fprintf(fout, "Offset / size of bbReach               = %3u / %3u\n", offsetof(BasicBlock, bbReach),
1625             sizeof(bbDummy->bbReach));
1626     fprintf(fout, "Offset / size of bbIDom                = %3u / %3u\n", offsetof(BasicBlock, bbIDom),
1627             sizeof(bbDummy->bbIDom));
1628     fprintf(fout, "Offset / size of bbDfsNum              = %3u / %3u\n", offsetof(BasicBlock, bbDfsNum),
1629             sizeof(bbDummy->bbDfsNum));
1630     fprintf(fout, "Offset / size of bbCodeOffs            = %3u / %3u\n", offsetof(BasicBlock, bbCodeOffs),
1631             sizeof(bbDummy->bbCodeOffs));
1632     fprintf(fout, "Offset / size of bbCodeOffsEnd         = %3u / %3u\n", offsetof(BasicBlock, bbCodeOffsEnd),
1633             sizeof(bbDummy->bbCodeOffsEnd));
1634     fprintf(fout, "Offset / size of bbVarUse              = %3u / %3u\n", offsetof(BasicBlock, bbVarUse),
1635             sizeof(bbDummy->bbVarUse));
1636     fprintf(fout, "Offset / size of bbVarDef              = %3u / %3u\n", offsetof(BasicBlock, bbVarDef),
1637             sizeof(bbDummy->bbVarDef));
1638     fprintf(fout, "Offset / size of bbLiveIn              = %3u / %3u\n", offsetof(BasicBlock, bbLiveIn),
1639             sizeof(bbDummy->bbLiveIn));
1640     fprintf(fout, "Offset / size of bbLiveOut             = %3u / %3u\n", offsetof(BasicBlock, bbLiveOut),
1641             sizeof(bbDummy->bbLiveOut));
1642     fprintf(fout, "Offset / size of bbHeapSsaPhiFunc      = %3u / %3u\n", offsetof(BasicBlock, bbHeapSsaPhiFunc),
1643             sizeof(bbDummy->bbHeapSsaPhiFunc));
1644     fprintf(fout, "Offset / size of bbHeapSsaNumIn        = %3u / %3u\n", offsetof(BasicBlock, bbHeapSsaNumIn),
1645             sizeof(bbDummy->bbHeapSsaNumIn));
1646     fprintf(fout, "Offset / size of bbHeapSsaNumOut       = %3u / %3u\n", offsetof(BasicBlock, bbHeapSsaNumOut),
1647             sizeof(bbDummy->bbHeapSsaNumOut));
1648     fprintf(fout, "Offset / size of bbScope               = %3u / %3u\n", offsetof(BasicBlock, bbScope),
1649             sizeof(bbDummy->bbScope));
1650     fprintf(fout, "Offset / size of bbCseGen              = %3u / %3u\n", offsetof(BasicBlock, bbCseGen),
1651             sizeof(bbDummy->bbCseGen));
1652     fprintf(fout, "Offset / size of bbCseIn               = %3u / %3u\n", offsetof(BasicBlock, bbCseIn),
1653             sizeof(bbDummy->bbCseIn));
1654     fprintf(fout, "Offset / size of bbCseOut              = %3u / %3u\n", offsetof(BasicBlock, bbCseOut),
1655             sizeof(bbDummy->bbCseOut));
1656
1657     fprintf(fout, "Offset / size of bbEmitCookie          = %3u / %3u\n", offsetof(BasicBlock, bbEmitCookie),
1658             sizeof(bbDummy->bbEmitCookie));
1659
1660 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
1661     fprintf(fout, "Offset / size of bbUnwindNopEmitCookie = %3u / %3u\n", offsetof(BasicBlock, bbUnwindNopEmitCookie),
1662             sizeof(bbDummy->bbUnwindNopEmitCookie));
1663 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
1664
1665 #ifdef VERIFIER
1666     fprintf(fout, "Offset / size of bbStackIn             = %3u / %3u\n", offsetof(BasicBlock, bbStackIn),
1667             sizeof(bbDummy->bbStackIn));
1668     fprintf(fout, "Offset / size of bbStackOut            = %3u / %3u\n", offsetof(BasicBlock, bbStackOut),
1669             sizeof(bbDummy->bbStackOut));
1670     fprintf(fout, "Offset / size of bbTypesIn             = %3u / %3u\n", offsetof(BasicBlock, bbTypesIn),
1671             sizeof(bbDummy->bbTypesIn));
1672     fprintf(fout, "Offset / size of bbTypesOut            = %3u / %3u\n", offsetof(BasicBlock, bbTypesOut),
1673             sizeof(bbDummy->bbTypesOut));
1674 #endif // VERIFIER
1675
1676 #if FEATURE_STACK_FP_X87
1677     fprintf(fout, "Offset / size of bbFPStateX87          = %3u / %3u\n", offsetof(BasicBlock, bbFPStateX87),
1678             sizeof(bbDummy->bbFPStateX87));
1679 #endif // FEATURE_STACK_FP_X87
1680
1681 #ifdef DEBUG
1682     fprintf(fout, "Offset / size of bbLoopNum             = %3u / %3u\n", offsetof(BasicBlock, bbLoopNum),
1683             sizeof(bbDummy->bbLoopNum));
1684 #endif // DEBUG
1685
1686     fprintf(fout, "\n");
1687     fprintf(fout, "Size   of BasicBlock                   = %3u\n", sizeof(BasicBlock));
1688
1689 #endif // MEASURE_BLOCK_SIZE
1690
1691 #if EMITTER_STATS
1692     emitterStaticStats(fout);
1693 #endif
1694 }
1695
1696 /*****************************************************************************
1697  *
1698  *  Constructor
1699  */
1700
1701 void Compiler::compInit(ArenaAllocator* pAlloc, InlineInfo* inlineInfo)
1702 {
1703     assert(pAlloc);
1704     compAllocator = pAlloc;
1705
1706     // Inlinee Compile object will only be allocated when needed for the 1st time.
1707     InlineeCompiler = nullptr;
1708
1709     // Set the inline info.
1710     impInlineInfo = inlineInfo;
1711
1712     eeInfoInitialized = false;
1713
1714     compDoAggressiveInlining = false;
1715
1716     if (compIsForInlining())
1717     {
1718         m_inlineStrategy = nullptr;
1719         compInlineResult = inlineInfo->inlineResult;
1720         compAsIAllocator = nullptr; // We shouldn't be using the compAsIAllocator for other than the root compiler.
1721 #if MEASURE_MEM_ALLOC
1722         compAsIAllocatorBitset    = nullptr;
1723         compAsIAllocatorGC        = nullptr;
1724         compAsIAllocatorLoopHoist = nullptr;
1725 #ifdef DEBUG
1726         compAsIAllocatorDebugOnly = nullptr;
1727 #endif // DEBUG
1728 #endif // MEASURE_MEM_ALLOC
1729
1730         compQMarks = nullptr;
1731     }
1732     else
1733     {
1734         m_inlineStrategy = new (this, CMK_Inlining) InlineStrategy(this);
1735         compInlineResult = nullptr;
1736         compAsIAllocator = new (this, CMK_Unknown) CompAllocator(this, CMK_AsIAllocator);
1737 #if MEASURE_MEM_ALLOC
1738         compAsIAllocatorBitset    = new (this, CMK_Unknown) CompAllocator(this, CMK_bitset);
1739         compAsIAllocatorGC        = new (this, CMK_Unknown) CompAllocator(this, CMK_GC);
1740         compAsIAllocatorLoopHoist = new (this, CMK_Unknown) CompAllocator(this, CMK_LoopHoist);
1741 #ifdef DEBUG
1742         compAsIAllocatorDebugOnly = new (this, CMK_Unknown) CompAllocator(this, CMK_DebugOnly);
1743 #endif // DEBUG
1744 #endif // MEASURE_MEM_ALLOC
1745
1746         compQMarks = new (this, CMK_Unknown) ExpandArrayStack<GenTreePtr>(getAllocator());
1747     }
1748
1749 #ifdef FEATURE_TRACELOGGING
1750     // Make sure JIT telemetry is initialized as soon as allocations can be made
1751     // but no later than a point where noway_asserts can be thrown.
1752     //    1. JIT telemetry could allocate some objects internally.
1753     //    2. NowayAsserts are tracked through telemetry.
1754     //    Note: JIT telemetry could gather data when compiler is not fully initialized.
1755     //          So you have to initialize the compiler variables you use for telemetry.
1756     assert((unsigned)PHASE_PRE_IMPORT == 0);
1757     previousCompletedPhase = PHASE_PRE_IMPORT;
1758     info.compILCodeSize    = 0;
1759     info.compMethodHnd     = nullptr;
1760     compJitTelemetry.Initialize(this);
1761 #endif
1762
1763 #ifdef DEBUG
1764     bRangeAllowStress = false;
1765 #endif
1766
1767     fgInit();
1768     lvaInit();
1769
1770     if (!compIsForInlining())
1771     {
1772         codeGen = getCodeGenerator(this);
1773 #ifdef LEGACY_BACKEND
1774         raInit();
1775 #endif // LEGACY_BACKEND
1776         optInit();
1777 #ifndef LEGACY_BACKEND
1778         hashBv::Init(this);
1779 #endif // !LEGACY_BACKEND
1780
1781         compVarScopeMap = nullptr;
1782
1783         // If this method were a real constructor for Compiler, these would
1784         // become method initializations.
1785         impPendingBlockMembers    = ExpandArray<BYTE>(getAllocator());
1786         impSpillCliquePredMembers = ExpandArray<BYTE>(getAllocator());
1787         impSpillCliqueSuccMembers = ExpandArray<BYTE>(getAllocator());
1788
1789         memset(&lvHeapPerSsaData, 0, sizeof(PerSsaArray));
1790         lvHeapPerSsaData.Init(getAllocator());
1791         lvHeapNumSsaNames = 0;
1792
1793         //
1794         // Initialize all the per-method statistics gathering data structures.
1795         //
1796
1797         optLoopsCloned = 0;
1798
1799 #if MEASURE_MEM_ALLOC
1800         genMemStats.Init();
1801 #endif // MEASURE_MEM_ALLOC
1802 #if LOOP_HOIST_STATS
1803         m_loopsConsidered             = 0;
1804         m_curLoopHasHoistedExpression = false;
1805         m_loopsWithHoistedExpressions = 0;
1806         m_totalHoistedExpressions     = 0;
1807 #endif // LOOP_HOIST_STATS
1808 #if MEASURE_NODE_SIZE
1809         genNodeSizeStatsPerFunc.Init();
1810 #endif // MEASURE_NODE_SIZE
1811     }
1812     else
1813     {
1814         codeGen = nullptr;
1815     }
1816
1817     compJmpOpUsed         = false;
1818     compLongUsed          = false;
1819     compTailCallUsed      = false;
1820     compLocallocUsed      = false;
1821     compQmarkRationalized = false;
1822     compQmarkUsed         = false;
1823     compFloatingPointUsed = false;
1824     compUnsafeCastUsed    = false;
1825 #if CPU_USES_BLOCK_MOVE
1826     compBlkOpUsed = false;
1827 #endif
1828 #if FEATURE_STACK_FP_X87
1829     compMayHaveTransitionBlocks = false;
1830 #endif
1831     compNeedsGSSecurityCookie = false;
1832     compGSReorderStackLayout  = false;
1833 #if STACK_PROBES
1834     compStackProbePrologDone = false;
1835 #endif
1836
1837     compGeneratingProlog = false;
1838     compGeneratingEpilog = false;
1839
1840 #ifndef LEGACY_BACKEND
1841     compLSRADone = false;
1842 #endif // !LEGACY_BACKEND
1843     compRationalIRForm = false;
1844
1845 #ifdef DEBUG
1846     compCodeGenDone        = false;
1847     compRegSetCheckLevel   = 0;
1848     opts.compMinOptsIsUsed = false;
1849 #endif
1850     opts.compMinOptsIsSet = false;
1851
1852     // Used by fgFindJumpTargets for inlining heuristics.
1853     opts.instrCount = 0;
1854
1855     // Used to track when we should consider running EarlyProp
1856     optMethodFlags = 0;
1857
1858     for (unsigned i = 0; i < MAX_LOOP_NUM; i++)
1859     {
1860         AllVarSetOps::AssignNoCopy(this, optLoopTable[i].lpAsgVars, AllVarSetOps::UninitVal());
1861     }
1862
1863 #ifdef DEBUG
1864     m_nodeTestData      = nullptr;
1865     m_loopHoistCSEClass = FIRST_LOOP_HOIST_CSE_CLASS;
1866 #endif
1867     m_switchDescMap      = nullptr;
1868     m_blockToEHPreds     = nullptr;
1869     m_fieldSeqStore      = nullptr;
1870     m_zeroOffsetFieldMap = nullptr;
1871     m_arrayInfoMap       = nullptr;
1872     m_heapSsaMap         = nullptr;
1873     m_refAnyClass        = nullptr;
1874
1875 #ifdef DEBUG
1876     if (!compIsForInlining())
1877     {
1878         compDoComponentUnitTestsOnce();
1879     }
1880 #endif // DEBUG
1881
1882     vnStore               = nullptr;
1883     m_opAsgnVarDefSsaNums = nullptr;
1884     m_indirAssignMap      = nullptr;
1885     fgSsaPassesCompleted  = 0;
1886     fgVNPassesCompleted   = 0;
1887
1888     // check that HelperCallProperties are initialized
1889
1890     assert(s_helperCallProperties.IsPure(CORINFO_HELP_GETSHARED_GCSTATIC_BASE));
1891     assert(!s_helperCallProperties.IsPure(CORINFO_HELP_GETFIELDOBJ)); // quick sanity check
1892
1893     // We start with the flow graph in tree-order
1894     fgOrder = FGOrderTree;
1895
1896 #ifdef FEATURE_SIMD
1897     // SIMD Types
1898     SIMDFloatHandle   = nullptr;
1899     SIMDDoubleHandle  = nullptr;
1900     SIMDIntHandle     = nullptr;
1901     SIMDUShortHandle  = nullptr;
1902     SIMDUByteHandle   = nullptr;
1903     SIMDShortHandle   = nullptr;
1904     SIMDByteHandle    = nullptr;
1905     SIMDLongHandle    = nullptr;
1906     SIMDUIntHandle    = nullptr;
1907     SIMDULongHandle   = nullptr;
1908     SIMDVector2Handle = nullptr;
1909     SIMDVector3Handle = nullptr;
1910     SIMDVector4Handle = nullptr;
1911     SIMDVectorHandle  = nullptr;
1912 #endif
1913
1914     compUsesThrowHelper = false;
1915 }
1916
1917 /*****************************************************************************
1918  *
1919  *  Destructor
1920  */
1921
1922 void Compiler::compDone()
1923 {
1924 }
1925
1926 void* Compiler::compGetHelperFtn(CorInfoHelpFunc ftnNum,        /* IN  */
1927                                  void**          ppIndirection) /* OUT */
1928 {
1929     void* addr;
1930
1931     if (info.compMatchedVM)
1932     {
1933         addr = info.compCompHnd->getHelperFtn(ftnNum, ppIndirection);
1934     }
1935     else
1936     {
1937         // If we don't have a matched VM, we won't get valid results when asking for a helper function.
1938         addr = (void*)0xCA11CA11; // "callcall"
1939     }
1940
1941     return addr;
1942 }
1943
1944 unsigned Compiler::compGetTypeSize(CorInfoType cit, CORINFO_CLASS_HANDLE clsHnd)
1945 {
1946     var_types sigType = genActualType(JITtype2varType(cit));
1947     unsigned  sigSize;
1948     sigSize = genTypeSize(sigType);
1949     if (cit == CORINFO_TYPE_VALUECLASS)
1950     {
1951         sigSize = info.compCompHnd->getClassSize(clsHnd);
1952     }
1953     else if (cit == CORINFO_TYPE_REFANY)
1954     {
1955         sigSize = 2 * sizeof(void*);
1956     }
1957     return sigSize;
1958 }
1959
1960 #ifdef DEBUG
1961 static bool DidComponentUnitTests = false;
1962
1963 void Compiler::compDoComponentUnitTestsOnce()
1964 {
1965     if (!JitConfig.RunComponentUnitTests())
1966     {
1967         return;
1968     }
1969
1970     if (!DidComponentUnitTests)
1971     {
1972         DidComponentUnitTests = true;
1973         ValueNumStore::RunTests(this);
1974         BitSetSupport::TestSuite(getAllocatorDebugOnly());
1975     }
1976 }
1977 #endif // DEBUG
1978
1979 /******************************************************************************
1980  *
1981  *  The Emitter uses this callback function to allocate its memory
1982  */
1983
1984 /* static */
1985 void* Compiler::compGetMemCallback(void* p, size_t size, CompMemKind cmk)
1986 {
1987     assert(p);
1988
1989     return ((Compiler*)p)->compGetMem(size, cmk);
1990 }
1991
1992 /*****************************************************************************
1993  *
1994  *  The central memory allocation routine used by the compiler. Normally this
1995  *  is a simple inline method defined in compiler.hpp, but for debugging it's
1996  *  often convenient to keep it non-inline.
1997  */
1998
1999 #ifdef DEBUG
2000
2001 void* Compiler::compGetMem(size_t sz, CompMemKind cmk)
2002 {
2003 #if 0
2004 #if SMALL_TREE_NODES
2005     if  (sz != TREE_NODE_SZ_SMALL &&
2006          sz != TREE_NODE_SZ_LARGE && sz > 32)
2007     {
2008         printf("Alloc %3u bytes\n", sz);
2009     }
2010 #else
2011     if  (sz != sizeof(GenTree)    && sz > 32)
2012     {
2013         printf("Alloc %3u bytes\n", sz);
2014     }
2015 #endif
2016 #endif // 0
2017
2018 #if MEASURE_MEM_ALLOC
2019     genMemStats.AddAlloc(sz, cmk);
2020 #endif
2021
2022     void* ptr = compAllocator->allocateMemory(sz);
2023
2024     // Verify that the current block is aligned. Only then will the next
2025     // block allocated be on an aligned boundary.
2026     assert((size_t(ptr) & (sizeof(size_t) - 1)) == 0);
2027
2028     return ptr;
2029 }
2030
2031 #endif
2032
2033 /*****************************************************************************/
2034 #ifdef DEBUG
2035 /*****************************************************************************/
2036
2037 VarName Compiler::compVarName(regNumber reg, bool isFloatReg)
2038 {
2039     if (isFloatReg)
2040     {
2041 #if FEATURE_STACK_FP_X87
2042         assert(reg < FP_STK_SIZE); // would like to have same assert as below but sometimes you get -1?
2043 #else
2044         assert(genIsValidFloatReg(reg));
2045 #endif
2046     }
2047     else
2048     {
2049         assert(genIsValidReg(reg));
2050     }
2051
2052     if ((info.compVarScopesCount > 0) && compCurBB && opts.varNames)
2053     {
2054         unsigned   lclNum;
2055         LclVarDsc* varDsc;
2056
2057         /* Look for the matching register */
2058         for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
2059         {
2060             /* If the variable is not in a register, or not in the register we're looking for, quit. */
2061             /* Also, if it is a compiler generated variable (i.e. slot# > info.compVarScopesCount), don't bother. */
2062             if ((varDsc->lvRegister != 0) && (varDsc->lvRegNum == reg) && (varDsc->IsFloatRegType() || !isFloatReg) &&
2063                 (varDsc->lvSlotNum < info.compVarScopesCount))
2064             {
2065                 /* check if variable in that register is live */
2066                 if (VarSetOps::IsMember(this, compCurLife, varDsc->lvVarIndex))
2067                 {
2068                     /* variable is live - find the corresponding slot */
2069                     VarScopeDsc* varScope =
2070                         compFindLocalVar(varDsc->lvSlotNum, compCurBB->bbCodeOffs, compCurBB->bbCodeOffsEnd);
2071                     if (varScope)
2072                     {
2073                         return varScope->vsdName;
2074                     }
2075                 }
2076             }
2077         }
2078
2079 #ifdef LEGACY_BACKEND
2080         // maybe var is marked dead, but still used (last use)
2081         if (!isFloatReg && codeGen->regSet.rsUsedTree[reg] != NULL)
2082         {
2083             GenTreePtr nodePtr;
2084
2085             if (GenTree::OperIsUnary(codeGen->regSet.rsUsedTree[reg]->OperGet()))
2086             {
2087                 assert(codeGen->regSet.rsUsedTree[reg]->gtOp.gtOp1 != NULL);
2088                 nodePtr = codeGen->regSet.rsUsedTree[reg]->gtOp.gtOp1;
2089             }
2090             else
2091             {
2092                 nodePtr = codeGen->regSet.rsUsedTree[reg];
2093             }
2094
2095             if ((nodePtr->gtOper == GT_REG_VAR) && (nodePtr->gtRegVar.gtRegNum == reg) &&
2096                 (nodePtr->gtRegVar.gtLclNum < info.compVarScopesCount))
2097             {
2098                 VarScopeDsc* varScope =
2099                     compFindLocalVar(nodePtr->gtRegVar.gtLclNum, compCurBB->bbCodeOffs, compCurBB->bbCodeOffsEnd);
2100                 if (varScope)
2101                     return varScope->vsdName;
2102             }
2103         }
2104 #endif // LEGACY_BACKEND
2105     }
2106     return nullptr;
2107 }
2108
2109 const char* Compiler::compRegVarName(regNumber reg, bool displayVar, bool isFloatReg)
2110 {
2111
2112 #ifdef _TARGET_ARM_
2113     isFloatReg = genIsValidFloatReg(reg);
2114 #endif
2115
2116     if (displayVar && (reg != REG_NA))
2117     {
2118         VarName varName = compVarName(reg, isFloatReg);
2119
2120         if (varName)
2121         {
2122             const int   NAME_VAR_REG_BUFFER_LEN = 4 + 256 + 1;
2123             static char nameVarReg[2][NAME_VAR_REG_BUFFER_LEN]; // to avoid overwriting the buffer when have 2
2124                                                                 // consecutive calls before printing
2125             static int index = 0;                               // for circular index into the name array
2126
2127             index = (index + 1) % 2; // circular reuse of index
2128             sprintf_s(nameVarReg[index], NAME_VAR_REG_BUFFER_LEN, "%s'%s'", getRegName(reg, isFloatReg),
2129                       VarNameToStr(varName));
2130
2131             return nameVarReg[index];
2132         }
2133     }
2134
2135     /* no debug info required or no variable in that register
2136        -> return standard name */
2137
2138     return getRegName(reg, isFloatReg);
2139 }
2140
2141 #define MAX_REG_PAIR_NAME_LENGTH 10
2142
2143 const char* Compiler::compRegPairName(regPairNo regPair)
2144 {
2145     static char regNameLong[MAX_REG_PAIR_NAME_LENGTH];
2146
2147     if (regPair == REG_PAIR_NONE)
2148     {
2149         return "NA|NA";
2150     }
2151
2152     assert(regPair >= REG_PAIR_FIRST && regPair <= REG_PAIR_LAST);
2153
2154     strcpy_s(regNameLong, sizeof(regNameLong), compRegVarName(genRegPairLo(regPair)));
2155     strcat_s(regNameLong, sizeof(regNameLong), "|");
2156     strcat_s(regNameLong, sizeof(regNameLong), compRegVarName(genRegPairHi(regPair)));
2157     return regNameLong;
2158 }
2159
2160 const char* Compiler::compRegNameForSize(regNumber reg, size_t size)
2161 {
2162     if (size == 0 || size >= 4)
2163     {
2164         return compRegVarName(reg, true);
2165     }
2166
2167     // clang-format off
2168     static
2169     const char  *   sizeNames[][2] =
2170     {
2171         { "al", "ax" },
2172         { "cl", "cx" },
2173         { "dl", "dx" },
2174         { "bl", "bx" },
2175 #ifdef _TARGET_AMD64_
2176         {  "spl",   "sp" }, // ESP
2177         {  "bpl",   "bp" }, // EBP
2178         {  "sil",   "si" }, // ESI
2179         {  "dil",   "di" }, // EDI
2180         {  "r8b",  "r8w" },
2181         {  "r9b",  "r9w" },
2182         { "r10b", "r10w" },
2183         { "r11b", "r11w" },
2184         { "r12b", "r12w" },
2185         { "r13b", "r13w" },
2186         { "r14b", "r14w" },
2187         { "r15b", "r15w" },
2188 #endif // _TARGET_AMD64_
2189     };
2190     // clang-format on
2191
2192     assert(isByteReg(reg));
2193     assert(genRegMask(reg) & RBM_BYTE_REGS);
2194     assert(size == 1 || size == 2);
2195
2196     return sizeNames[reg][size - 1];
2197 }
2198
2199 const char* Compiler::compFPregVarName(unsigned fpReg, bool displayVar)
2200 {
2201     const int   NAME_VAR_REG_BUFFER_LEN = 4 + 256 + 1;
2202     static char nameVarReg[2][NAME_VAR_REG_BUFFER_LEN]; // to avoid overwriting the buffer when have 2 consecutive calls
2203                                                         // before printing
2204     static int index = 0;                               // for circular index into the name array
2205
2206     index = (index + 1) % 2; // circular reuse of index
2207
2208 #if FEATURE_STACK_FP_X87
2209     /* 'fpReg' is the distance from the bottom of the stack, ie.
2210      * it is independant of the current FP stack level
2211      */
2212
2213     if (displayVar && codeGen->genFPregCnt)
2214     {
2215         assert(fpReg < FP_STK_SIZE);
2216         assert(compCodeGenDone || (fpReg <= codeGen->compCurFPState.m_uStackSize));
2217
2218         int pos = codeGen->genFPregCnt - (fpReg + 1 - codeGen->genGetFPstkLevel());
2219         if (pos >= 0)
2220         {
2221             VarName varName = compVarName((regNumber)pos, true);
2222
2223             if (varName)
2224             {
2225                 sprintf_s(nameVarReg[index], NAME_VAR_REG_BUFFER_LEN, "ST(%d)'%s'", fpReg, VarNameToStr(varName));
2226                 return nameVarReg[index];
2227             }
2228         }
2229     }
2230 #endif // FEATURE_STACK_FP_X87
2231
2232     /* no debug info required or no variable in that register
2233        -> return standard name */
2234
2235     sprintf_s(nameVarReg[index], NAME_VAR_REG_BUFFER_LEN, "ST(%d)", fpReg);
2236     return nameVarReg[index];
2237 }
2238
2239 const char* Compiler::compLocalVarName(unsigned varNum, unsigned offs)
2240 {
2241     unsigned     i;
2242     VarScopeDsc* t;
2243
2244     for (i = 0, t = info.compVarScopes; i < info.compVarScopesCount; i++, t++)
2245     {
2246         if (t->vsdVarNum != varNum)
2247         {
2248             continue;
2249         }
2250
2251         if (offs >= t->vsdLifeBeg && offs < t->vsdLifeEnd)
2252         {
2253             return VarNameToStr(t->vsdName);
2254         }
2255     }
2256
2257     return nullptr;
2258 }
2259
2260 /*****************************************************************************/
2261 #endif // DEBUG
2262 /*****************************************************************************/
2263
2264 void Compiler::compSetProcessor()
2265 {
2266     const JitFlags& jitFlags = *opts.jitFlags;
2267
2268 #if defined(_TARGET_ARM_)
2269     info.genCPU = CPU_ARM;
2270 #elif defined(_TARGET_AMD64_)
2271     info.genCPU       = CPU_X64;
2272 #elif defined(_TARGET_X86_)
2273     if (jitFlags.IsSet(JitFlags::JIT_FLAG_TARGET_P4))
2274         info.genCPU = CPU_X86_PENTIUM_4;
2275     else
2276         info.genCPU = CPU_X86;
2277 #endif
2278
2279     //
2280     // Processor specific optimizations
2281     //
2282     CLANG_FORMAT_COMMENT_ANCHOR;
2283
2284 #ifdef _TARGET_XARCH_
2285     opts.compCanUseSSE3_4 = false;
2286     if (!jitFlags.IsSet(JitFlags::JIT_FLAG_PREJIT) && jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE3_4))
2287     {
2288         if (JitConfig.EnableSSE3_4() != 0)
2289         {
2290             opts.compCanUseSSE3_4 = true;
2291         }
2292     }
2293
2294 #ifdef FEATURE_AVX_SUPPORT
2295     // COMPlus_EnableAVX can be used to disable using AVX if available on a target machine.
2296     // Note that FEATURE_AVX_SUPPORT is not enabled for ctpjit
2297     opts.compCanUseAVX = false;
2298     if (!jitFlags.IsSet(JitFlags::JIT_FLAG_PREJIT) && jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AVX2))
2299     {
2300         if (JitConfig.EnableAVX() != 0)
2301         {
2302             opts.compCanUseAVX = true;
2303         }
2304     }
2305 #endif // FEATURE_AVX_SUPPORT
2306
2307     if (!compIsForInlining())
2308     {
2309 #ifdef FEATURE_AVX_SUPPORT
2310         if (opts.compCanUseAVX)
2311         {
2312             codeGen->getEmitter()->SetUseAVX(true);
2313             // Assume each JITted method does not contain AVX instruction at first
2314             codeGen->getEmitter()->SetContainsAVX(false);
2315             codeGen->getEmitter()->SetContains256bitAVX(false);
2316         }
2317         else
2318 #endif // FEATURE_AVX_SUPPORT
2319             if (opts.compCanUseSSE3_4)
2320         {
2321             codeGen->getEmitter()->SetUseSSE3_4(true);
2322         }
2323     }
2324 #endif // _TARGET_XARCH_
2325
2326 #ifdef _TARGET_AMD64_
2327     opts.compUseFCOMI   = false;
2328     opts.compUseCMOV    = true;
2329     opts.compCanUseSSE2 = true;
2330 #elif defined(_TARGET_X86_)
2331     opts.compUseFCOMI = jitFlags.IsSet(JitFlags::JIT_FLAG_USE_FCOMI);
2332     opts.compUseCMOV  = jitFlags.IsSet(JitFlags::JIT_FLAG_USE_CMOV);
2333     opts.compCanUseSSE2 = jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE2);
2334
2335 #if !defined(LEGACY_BACKEND) && !defined(FEATURE_CORECLR)
2336     // RyuJIT/x86 requires SSE2 to be available: there is no support for generating floating-point
2337     // code with x87 instructions. On .NET Core, the VM always tells us that SSE2 is available.
2338     // However, on desktop, under ngen, (and presumably in the unlikely case you're actually
2339     // running on a machine without SSE2), the VM does not set the SSE2 flag. We ignore this and
2340     // go ahead and generate SSE2 code anyway.
2341     if (!opts.compCanUseSSE2)
2342     {
2343         JITDUMP("VM didn't set CORJIT_FLG_USE_SSE2! Ignoring, and generating SSE2 code anyway.\n");
2344         opts.compCanUseSSE2 = true;
2345     }
2346 #endif // !defined(LEGACY_BACKEND) && !defined(FEATURE_CORECLR)
2347
2348 #ifdef DEBUG
2349     if (opts.compUseFCOMI)
2350         opts.compUseFCOMI = !compStressCompile(STRESS_USE_FCOMI, 50);
2351     if (opts.compUseCMOV)
2352         opts.compUseCMOV = !compStressCompile(STRESS_USE_CMOV, 50);
2353
2354 #ifdef LEGACY_BACKEND
2355
2356     // Should we override the SSE2 setting?
2357     enum
2358     {
2359         SSE2_FORCE_DISABLE = 0,
2360         SSE2_FORCE_USE     = 1,
2361         SSE2_FORCE_INVALID = -1
2362     };
2363
2364     if (JitConfig.JitCanUseSSE2() == SSE2_FORCE_DISABLE)
2365         opts.compCanUseSSE2 = false;
2366     else if (JitConfig.JitCanUseSSE2() == SSE2_FORCE_USE)
2367         opts.compCanUseSSE2 = true;
2368     else if (opts.compCanUseSSE2)
2369         opts.compCanUseSSE2 = !compStressCompile(STRESS_GENERIC_VARN, 50);
2370
2371 #else // !LEGACY_BACKEND
2372
2373     // RyuJIT/x86 requires SSE2 to be available and hence
2374     // don't turn off compCanUseSSE2 under stress.
2375     assert(opts.compCanUseSSE2);
2376
2377 #endif // !LEGACY_BACKEND
2378
2379 #endif // DEBUG
2380
2381 #endif // _TARGET_X86_
2382 }
2383
2384 #ifdef PROFILING_SUPPORTED
2385 // A Dummy routine to receive Enter/Leave/Tailcall profiler callbacks.
2386 // These are used when complus_JitEltHookEnabled=1
2387 #ifdef _TARGET_AMD64_
2388 void DummyProfilerELTStub(UINT_PTR ProfilerHandle, UINT_PTR callerSP)
2389 {
2390     return;
2391 }
2392 #else  //! _TARGET_AMD64_
2393 void DummyProfilerELTStub(UINT_PTR ProfilerHandle)
2394 {
2395     return;
2396 }
2397 #endif //!_TARGET_AMD64_
2398
2399 #endif // PROFILING_SUPPORTED
2400
2401 bool Compiler::compIsFullTrust()
2402 {
2403     return (info.compCompHnd->canSkipMethodVerification(info.compMethodHnd) == CORINFO_VERIFICATION_CAN_SKIP);
2404 }
2405
2406 bool Compiler::compShouldThrowOnNoway(
2407 #ifdef FEATURE_TRACELOGGING
2408     const char* filename, unsigned line
2409 #endif
2410     )
2411 {
2412 #ifdef FEATURE_TRACELOGGING
2413     compJitTelemetry.NotifyNowayAssert(filename, line);
2414 #endif
2415     // In min opts, we don't want the noway assert to go through the exception
2416     // path. Instead we want it to just silently go through codegen for
2417     // compat reasons.
2418     // If we are not in full trust, we should always fire for security.
2419     return !opts.MinOpts() || !compIsFullTrust();
2420 }
2421
2422 // ConfigInteger does not offer an option for decimal flags.  Any numbers are interpreted as hex.
2423 // I could add the decimal option to ConfigInteger or I could write a function to reinterpret this
2424 // value as the user intended.
2425 unsigned ReinterpretHexAsDecimal(unsigned in)
2426 {
2427     // ex: in: 0x100 returns: 100
2428     unsigned result = 0;
2429     unsigned index  = 1;
2430
2431     // default value
2432     if (in == INT_MAX)
2433     {
2434         return in;
2435     }
2436
2437     while (in)
2438     {
2439         unsigned digit = in % 16;
2440         in >>= 4;
2441         assert(digit < 10);
2442         result += digit * index;
2443         index *= 10;
2444     }
2445     return result;
2446 }
2447
2448 void Compiler::compInitOptions(JitFlags* jitFlags)
2449 {
2450 #ifdef UNIX_AMD64_ABI
2451     opts.compNeedToAlignFrame = false;
2452 #endif // UNIX_AMD64_ABI
2453     memset(&opts, 0, sizeof(opts));
2454
2455     if (compIsForInlining())
2456     {
2457         // The following flags are lost when inlining. (They are removed in
2458         // Compiler::fgInvokeInlineeCompiler().)
2459         assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT));
2460         assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_BBINSTR));
2461         assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_PROF_ENTERLEAVE));
2462         assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_EnC));
2463         assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_INFO));
2464
2465         assert(jitFlags->IsSet(JitFlags::JIT_FLAG_SKIP_VERIFICATION));
2466     }
2467
2468     opts.jitFlags  = jitFlags;
2469     opts.compFlags = CLFLG_MAXOPT; // Default value is for full optimization
2470
2471     if (jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_CODE) || jitFlags->IsSet(JitFlags::JIT_FLAG_MIN_OPT))
2472     {
2473         opts.compFlags = CLFLG_MINOPT;
2474     }
2475     // Don't optimize .cctors (except prejit) or if we're an inlinee
2476     else if (!jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT) && ((info.compFlags & FLG_CCTOR) == FLG_CCTOR) &&
2477              !compIsForInlining())
2478     {
2479         opts.compFlags = CLFLG_MINOPT;
2480     }
2481
2482     // Default value is to generate a blend of size and speed optimizations
2483     //
2484     opts.compCodeOpt = BLENDED_CODE;
2485
2486     // If the EE sets SIZE_OPT or if we are compiling a Class constructor
2487     // we will optimize for code size at the expense of speed
2488     //
2489     if (jitFlags->IsSet(JitFlags::JIT_FLAG_SIZE_OPT) || ((info.compFlags & FLG_CCTOR) == FLG_CCTOR))
2490     {
2491         opts.compCodeOpt = SMALL_CODE;
2492     }
2493     //
2494     // If the EE sets SPEED_OPT we will optimize for speed at the expense of code size
2495     //
2496     else if (jitFlags->IsSet(JitFlags::JIT_FLAG_SPEED_OPT))
2497     {
2498         opts.compCodeOpt = FAST_CODE;
2499         assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_SIZE_OPT));
2500     }
2501
2502     //-------------------------------------------------------------------------
2503
2504     opts.compDbgCode = jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_CODE);
2505     opts.compDbgInfo = jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_INFO);
2506     opts.compDbgEnC  = jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_EnC);
2507
2508 #if REGEN_SHORTCUTS || REGEN_CALLPAT
2509     // We never want to have debugging enabled when regenerating GC encoding patterns
2510     opts.compDbgCode = false;
2511     opts.compDbgInfo = false;
2512     opts.compDbgEnC  = false;
2513 #endif
2514
2515     compSetProcessor();
2516
2517 #ifdef DEBUG
2518     opts.dspOrder = false;
2519     if (compIsForInlining())
2520     {
2521         verbose = impInlineInfo->InlinerCompiler->verbose;
2522     }
2523     else
2524     {
2525         verbose = false;
2526         codeGen->setVerbose(false);
2527     }
2528     verboseTrees     = verbose && shouldUseVerboseTrees();
2529     verboseSsa       = verbose && shouldUseVerboseSsa();
2530     asciiTrees       = shouldDumpASCIITrees();
2531     opts.dspDiffable = compIsForInlining() ? impInlineInfo->InlinerCompiler->opts.dspDiffable : false;
2532 #endif
2533
2534     opts.compNeedSecurityCheck = false;
2535     opts.altJit                = false;
2536
2537 #if defined(LATE_DISASM) && !defined(DEBUG)
2538     // For non-debug builds with the late disassembler built in, we currently always do late disassembly
2539     // (we have no way to determine when not to, since we don't have class/method names).
2540     // In the DEBUG case, this is initialized to false, below.
2541     opts.doLateDisasm = true;
2542 #endif
2543
2544 #ifdef DEBUG
2545
2546     const JitConfigValues::MethodSet* pfAltJit;
2547     if (jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
2548     {
2549         pfAltJit = &JitConfig.AltJitNgen();
2550     }
2551     else
2552     {
2553         pfAltJit = &JitConfig.AltJit();
2554     }
2555
2556 #ifdef ALT_JIT
2557     if (pfAltJit->contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
2558     {
2559         opts.altJit = true;
2560     }
2561
2562     unsigned altJitLimit = ReinterpretHexAsDecimal(JitConfig.AltJitLimit());
2563     if (altJitLimit > 0 && Compiler::jitTotalMethodCompiled >= altJitLimit)
2564     {
2565         opts.altJit = false;
2566     }
2567 #endif // ALT_JIT
2568
2569 #else // !DEBUG
2570
2571     const char* altJitVal;
2572     if (jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
2573     {
2574         altJitVal = JitConfig.AltJitNgen().list();
2575     }
2576     else
2577     {
2578         altJitVal = JitConfig.AltJit().list();
2579     }
2580
2581 #ifdef ALT_JIT
2582     // In release mode, you either get all methods or no methods. You must use "*" as the parameter, or we ignore it.
2583     // You don't get to give a regular expression of methods to match.
2584     // (Partially, this is because we haven't computed and stored the method and class name except in debug, and it
2585     // might be expensive to do so.)
2586     if ((altJitVal != nullptr) && (strcmp(altJitVal, "*") == 0))
2587     {
2588         opts.altJit = true;
2589     }
2590 #endif // ALT_JIT
2591
2592 #endif // !DEBUG
2593
2594 #ifdef ALT_JIT
2595     // Take care of COMPlus_AltJitExcludeAssemblies.
2596     if (opts.altJit)
2597     {
2598         // First, initialize the AltJitExcludeAssemblies list, but only do it once.
2599         if (!s_pAltJitExcludeAssembliesListInitialized)
2600         {
2601             const wchar_t* wszAltJitExcludeAssemblyList = JitConfig.AltJitExcludeAssemblies();
2602             if (wszAltJitExcludeAssemblyList != nullptr)
2603             {
2604                 // NOTE: The Assembly name list is allocated in the process heap, not in the no-release heap, which is
2605                 // reclaimed
2606                 // for every compilation. This is ok because we only allocate once, due to the static.
2607                 s_pAltJitExcludeAssembliesList = new (HostAllocator::getHostAllocator())
2608                     AssemblyNamesList2(wszAltJitExcludeAssemblyList, HostAllocator::getHostAllocator());
2609             }
2610             s_pAltJitExcludeAssembliesListInitialized = true;
2611         }
2612
2613         if (s_pAltJitExcludeAssembliesList != nullptr)
2614         {
2615             // We have an exclusion list. See if this method is in an assembly that is on the list.
2616             // Note that we check this for every method, since we might inline across modules, and
2617             // if the inlinee module is on the list, we don't want to use the altjit for it.
2618             const char* methodAssemblyName = info.compCompHnd->getAssemblyName(
2619                 info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));
2620             if (s_pAltJitExcludeAssembliesList->IsInList(methodAssemblyName))
2621             {
2622                 opts.altJit = false;
2623             }
2624         }
2625     }
2626 #endif // ALT_JIT
2627
2628 #ifdef DEBUG
2629
2630     bool altJitConfig = !pfAltJit->isEmpty();
2631
2632     //  If we have a non-empty AltJit config then we change all of these other
2633     //  config values to refer only to the AltJit. Otherwise, a lot of COMPlus_* variables
2634     //  would apply to both the altjit and the normal JIT, but we only care about
2635     //  debugging the altjit if the COMPlus_AltJit configuration is set.
2636     //
2637     if (compIsForImportOnly() && (!altJitConfig || opts.altJit))
2638     {
2639         if (JitConfig.JitImportBreak().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
2640         {
2641             assert(!"JitImportBreak reached");
2642         }
2643     }
2644
2645     bool    verboseDump        = false;
2646     bool    dumpIR             = false;
2647     bool    dumpIRTypes        = false;
2648     bool    dumpIRLocals       = false;
2649     bool    dumpIRRegs         = false;
2650     bool    dumpIRSsa          = false;
2651     bool    dumpIRValnums      = false;
2652     bool    dumpIRCosts        = false;
2653     bool    dumpIRFlags        = false;
2654     bool    dumpIRKinds        = false;
2655     bool    dumpIRNodes        = false;
2656     bool    dumpIRNoLists      = false;
2657     bool    dumpIRNoLeafs      = false;
2658     bool    dumpIRNoStmts      = false;
2659     bool    dumpIRTrees        = false;
2660     bool    dumpIRLinear       = false;
2661     bool    dumpIRDataflow     = false;
2662     bool    dumpIRBlockHeaders = false;
2663     bool    dumpIRExit         = false;
2664     LPCWSTR dumpIRPhase        = nullptr;
2665     LPCWSTR dumpIRFormat       = nullptr;
2666
2667     if (!altJitConfig || opts.altJit)
2668     {
2669         LPCWSTR dumpIRFormat = nullptr;
2670
2671         // We should only enable 'verboseDump' when we are actually compiling a matching method
2672         // and not enable it when we are just considering inlining a matching method.
2673         //
2674         if (!compIsForInlining())
2675         {
2676             if (jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
2677             {
2678                 if (JitConfig.NgenDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
2679                 {
2680                     verboseDump = true;
2681                 }
2682                 unsigned ngenHashDumpVal = (unsigned)JitConfig.NgenHashDump();
2683                 if ((ngenHashDumpVal != (DWORD)-1) && (ngenHashDumpVal == info.compMethodHash()))
2684                 {
2685                     verboseDump = true;
2686                 }
2687                 if (JitConfig.NgenDumpIR().contains(info.compMethodName, info.compClassName,
2688                                                     &info.compMethodInfo->args))
2689                 {
2690                     dumpIR = true;
2691                 }
2692                 unsigned ngenHashDumpIRVal = (unsigned)JitConfig.NgenHashDumpIR();
2693                 if ((ngenHashDumpIRVal != (DWORD)-1) && (ngenHashDumpIRVal == info.compMethodHash()))
2694                 {
2695                     dumpIR = true;
2696                 }
2697                 dumpIRFormat = JitConfig.NgenDumpIRFormat();
2698                 dumpIRPhase  = JitConfig.NgenDumpIRPhase();
2699             }
2700             else
2701             {
2702                 if (JitConfig.JitDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
2703                 {
2704                     verboseDump = true;
2705                 }
2706                 unsigned jitHashDumpVal = (unsigned)JitConfig.JitHashDump();
2707                 if ((jitHashDumpVal != (DWORD)-1) && (jitHashDumpVal == info.compMethodHash()))
2708                 {
2709                     verboseDump = true;
2710                 }
2711                 if (JitConfig.JitDumpIR().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
2712                 {
2713                     dumpIR = true;
2714                 }
2715                 unsigned jitHashDumpIRVal = (unsigned)JitConfig.JitHashDumpIR();
2716                 if ((jitHashDumpIRVal != (DWORD)-1) && (jitHashDumpIRVal == info.compMethodHash()))
2717                 {
2718                     dumpIR = true;
2719                 }
2720                 dumpIRFormat = JitConfig.JitDumpIRFormat();
2721                 dumpIRPhase  = JitConfig.JitDumpIRPhase();
2722             }
2723         }
2724
2725         if (dumpIRPhase == nullptr)
2726         {
2727             dumpIRPhase = W("*");
2728         }
2729
2730         this->dumpIRPhase = dumpIRPhase;
2731
2732         if (dumpIRFormat != nullptr)
2733         {
2734             this->dumpIRFormat = dumpIRFormat;
2735         }
2736
2737         dumpIRTrees  = false;
2738         dumpIRLinear = true;
2739         if (dumpIRFormat != nullptr)
2740         {
2741             for (LPCWSTR p = dumpIRFormat; (*p != 0);)
2742             {
2743                 for (; (*p != 0); p++)
2744                 {
2745                     if (*p != L' ')
2746                     {
2747                         break;
2748                     }
2749                 }
2750
2751                 if (*p == 0)
2752                 {
2753                     break;
2754                 }
2755
2756                 static bool dumpedHelp = false;
2757
2758                 if ((*p == L'?') && (!dumpedHelp))
2759                 {
2760                     printf("*******************************************************************************\n");
2761                     printf("\n");
2762                     dFormatIR();
2763                     printf("\n");
2764                     printf("\n");
2765                     printf("Available specifiers (comma separated):\n");
2766                     printf("\n");
2767                     printf("?          dump out value of COMPlus_JitDumpIRFormat and this list of values\n");
2768                     printf("\n");
2769                     printf("linear     linear IR dump (default)\n");
2770                     printf("tree       tree IR dump (traditional)\n");
2771                     printf("mixed      intermingle tree dump with linear IR dump\n");
2772                     printf("\n");
2773                     printf("dataflow   use data flow form of linear IR dump\n");
2774                     printf("structural use structural form of linear IR dump\n");
2775                     printf("all        implies structural, include everything\n");
2776                     printf("\n");
2777                     printf("kinds      include tree node kinds in dump, example: \"kinds=[LEAF][LOCAL]\"\n");
2778                     printf("flags      include tree node flags in dump, example: \"flags=[CALL][GLOB_REF]\" \n");
2779                     printf("types      includes tree node types in dump, example: \".int\"\n");
2780                     printf("locals     include local numbers and tracking numbers in dump, example: \"(V3,T1)\"\n");
2781                     printf("regs       include register assignments in dump, example: \"(rdx)\"\n");
2782                     printf("ssa        include SSA numbers in dump, example: \"<d:3>\" or \"<u:3>\"\n");
2783                     printf("valnums    include Value numbers in dump, example: \"<v:$c4>\" or \"<v:$c4,$c5>\"\n");
2784                     printf("\n");
2785                     printf("nolist     exclude GT_LIST nodes from dump\n");
2786                     printf("noleafs    exclude LEAF nodes from dump (fold into operations)\n");
2787                     printf("nostmts    exclude GT_STMTS from dump (unless required by dependencies)\n");
2788                     printf("\n");
2789                     printf("blkhdrs    include block headers\n");
2790                     printf("exit       exit program after last phase dump (used with single method)\n");
2791                     printf("\n");
2792                     printf("*******************************************************************************\n");
2793                     dumpedHelp = true;
2794                 }
2795
2796                 if (wcsncmp(p, W("types"), 5) == 0)
2797                 {
2798                     dumpIRTypes = true;
2799                 }
2800
2801                 if (wcsncmp(p, W("locals"), 6) == 0)
2802                 {
2803                     dumpIRLocals = true;
2804                 }
2805
2806                 if (wcsncmp(p, W("regs"), 4) == 0)
2807                 {
2808                     dumpIRRegs = true;
2809                 }
2810
2811                 if (wcsncmp(p, W("ssa"), 3) == 0)
2812                 {
2813                     dumpIRSsa = true;
2814                 }
2815
2816                 if (wcsncmp(p, W("valnums"), 7) == 0)
2817                 {
2818                     dumpIRValnums = true;
2819                 }
2820
2821                 if (wcsncmp(p, W("costs"), 5) == 0)
2822                 {
2823                     dumpIRCosts = true;
2824                 }
2825
2826                 if (wcsncmp(p, W("flags"), 5) == 0)
2827                 {
2828                     dumpIRFlags = true;
2829                 }
2830
2831                 if (wcsncmp(p, W("kinds"), 5) == 0)
2832                 {
2833                     dumpIRKinds = true;
2834                 }
2835
2836                 if (wcsncmp(p, W("nodes"), 5) == 0)
2837                 {
2838                     dumpIRNodes = true;
2839                 }
2840
2841                 if (wcsncmp(p, W("exit"), 4) == 0)
2842                 {
2843                     dumpIRExit = true;
2844                 }
2845
2846                 if (wcsncmp(p, W("nolists"), 7) == 0)
2847                 {
2848                     dumpIRNoLists = true;
2849                 }
2850
2851                 if (wcsncmp(p, W("noleafs"), 7) == 0)
2852                 {
2853                     dumpIRNoLeafs = true;
2854                 }
2855
2856                 if (wcsncmp(p, W("nostmts"), 7) == 0)
2857                 {
2858                     dumpIRNoStmts = true;
2859                 }
2860
2861                 if (wcsncmp(p, W("trees"), 5) == 0)
2862                 {
2863                     dumpIRTrees  = true;
2864                     dumpIRLinear = false;
2865                 }
2866
2867                 if (wcsncmp(p, W("structural"), 10) == 0)
2868                 {
2869                     dumpIRLinear  = true;
2870                     dumpIRNoStmts = false;
2871                     dumpIRNoLeafs = false;
2872                     dumpIRNoLists = false;
2873                 }
2874
2875                 if (wcsncmp(p, W("all"), 3) == 0)
2876                 {
2877                     dumpIRLinear  = true;
2878                     dumpIRKinds   = true;
2879                     dumpIRFlags   = true;
2880                     dumpIRTypes   = true;
2881                     dumpIRLocals  = true;
2882                     dumpIRRegs    = true;
2883                     dumpIRSsa     = true;
2884                     dumpIRValnums = true;
2885                     dumpIRCosts   = true;
2886                     dumpIRNoStmts = false;
2887                     dumpIRNoLeafs = false;
2888                     dumpIRNoLists = false;
2889                 }
2890
2891                 if (wcsncmp(p, W("linear"), 6) == 0)
2892                 {
2893                     dumpIRTrees  = false;
2894                     dumpIRLinear = true;
2895                 }
2896
2897                 if (wcsncmp(p, W("mixed"), 5) == 0)
2898                 {
2899                     dumpIRTrees  = true;
2900                     dumpIRLinear = true;
2901                 }
2902
2903                 if (wcsncmp(p, W("dataflow"), 8) == 0)
2904                 {
2905                     dumpIRDataflow = true;
2906                     dumpIRNoLeafs  = true;
2907                     dumpIRNoLists  = true;
2908                     dumpIRNoStmts  = true;
2909                 }
2910
2911                 if (wcsncmp(p, W("blkhdrs"), 7) == 0)
2912                 {
2913                     dumpIRBlockHeaders = true;
2914                 }
2915
2916                 for (; (*p != 0); p++)
2917                 {
2918                     if (*p == L',')
2919                     {
2920                         p++;
2921                         break;
2922                     }
2923                 }
2924             }
2925         }
2926     }
2927
2928     if (verboseDump)
2929     {
2930         verbose = true;
2931     }
2932
2933     if (dumpIR)
2934     {
2935         this->dumpIR = true;
2936     }
2937
2938     if (dumpIRTypes)
2939     {
2940         this->dumpIRTypes = true;
2941     }
2942
2943     if (dumpIRLocals)
2944     {
2945         this->dumpIRLocals = true;
2946     }
2947
2948     if (dumpIRRegs)
2949     {
2950         this->dumpIRRegs = true;
2951     }
2952
2953     if (dumpIRSsa)
2954     {
2955         this->dumpIRSsa = true;
2956     }
2957
2958     if (dumpIRValnums)
2959     {
2960         this->dumpIRValnums = true;
2961     }
2962
2963     if (dumpIRCosts)
2964     {
2965         this->dumpIRCosts = true;
2966     }
2967
2968     if (dumpIRFlags)
2969     {
2970         this->dumpIRFlags = true;
2971     }
2972
2973     if (dumpIRKinds)
2974     {
2975         this->dumpIRKinds = true;
2976     }
2977
2978     if (dumpIRNodes)
2979     {
2980         this->dumpIRNodes = true;
2981     }
2982
2983     if (dumpIRNoLists)
2984     {
2985         this->dumpIRNoLists = true;
2986     }
2987
2988     if (dumpIRNoLeafs)
2989     {
2990         this->dumpIRNoLeafs = true;
2991     }
2992
2993     if (dumpIRNoLeafs && dumpIRDataflow)
2994     {
2995         this->dumpIRDataflow = true;
2996     }
2997
2998     if (dumpIRNoStmts)
2999     {
3000         this->dumpIRNoStmts = true;
3001     }
3002
3003     if (dumpIRTrees)
3004     {
3005         this->dumpIRTrees = true;
3006     }
3007
3008     if (dumpIRLinear)
3009     {
3010         this->dumpIRLinear = true;
3011     }
3012
3013     if (dumpIRBlockHeaders)
3014     {
3015         this->dumpIRBlockHeaders = true;
3016     }
3017
3018     if (dumpIRExit)
3019     {
3020         this->dumpIRExit = true;
3021     }
3022
3023 #endif // DEBUG
3024
3025 #ifdef FEATURE_SIMD
3026     // Minimum bar for availing SIMD benefits is SSE2 on AMD64/x86.
3027     featureSIMD = jitFlags->IsSet(JitFlags::JIT_FLAG_FEATURE_SIMD);
3028 #endif // FEATURE_SIMD
3029
3030     if (compIsForInlining() || compIsForImportOnly())
3031     {
3032         return;
3033     }
3034     // The rest of the opts fields that we initialize here
3035     // should only be used when we generate code for the method
3036     // They should not be used when importing or inlining
3037
3038     opts.genFPorder = true;
3039     opts.genFPopt   = true;
3040
3041     opts.instrCount = 0;
3042     opts.lvRefCount = 0;
3043
3044 #if FEATURE_TAILCALL_OPT
3045     // By default opportunistic tail call optimization is enabled
3046     opts.compTailCallOpt     = true;
3047     opts.compTailCallLoopOpt = true;
3048 #endif
3049
3050 #ifdef PROFILING_SUPPORTED
3051     opts.compJitELTHookEnabled = false;
3052 #endif // PROFILING_SUPPORTED
3053
3054 #ifdef DEBUG
3055     opts.dspInstrs       = false;
3056     opts.dspEmit         = false;
3057     opts.dspLines        = false;
3058     opts.varNames        = false;
3059     opts.dmpHex          = false;
3060     opts.disAsm          = false;
3061     opts.disAsmSpilled   = false;
3062     opts.disDiffable     = false;
3063     opts.dspCode         = false;
3064     opts.dspEHTable      = false;
3065     opts.dspGCtbls       = false;
3066     opts.disAsm2         = false;
3067     opts.dspUnwind       = false;
3068     opts.compLongAddress = false;
3069     opts.optRepeat       = false;
3070
3071 #ifdef LATE_DISASM
3072     opts.doLateDisasm = false;
3073 #endif // LATE_DISASM
3074
3075     compDebugBreak = false;
3076
3077     //  If we have a non-empty AltJit config then we change all of these other
3078     //  config values to refer only to the AltJit.
3079     //
3080     if (!altJitConfig || opts.altJit)
3081     {
3082         if (jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
3083         {
3084             if ((JitConfig.NgenOrder() & 1) == 1)
3085             {
3086                 opts.dspOrder = true;
3087             }
3088
3089             if (JitConfig.NgenGCDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3090             {
3091                 opts.dspGCtbls = true;
3092             }
3093
3094             if (JitConfig.NgenDisasm().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3095             {
3096                 opts.disAsm = true;
3097             }
3098             if (JitConfig.NgenDisasm().contains("SPILLED", nullptr, nullptr))
3099             {
3100                 opts.disAsmSpilled = true;
3101             }
3102
3103             if (JitConfig.NgenUnwindDump().contains(info.compMethodName, info.compClassName,
3104                                                     &info.compMethodInfo->args))
3105             {
3106                 opts.dspUnwind = true;
3107             }
3108
3109             if (JitConfig.NgenEHDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3110             {
3111                 opts.dspEHTable = true;
3112             }
3113         }
3114         else
3115         {
3116             if ((JitConfig.JitOrder() & 1) == 1)
3117             {
3118                 opts.dspOrder = true;
3119             }
3120
3121             if (JitConfig.JitGCDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3122             {
3123                 opts.dspGCtbls = true;
3124             }
3125
3126             if (JitConfig.JitDisasm().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3127             {
3128                 opts.disAsm = true;
3129             }
3130
3131             if (JitConfig.JitDisasm().contains("SPILLED", nullptr, nullptr))
3132             {
3133                 opts.disAsmSpilled = true;
3134             }
3135
3136             if (JitConfig.JitUnwindDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3137             {
3138                 opts.dspUnwind = true;
3139             }
3140
3141             if (JitConfig.JitEHDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3142             {
3143                 opts.dspEHTable = true;
3144             }
3145         }
3146
3147 #ifdef LATE_DISASM
3148         if (JitConfig.JitLateDisasm().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3149             opts.doLateDisasm = true;
3150 #endif // LATE_DISASM
3151
3152         // This one applies to both Ngen/Jit Disasm output: COMPlus_JitDiffableDasm=1
3153         if (JitConfig.DiffableDasm() != 0)
3154         {
3155             opts.disDiffable = true;
3156             opts.dspDiffable = true;
3157         }
3158
3159         if (JitConfig.JitLongAddress() != 0)
3160         {
3161             opts.compLongAddress = true;
3162         }
3163
3164         if (JitConfig.JitOptRepeat().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3165         {
3166             opts.optRepeat = true;
3167         }
3168     }
3169
3170     if (verboseDump)
3171     {
3172         opts.dspCode    = true;
3173         opts.dspEHTable = true;
3174         opts.dspGCtbls  = true;
3175         opts.disAsm2    = true;
3176         opts.dspUnwind  = true;
3177         verbose         = true;
3178         verboseTrees    = shouldUseVerboseTrees();
3179         verboseSsa      = shouldUseVerboseSsa();
3180         codeGen->setVerbose(true);
3181     }
3182
3183     treesBeforeAfterMorph = (JitConfig.TreesBeforeAfterMorph() == 1);
3184     morphNum              = 0; // Initialize the morphed-trees counting.
3185
3186     expensiveDebugCheckLevel = JitConfig.JitExpensiveDebugCheckLevel();
3187     if (expensiveDebugCheckLevel == 0)
3188     {
3189         // If we're in a stress mode that modifies the flowgraph, make 1 the default.
3190         if (fgStressBBProf() || compStressCompile(STRESS_DO_WHILE_LOOPS, 30))
3191         {
3192             expensiveDebugCheckLevel = 1;
3193         }
3194     }
3195
3196     if (verbose)
3197     {
3198         printf("****** START compiling %s (MethodHash=%08x)\n", info.compFullName, info.compMethodHash());
3199         printf("Generating code for %s %s\n", Target::g_tgtPlatformName, Target::g_tgtCPUName);
3200         printf(""); // in our logic this causes a flush
3201     }
3202
3203     if (JitConfig.JitBreak().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3204     {
3205         assert(!"JitBreak reached");
3206     }
3207
3208     unsigned jitHashBreakVal = (unsigned)JitConfig.JitHashBreak();
3209     if ((jitHashBreakVal != (DWORD)-1) && (jitHashBreakVal == info.compMethodHash()))
3210     {
3211         assert(!"JitHashBreak reached");
3212     }
3213
3214     if (verbose ||
3215         JitConfig.JitDebugBreak().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args) ||
3216         JitConfig.JitBreak().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3217     {
3218         compDebugBreak = true;
3219     }
3220
3221     memset(compActiveStressModes, 0, sizeof(compActiveStressModes));
3222
3223 #endif // DEBUG
3224
3225 //-------------------------------------------------------------------------
3226
3227 #ifdef DEBUG
3228     assert(!codeGen->isGCTypeFixed());
3229     opts.compGcChecks = (JitConfig.JitGCChecks() != 0) || compStressCompile(STRESS_GENERIC_VARN, 5);
3230
3231     enum
3232     {
3233         STACK_CHECK_ON_RETURN = 0x1,
3234         STACK_CHECK_ON_CALL   = 0x2,
3235         STACK_CHECK_ALL       = 0x3,
3236     };
3237
3238     DWORD dwJitStackChecks = JitConfig.JitStackChecks();
3239     if (compStressCompile(STRESS_GENERIC_VARN, 5))
3240     {
3241         dwJitStackChecks = STACK_CHECK_ALL;
3242     }
3243     opts.compStackCheckOnRet  = (dwJitStackChecks & DWORD(STACK_CHECK_ON_RETURN)) != 0;
3244     opts.compStackCheckOnCall = (dwJitStackChecks & DWORD(STACK_CHECK_ON_CALL)) != 0;
3245 #endif
3246
3247 #if MEASURE_MEM_ALLOC
3248     s_dspMemStats = (JitConfig.DisplayMemStats() != 0);
3249 #endif
3250
3251 #ifdef PROFILING_SUPPORTED
3252     opts.compNoPInvokeInlineCB = jitFlags->IsSet(JitFlags::JIT_FLAG_PROF_NO_PINVOKE_INLINE);
3253
3254     // Cache the profiler handle
3255     if (jitFlags->IsSet(JitFlags::JIT_FLAG_PROF_ENTERLEAVE))
3256     {
3257         BOOL hookNeeded;
3258         BOOL indirected;
3259         info.compCompHnd->GetProfilingHandle(&hookNeeded, &compProfilerMethHnd, &indirected);
3260         compProfilerHookNeeded        = !!hookNeeded;
3261         compProfilerMethHndIndirected = !!indirected;
3262     }
3263     else
3264     {
3265         compProfilerHookNeeded        = false;
3266         compProfilerMethHnd           = nullptr;
3267         compProfilerMethHndIndirected = false;
3268     }
3269
3270     // Honour COMPlus_JitELTHookEnabled only if VM has not asked us to generate profiler
3271     // hooks in the first place. That is, override VM only if it hasn't asked for a
3272     // profiler callback for this method.
3273     if (!compProfilerHookNeeded && (JitConfig.JitELTHookEnabled() != 0))
3274     {
3275         opts.compJitELTHookEnabled = true;
3276     }
3277
3278     // TBD: Exclude PInvoke stubs
3279     if (opts.compJitELTHookEnabled)
3280     {
3281         compProfilerMethHnd           = (void*)DummyProfilerELTStub;
3282         compProfilerMethHndIndirected = false;
3283     }
3284
3285 #endif // PROFILING_SUPPORTED
3286
3287 #if FEATURE_TAILCALL_OPT
3288     const wchar_t* strTailCallOpt = JitConfig.TailCallOpt();
3289     if (strTailCallOpt != nullptr)
3290     {
3291         opts.compTailCallOpt = (UINT)_wtoi(strTailCallOpt) != 0;
3292     }
3293
3294     if (JitConfig.TailCallLoopOpt() == 0)
3295     {
3296         opts.compTailCallLoopOpt = false;
3297     }
3298 #endif
3299
3300     opts.compScopeInfo = opts.compDbgInfo;
3301
3302 #ifdef LATE_DISASM
3303     codeGen->getDisAssembler().disOpenForLateDisAsm(info.compMethodName, info.compClassName,
3304                                                     info.compMethodInfo->args.pSig);
3305 #endif
3306
3307 //-------------------------------------------------------------------------
3308
3309 #if RELOC_SUPPORT
3310     opts.compReloc = jitFlags->IsSet(JitFlags::JIT_FLAG_RELOC);
3311 #endif
3312
3313 #ifdef DEBUG
3314 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3315     // Whether encoding of absolute addr as PC-rel offset is enabled in RyuJIT
3316     opts.compEnablePCRelAddr = (JitConfig.EnablePCRelAddr() != 0);
3317 #endif
3318 #endif // DEBUG
3319
3320     opts.compProcedureSplitting = jitFlags->IsSet(JitFlags::JIT_FLAG_PROCSPLIT);
3321
3322 #ifdef _TARGET_ARM64_
3323     // TODO-ARM64-NYI: enable hot/cold splitting
3324     opts.compProcedureSplitting = false;
3325 #endif // _TARGET_ARM64_
3326
3327 #ifdef DEBUG
3328     opts.compProcedureSplittingEH = opts.compProcedureSplitting;
3329 #endif // DEBUG
3330
3331     if (opts.compProcedureSplitting)
3332     {
3333         // Note that opts.compdbgCode is true under ngen for checked assemblies!
3334         opts.compProcedureSplitting = !opts.compDbgCode;
3335
3336 #ifdef DEBUG
3337         // JitForceProcedureSplitting is used to force procedure splitting on checked assemblies.
3338         // This is useful for debugging on a checked build.  Note that we still only do procedure
3339         // splitting in the zapper.
3340         if (JitConfig.JitForceProcedureSplitting().contains(info.compMethodName, info.compClassName,
3341                                                             &info.compMethodInfo->args))
3342         {
3343             opts.compProcedureSplitting = true;
3344         }
3345
3346         // JitNoProcedureSplitting will always disable procedure splitting.
3347         if (JitConfig.JitNoProcedureSplitting().contains(info.compMethodName, info.compClassName,
3348                                                          &info.compMethodInfo->args))
3349         {
3350             opts.compProcedureSplitting = false;
3351         }
3352         //
3353         // JitNoProcedureSplittingEH will disable procedure splitting in functions with EH.
3354         if (JitConfig.JitNoProcedureSplittingEH().contains(info.compMethodName, info.compClassName,
3355                                                            &info.compMethodInfo->args))
3356         {
3357             opts.compProcedureSplittingEH = false;
3358         }
3359 #endif
3360     }
3361
3362     fgProfileBuffer              = nullptr;
3363     fgProfileData_ILSizeMismatch = false;
3364     fgNumProfileRuns             = 0;
3365     if (jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT))
3366     {
3367         assert(!compIsForInlining());
3368         HRESULT hr;
3369         hr = info.compCompHnd->getBBProfileData(info.compMethodHnd, &fgProfileBufferCount, &fgProfileBuffer,
3370                                                 &fgNumProfileRuns);
3371
3372         // a failed result that also has a non-NULL fgProfileBuffer
3373         // indicates that the ILSize for the method no longer matches
3374         // the ILSize for the method when profile data was collected.
3375         //
3376         // We will discard the IBC data in this case
3377         //
3378         if (FAILED(hr) && (fgProfileBuffer != nullptr))
3379         {
3380             fgProfileData_ILSizeMismatch = true;
3381             fgProfileBuffer              = nullptr;
3382         }
3383 #ifdef DEBUG
3384         // A successful result implies a non-NULL fgProfileBuffer
3385         //
3386         if (SUCCEEDED(hr))
3387         {
3388             assert(fgProfileBuffer != nullptr);
3389         }
3390
3391         // A failed result implies a NULL fgProfileBuffer
3392         //   see implementation of Compiler::fgHaveProfileData()
3393         //
3394         if (FAILED(hr))
3395         {
3396             assert(fgProfileBuffer == nullptr);
3397         }
3398 #endif
3399     }
3400
3401     opts.compNeedStackProbes = false;
3402
3403 #ifdef DEBUG
3404     if (JitConfig.StackProbesOverride() != 0 || compStressCompile(STRESS_GENERIC_VARN, 5))
3405     {
3406         opts.compNeedStackProbes = true;
3407     }
3408 #endif
3409
3410 #ifdef DEBUG
3411     // Now, set compMaxUncheckedOffsetForNullObject for STRESS_NULL_OBJECT_CHECK
3412     if (compStressCompile(STRESS_NULL_OBJECT_CHECK, 30))
3413     {
3414         compMaxUncheckedOffsetForNullObject = (size_t)JitConfig.JitMaxUncheckedOffset();
3415         if (verbose)
3416         {
3417             printf("STRESS_NULL_OBJECT_CHECK: compMaxUncheckedOffsetForNullObject=0x%X\n",
3418                    compMaxUncheckedOffsetForNullObject);
3419         }
3420     }
3421
3422     if (verbose)
3423     {
3424         printf("OPTIONS: compCodeOpt = %s\n",
3425                (opts.compCodeOpt == BLENDED_CODE)
3426                    ? "BLENDED_CODE"
3427                    : (opts.compCodeOpt == SMALL_CODE) ? "SMALL_CODE"
3428                                                       : (opts.compCodeOpt == FAST_CODE) ? "FAST_CODE" : "UNKNOWN_CODE");
3429
3430         printf("OPTIONS: compDbgCode = %s\n", dspBool(opts.compDbgCode));
3431         printf("OPTIONS: compDbgInfo = %s\n", dspBool(opts.compDbgInfo));
3432         printf("OPTIONS: compDbgEnC  = %s\n", dspBool(opts.compDbgEnC));
3433         printf("OPTIONS: compProcedureSplitting   = %s\n", dspBool(opts.compProcedureSplitting));
3434         printf("OPTIONS: compProcedureSplittingEH = %s\n", dspBool(opts.compProcedureSplittingEH));
3435
3436         if (jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT) && fgHaveProfileData())
3437         {
3438             printf("OPTIONS: using real profile data\n");
3439         }
3440
3441         if (fgProfileData_ILSizeMismatch)
3442         {
3443             printf("OPTIONS: discarded IBC profile data due to mismatch in ILSize\n");
3444         }
3445
3446         if (jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
3447         {
3448             printf("OPTIONS: Jit invoked for ngen\n");
3449         }
3450         printf("OPTIONS: Stack probing is %s\n", opts.compNeedStackProbes ? "ENABLED" : "DISABLED");
3451     }
3452 #endif
3453
3454     opts.compGCPollType = GCPOLL_NONE;
3455     if (jitFlags->IsSet(JitFlags::JIT_FLAG_GCPOLL_CALLS))
3456     {
3457         opts.compGCPollType = GCPOLL_CALL;
3458     }
3459     else if (jitFlags->IsSet(JitFlags::JIT_FLAG_GCPOLL_INLINE))
3460     {
3461         // make sure that the EE didn't set both flags.
3462         assert(opts.compGCPollType == GCPOLL_NONE);
3463         opts.compGCPollType = GCPOLL_INLINE;
3464     }
3465 }
3466
3467 #ifdef DEBUG
3468
3469 void JitDump(const char* pcFormat, ...)
3470 {
3471     va_list lst;
3472     va_start(lst, pcFormat);
3473     vflogf(jitstdout, pcFormat, lst);
3474     va_end(lst);
3475 }
3476
3477 bool Compiler::compJitHaltMethod()
3478 {
3479     /* This method returns true when we use an INS_BREAKPOINT to allow us to step into the generated native code */
3480     /* Note that this these two "Jit" environment variables also work for ngen images */
3481
3482     if (JitConfig.JitHalt().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3483     {
3484         return true;
3485     }
3486
3487     /* Use this Hash variant when there are a lot of method with the same name and different signatures */
3488
3489     unsigned fJitHashHaltVal = (unsigned)JitConfig.JitHashHalt();
3490     if ((fJitHashHaltVal != (unsigned)-1) && (fJitHashHaltVal == info.compMethodHash()))
3491     {
3492         return true;
3493     }
3494
3495     return false;
3496 }
3497
3498 /*****************************************************************************
3499  * Should we use a "stress-mode" for the given stressArea. We have different
3500  *   areas to allow the areas to be mixed in different combinations in
3501  *   different methods.
3502  * 'weight' indicates how often (as a percentage) the area should be stressed.
3503  *    It should reflect the usefulness:overhead ratio.
3504  */
3505
3506 const LPCWSTR Compiler::s_compStressModeNames[STRESS_COUNT + 1] = {
3507 #define STRESS_MODE(mode) W("STRESS_") W(#mode),
3508
3509     STRESS_MODES
3510 #undef STRESS_MODE
3511 };
3512
3513 bool Compiler::compStressCompile(compStressArea stressArea, unsigned weight)
3514 {
3515     unsigned hash;
3516     DWORD    stressLevel;
3517
3518     if (!bRangeAllowStress)
3519     {
3520         return false;
3521     }
3522
3523     if (!JitConfig.JitStressOnly().isEmpty() &&
3524         !JitConfig.JitStressOnly().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3525     {
3526         return false;
3527     }
3528
3529     bool           doStress = false;
3530     const wchar_t* strStressModeNames;
3531
3532     // Does user explicitly prevent using this STRESS_MODE through the command line?
3533     const wchar_t* strStressModeNamesNot = JitConfig.JitStressModeNamesNot();
3534     if ((strStressModeNamesNot != nullptr) &&
3535         (wcsstr(strStressModeNamesNot, s_compStressModeNames[stressArea]) != nullptr))
3536     {
3537         if (verbose)
3538         {
3539             printf("JitStressModeNamesNot contains %ws\n", s_compStressModeNames[stressArea]);
3540         }
3541         doStress = false;
3542         goto _done;
3543     }
3544
3545     // Does user explicitly set this STRESS_MODE through the command line?
3546     strStressModeNames = JitConfig.JitStressModeNames();
3547     if (strStressModeNames != nullptr)
3548     {
3549         if (wcsstr(strStressModeNames, s_compStressModeNames[stressArea]) != nullptr)
3550         {
3551             if (verbose)
3552             {
3553                 printf("JitStressModeNames contains %ws\n", s_compStressModeNames[stressArea]);
3554             }
3555             doStress = true;
3556             goto _done;
3557         }
3558
3559         // This stress mode name did not match anything in the stress
3560         // mode whitelist. If user has requested only enable mode,
3561         // don't allow this stress mode to turn on.
3562         const bool onlyEnableMode = JitConfig.JitStressModeNamesOnly() != 0;
3563
3564         if (onlyEnableMode)
3565         {
3566             doStress = false;
3567             goto _done;
3568         }
3569     }
3570
3571     // 0:   No stress (Except when explicitly set in complus_JitStressModeNames)
3572     // !=2: Vary stress. Performance will be slightly/moderately degraded
3573     // 2:   Check-all stress. Performance will be REALLY horrible
3574     stressLevel = getJitStressLevel();
3575
3576     assert(weight <= MAX_STRESS_WEIGHT);
3577
3578     /* Check for boundary conditions */
3579
3580     if (stressLevel == 0 || weight == 0)
3581     {
3582         return false;
3583     }
3584
3585     // Should we allow unlimited stress ?
3586     if (stressArea > STRESS_COUNT_VARN && stressLevel == 2)
3587     {
3588         return true;
3589     }
3590
3591     if (weight == MAX_STRESS_WEIGHT)
3592     {
3593         doStress = true;
3594         goto _done;
3595     }
3596
3597     // Get a hash which can be compared with 'weight'
3598
3599     assert(stressArea != 0);
3600     hash = (info.compMethodHash() ^ stressArea ^ stressLevel) % MAX_STRESS_WEIGHT;
3601
3602     assert(hash < MAX_STRESS_WEIGHT && weight <= MAX_STRESS_WEIGHT);
3603     doStress = (hash < weight);
3604
3605 _done:
3606
3607     if (doStress && !compActiveStressModes[stressArea])
3608     {
3609         if (verbose)
3610         {
3611             printf("\n\n*** JitStress: %ws ***\n\n", s_compStressModeNames[stressArea]);
3612         }
3613         compActiveStressModes[stressArea] = 1;
3614     }
3615
3616     return doStress;
3617 }
3618
3619 #endif // DEBUG
3620
3621 void Compiler::compInitDebuggingInfo()
3622 {
3623     assert(!compIsForInlining());
3624
3625 #ifdef DEBUG
3626     if (verbose)
3627     {
3628         printf("*************** In compInitDebuggingInfo() for %s\n", info.compFullName);
3629     }
3630 #endif
3631
3632     /*-------------------------------------------------------------------------
3633      *
3634      * Get hold of the local variable records, if there are any
3635      */
3636
3637     info.compVarScopesCount = 0;
3638
3639     if (opts.compScopeInfo)
3640     {
3641         eeGetVars();
3642     }
3643
3644     compInitVarScopeMap();
3645
3646     if (opts.compScopeInfo || opts.compDbgCode)
3647     {
3648         compInitScopeLists();
3649     }
3650
3651     if (opts.compDbgCode && (info.compVarScopesCount > 0))
3652     {
3653         /* Create a new empty basic block. fgExtendDbgLifetimes() may add
3654            initialization of variables which are in scope right from the
3655            start of the (real) first BB (and therefore artificially marked
3656            as alive) into this block.
3657          */
3658
3659         fgEnsureFirstBBisScratch();
3660
3661         fgInsertStmtAtEnd(fgFirstBB, gtNewNothingNode());
3662
3663         JITDUMP("Debuggable code - Add new BB%02u to perform initialization of variables [%08X]\n", fgFirstBB->bbNum,
3664                 dspPtr(fgFirstBB));
3665     }
3666
3667     /*-------------------------------------------------------------------------
3668      *
3669      * Read the stmt-offsets table and the line-number table
3670      */
3671
3672     info.compStmtOffsetsImplicit = ICorDebugInfo::NO_BOUNDARIES;
3673
3674     // We can only report debug info for EnC at places where the stack is empty.
3675     // Actually, at places where there are not live temps. Else, we won't be able
3676     // to map between the old and the new versions correctly as we won't have
3677     // any info for the live temps.
3678
3679     assert(!opts.compDbgEnC || !opts.compDbgInfo ||
3680            0 == (info.compStmtOffsetsImplicit & ~ICorDebugInfo::STACK_EMPTY_BOUNDARIES));
3681
3682     info.compStmtOffsetsCount = 0;
3683
3684     if (opts.compDbgInfo)
3685     {
3686         /* Get hold of the line# records, if there are any */
3687
3688         eeGetStmtOffsets();
3689
3690 #ifdef DEBUG
3691         if (verbose)
3692         {
3693             printf("info.compStmtOffsetsCount    = %d\n", info.compStmtOffsetsCount);
3694             printf("info.compStmtOffsetsImplicit = %04Xh", info.compStmtOffsetsImplicit);
3695
3696             if (info.compStmtOffsetsImplicit)
3697             {
3698                 printf(" ( ");
3699                 if (info.compStmtOffsetsImplicit & ICorDebugInfo::STACK_EMPTY_BOUNDARIES)
3700                 {
3701                     printf("STACK_EMPTY ");
3702                 }
3703                 if (info.compStmtOffsetsImplicit & ICorDebugInfo::NOP_BOUNDARIES)
3704                 {
3705                     printf("NOP ");
3706                 }
3707                 if (info.compStmtOffsetsImplicit & ICorDebugInfo::CALL_SITE_BOUNDARIES)
3708                 {
3709                     printf("CALL_SITE ");
3710                 }
3711                 printf(")");
3712             }
3713             printf("\n");
3714             IL_OFFSET* pOffs = info.compStmtOffsets;
3715             for (unsigned i = 0; i < info.compStmtOffsetsCount; i++, pOffs++)
3716             {
3717                 printf("%02d) IL_%04Xh\n", i, *pOffs);
3718             }
3719         }
3720 #endif
3721     }
3722 }
3723
3724 void Compiler::compSetOptimizationLevel()
3725 {
3726     bool     theMinOptsValue;
3727     unsigned jitMinOpts;
3728
3729     if (compIsForInlining())
3730     {
3731         theMinOptsValue = impInlineInfo->InlinerCompiler->opts.MinOpts();
3732         goto _SetMinOpts;
3733     }
3734
3735     theMinOptsValue = false;
3736
3737     if (opts.compFlags == CLFLG_MINOPT)
3738     {
3739         JITLOG((LL_INFO100, "CLFLG_MINOPT set for method %s\n", info.compFullName));
3740         theMinOptsValue = true;
3741     }
3742
3743 #ifdef DEBUG
3744     jitMinOpts = JitConfig.JitMinOpts();
3745
3746     if (!theMinOptsValue && (jitMinOpts > 0))
3747     {
3748         unsigned methodCount     = Compiler::jitTotalMethodCompiled;
3749         unsigned methodCountMask = methodCount & 0xFFF;
3750         unsigned kind            = (jitMinOpts & 0xF000000) >> 24;
3751         switch (kind)
3752         {
3753             default:
3754                 if (jitMinOpts <= methodCount)
3755                 {
3756                     if (verbose)
3757                     {
3758                         printf(" Optimizations disabled by JitMinOpts and methodCount\n");
3759                     }
3760                     theMinOptsValue = true;
3761                 }
3762                 break;
3763             case 0xD:
3764             {
3765                 unsigned firstMinopts  = (jitMinOpts >> 12) & 0xFFF;
3766                 unsigned secondMinopts = (jitMinOpts >> 0) & 0xFFF;
3767
3768                 if ((firstMinopts == methodCountMask) || (secondMinopts == methodCountMask))
3769                 {
3770                     if (verbose)
3771                     {
3772                         printf("0xD: Optimizations disabled by JitMinOpts and methodCountMask\n");
3773                     }
3774                     theMinOptsValue = true;
3775                 }
3776             }
3777             break;
3778             case 0xE:
3779             {
3780                 unsigned startMinopts = (jitMinOpts >> 12) & 0xFFF;
3781                 unsigned endMinopts   = (jitMinOpts >> 0) & 0xFFF;
3782
3783                 if ((startMinopts <= methodCountMask) && (endMinopts >= methodCountMask))
3784                 {
3785                     if (verbose)
3786                     {
3787                         printf("0xE: Optimizations disabled by JitMinOpts and methodCountMask\n");
3788                     }
3789                     theMinOptsValue = true;
3790                 }
3791             }
3792             break;
3793             case 0xF:
3794             {
3795                 unsigned bitsZero = (jitMinOpts >> 12) & 0xFFF;
3796                 unsigned bitsOne  = (jitMinOpts >> 0) & 0xFFF;
3797
3798                 if (((methodCountMask & bitsOne) == bitsOne) && ((~methodCountMask & bitsZero) == bitsZero))
3799                 {
3800                     if (verbose)
3801                     {
3802                         printf("0xF: Optimizations disabled by JitMinOpts and methodCountMask\n");
3803                     }
3804                     theMinOptsValue = true;
3805                 }
3806             }
3807             break;
3808         }
3809     }
3810
3811     if (!theMinOptsValue)
3812     {
3813         if (JitConfig.JitMinOptsName().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3814         {
3815             theMinOptsValue = true;
3816         }
3817     }
3818
3819 #if 0
3820     // The code in this #if can be used to debug optimization issues according to method hash.
3821         // To use, uncomment, rebuild and set environment variables minoptshashlo and minoptshashhi.
3822 #ifdef DEBUG
3823     unsigned methHash = info.compMethodHash();
3824     char* lostr = getenv("minoptshashlo");
3825     unsigned methHashLo = 0;
3826         if (lostr != nullptr)
3827         {
3828                 sscanf_s(lostr, "%x", &methHashLo);
3829                 char* histr = getenv("minoptshashhi");
3830                 unsigned methHashHi = UINT32_MAX;
3831                 if (histr != nullptr)
3832                 {
3833                         sscanf_s(histr, "%x", &methHashHi);
3834                         if (methHash >= methHashLo && methHash <= methHashHi)
3835                         {
3836                                 printf("MinOpts for method %s, hash = 0x%x.\n",
3837                                         info.compFullName, info.compMethodHash());
3838                                 printf("");         // in our logic this causes a flush
3839                                 theMinOptsValue = true;
3840                         }
3841                 }
3842         }
3843 #endif
3844 #endif
3845
3846     if (compStressCompile(STRESS_MIN_OPTS, 5))
3847     {
3848         theMinOptsValue = true;
3849     }
3850     // For PREJIT we never drop down to MinOpts
3851     // unless unless CLFLG_MINOPT is set
3852     else if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
3853     {
3854         if ((unsigned)JitConfig.JitMinOptsCodeSize() < info.compILCodeSize)
3855         {
3856             JITLOG((LL_INFO10, "IL Code Size exceeded, using MinOpts for method %s\n", info.compFullName));
3857             theMinOptsValue = true;
3858         }
3859         else if ((unsigned)JitConfig.JitMinOptsInstrCount() < opts.instrCount)
3860         {
3861             JITLOG((LL_INFO10, "IL instruction count exceeded, using MinOpts for method %s\n", info.compFullName));
3862             theMinOptsValue = true;
3863         }
3864         else if ((unsigned)JitConfig.JitMinOptsBbCount() < fgBBcount)
3865         {
3866             JITLOG((LL_INFO10, "Basic Block count exceeded, using MinOpts for method %s\n", info.compFullName));
3867             theMinOptsValue = true;
3868         }
3869         else if ((unsigned)JitConfig.JitMinOptsLvNumCount() < lvaCount)
3870         {
3871             JITLOG((LL_INFO10, "Local Variable Num count exceeded, using MinOpts for method %s\n", info.compFullName));
3872             theMinOptsValue = true;
3873         }
3874         else if ((unsigned)JitConfig.JitMinOptsLvRefCount() < opts.lvRefCount)
3875         {
3876             JITLOG((LL_INFO10, "Local Variable Ref count exceeded, using MinOpts for method %s\n", info.compFullName));
3877             theMinOptsValue = true;
3878         }
3879         if (theMinOptsValue == true)
3880         {
3881             JITLOG((LL_INFO10000, "IL Code Size,Instr %4d,%4d, Basic Block count %3d, Local Variable Num,Ref count "
3882                                   "%3d,%3d for method %s\n",
3883                     info.compILCodeSize, opts.instrCount, fgBBcount, lvaCount, opts.lvRefCount, info.compFullName));
3884             if (JitConfig.JitBreakOnMinOpts() != 0)
3885             {
3886                 assert(!"MinOpts enabled");
3887             }
3888         }
3889     }
3890 #else  // !DEBUG
3891     // Retail check if we should force Minopts due to the complexity of the method
3892     // For PREJIT we never drop down to MinOpts
3893     // unless unless CLFLG_MINOPT is set
3894     if (!theMinOptsValue && !opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT) &&
3895         ((DEFAULT_MIN_OPTS_CODE_SIZE < info.compILCodeSize) || (DEFAULT_MIN_OPTS_INSTR_COUNT < opts.instrCount) ||
3896          (DEFAULT_MIN_OPTS_BB_COUNT < fgBBcount) || (DEFAULT_MIN_OPTS_LV_NUM_COUNT < lvaCount) ||
3897          (DEFAULT_MIN_OPTS_LV_REF_COUNT < opts.lvRefCount)))
3898     {
3899         theMinOptsValue = true;
3900     }
3901 #endif // DEBUG
3902
3903     JITLOG((LL_INFO10000,
3904             "IL Code Size,Instr %4d,%4d, Basic Block count %3d, Local Variable Num,Ref count %3d,%3d for method %s\n",
3905             info.compILCodeSize, opts.instrCount, fgBBcount, lvaCount, opts.lvRefCount, info.compFullName));
3906
3907 #if 0
3908     // The code in this #if has been useful in debugging loop cloning issues, by
3909     // enabling selective enablement of the loop cloning optimization according to
3910     // method hash.
3911 #ifdef DEBUG
3912     if (!theMinOptsValue)
3913     {
3914     unsigned methHash = info.compMethodHash();
3915     char* lostr = getenv("opthashlo");
3916     unsigned methHashLo = 0;
3917     if (lostr != NULL)
3918     {
3919         sscanf_s(lostr, "%x", &methHashLo);
3920         // methHashLo = (unsigned(atoi(lostr)) << 2);  // So we don't have to use negative numbers.
3921     }
3922     char* histr = getenv("opthashhi");
3923     unsigned methHashHi = UINT32_MAX;
3924     if (histr != NULL)
3925     {
3926         sscanf_s(histr, "%x", &methHashHi);
3927         // methHashHi = (unsigned(atoi(histr)) << 2);  // So we don't have to use negative numbers.
3928     }
3929     if (methHash < methHashLo || methHash > methHashHi)
3930     {
3931         theMinOptsValue = true;
3932     }
3933     else
3934     {
3935         printf("Doing optimization in  in %s (0x%x).\n", info.compFullName, methHash);
3936     }
3937     }
3938 #endif
3939 #endif
3940
3941 _SetMinOpts:
3942
3943     // Set the MinOpts value
3944     opts.SetMinOpts(theMinOptsValue);
3945
3946 #ifdef DEBUG
3947     if (verbose && !compIsForInlining())
3948     {
3949         printf("OPTIONS: opts.MinOpts() == %s\n", opts.MinOpts() ? "true" : "false");
3950     }
3951 #endif
3952
3953     /* Control the optimizations */
3954
3955     if (opts.MinOpts() || opts.compDbgCode)
3956     {
3957         opts.compFlags &= ~CLFLG_MAXOPT;
3958         opts.compFlags |= CLFLG_MINOPT;
3959     }
3960
3961     if (!compIsForInlining())
3962     {
3963         codeGen->setFramePointerRequired(false);
3964         codeGen->setFrameRequired(false);
3965
3966         if (opts.MinOpts() || opts.compDbgCode)
3967         {
3968             codeGen->setFrameRequired(true);
3969         }
3970
3971 #if !defined(_TARGET_AMD64_)
3972         // The VM sets JitFlags::JIT_FLAG_FRAMED for two reasons: (1) the COMPlus_JitFramed variable is set, or
3973         // (2) the function is marked "noinline". The reason for #2 is that people mark functions
3974         // noinline to ensure the show up on in a stack walk. But for AMD64, we don't need a frame
3975         // pointer for the frame to show up in stack walk.
3976         if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_FRAMED))
3977             codeGen->setFrameRequired(true);
3978 #endif
3979
3980         if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_RELOC))
3981         {
3982             codeGen->genAlignLoops = false; // loop alignment not supported for prejitted code
3983
3984             // The zapper doesn't set JitFlags::JIT_FLAG_ALIGN_LOOPS, and there is
3985             // no reason for it to set it as the JIT doesn't currently support loop alignment
3986             // for prejitted images. (The JIT doesn't know the final address of the code, hence
3987             // it can't align code based on unknown addresses.)
3988             assert(!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_ALIGN_LOOPS));
3989         }
3990         else
3991         {
3992             codeGen->genAlignLoops = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_ALIGN_LOOPS);
3993         }
3994     }
3995
3996     info.compUnwrapContextful = !opts.MinOpts() && !opts.compDbgCode;
3997
3998     fgCanRelocateEHRegions = true;
3999 }
4000
4001 #ifdef _TARGET_ARMARCH_
4002 // Function compRsvdRegCheck:
4003 //  given a curState to use for calculating the total frame size
4004 //  it will return true if the REG_OPT_RSVD should be reserved so
4005 //  that it can be use to form large offsets when accessing stack
4006 //  based LclVar including both incoming and out going argument areas.
4007 //
4008 //  The method advances the frame layout state to curState by calling
4009 //  lvaFrameSize(curState).
4010 //
4011 bool Compiler::compRsvdRegCheck(FrameLayoutState curState)
4012 {
4013     // Always do the layout even if returning early. Callers might
4014     // depend on us to do the layout.
4015     unsigned frameSize = lvaFrameSize(curState);
4016
4017     if (opts.MinOpts())
4018     {
4019         // Have a recovery path in case we fail to reserve REG_OPT_RSVD and go
4020         // over the limit of SP and FP offset ranges due to large
4021         // temps.
4022         return true;
4023     }
4024
4025     unsigned calleeSavedRegMaxSz = CALLEE_SAVED_REG_MAXSZ;
4026     if (compFloatingPointUsed)
4027     {
4028         calleeSavedRegMaxSz += CALLEE_SAVED_FLOAT_MAXSZ;
4029     }
4030
4031     noway_assert(frameSize > calleeSavedRegMaxSz);
4032
4033 #if defined(_TARGET_ARM64_)
4034
4035     // TODO-ARM64-CQ: update this!
4036     return true; // just always assume we'll need it, for now
4037
4038 #else  // _TARGET_ARM_
4039
4040     // frame layout:
4041     //
4042     //         low addresses
4043     //                         inArgs               compArgSize
4044     //  origSP --->
4045     //  LR     --->
4046     //  R11    --->
4047     //                +        callee saved regs    CALLEE_SAVED_REG_MAXSZ   (32 bytes)
4048     //                     optional saved fp regs   16 * sizeof(float)       (64 bytes)
4049     //                -        lclSize
4050     //                             incl. TEMPS      MAX_SPILL_TEMP_SIZE
4051     //                +            incl. outArgs
4052     //  SP     --->
4053     //                -
4054     //          high addresses
4055
4056     // With codeGen->isFramePointerRequired we use R11 to access incoming args with positive offsets
4057     // and use R11 to access LclVars with negative offsets in the non funclet or
4058     // main region we use SP with positive offsets. The limiting factor in the
4059     // codeGen->isFramePointerRequired case is that we need the offset to be less than or equal to 0x7C
4060     // for negative offsets, but positive offsets can be imm12 limited by vldr/vstr
4061     // using +/-imm8.
4062     //
4063     // Subtract 4 bytes for alignment of a local var because number of temps could
4064     // trigger a misaligned double or long.
4065     //
4066     unsigned maxR11ArgLimit = (compFloatingPointUsed ? 0x03FC : 0x0FFC);
4067     unsigned maxR11LclLimit = 0x0078;
4068
4069     if (codeGen->isFramePointerRequired())
4070     {
4071         unsigned maxR11LclOffs = frameSize;
4072         unsigned maxR11ArgOffs = compArgSize + (2 * REGSIZE_BYTES);
4073         if (maxR11LclOffs > maxR11LclLimit || maxR11ArgOffs > maxR11ArgLimit)
4074         {
4075             return true;
4076         }
4077     }
4078
4079     // So this case is the SP based frame case, but note that we also will use SP based
4080     // offsets for R11 based frames in the non-funclet main code area. However if we have
4081     // passed the above max_R11_offset check these SP checks won't fire.
4082
4083     // Check local coverage first. If vldr/vstr will be used the limit can be +/-imm8.
4084     unsigned maxSPLclLimit = (compFloatingPointUsed ? 0x03F8 : 0x0FF8);
4085     if (frameSize > (codeGen->isFramePointerUsed() ? (maxR11LclLimit + maxSPLclLimit) : maxSPLclLimit))
4086     {
4087         return true;
4088     }
4089
4090     // Check arguments coverage.
4091     if ((!codeGen->isFramePointerUsed() || (compArgSize > maxR11ArgLimit)) && (compArgSize + frameSize) > maxSPLclLimit)
4092     {
4093         return true;
4094     }
4095
4096     // We won't need to reserve REG_OPT_RSVD.
4097     //
4098     return false;
4099 #endif // _TARGET_ARM_
4100 }
4101 #endif // _TARGET_ARMARCH_
4102
4103 void Compiler::compFunctionTraceStart()
4104 {
4105 #ifdef DEBUG
4106     if (compIsForInlining())
4107     {
4108         return;
4109     }
4110
4111     if ((JitConfig.JitFunctionTrace() != 0) && !opts.disDiffable)
4112     {
4113         LONG newJitNestingLevel = InterlockedIncrement(&Compiler::jitNestingLevel);
4114         if (newJitNestingLevel <= 0)
4115         {
4116             printf("{ Illegal nesting level %d }\n", newJitNestingLevel);
4117         }
4118
4119         for (LONG i = 0; i < newJitNestingLevel - 1; i++)
4120         {
4121             printf("  ");
4122         }
4123         printf("{ Start Jitting %s (MethodHash=%08x)\n", info.compFullName,
4124                info.compMethodHash()); /* } editor brace matching workaround for this printf */
4125     }
4126 #endif // DEBUG
4127 }
4128
4129 void Compiler::compFunctionTraceEnd(void* methodCodePtr, ULONG methodCodeSize, bool isNYI)
4130 {
4131 #ifdef DEBUG
4132     assert(!compIsForInlining());
4133
4134     if ((JitConfig.JitFunctionTrace() != 0) && !opts.disDiffable)
4135     {
4136         LONG newJitNestingLevel = InterlockedDecrement(&Compiler::jitNestingLevel);
4137         if (newJitNestingLevel < 0)
4138         {
4139             printf("{ Illegal nesting level %d }\n", newJitNestingLevel);
4140         }
4141
4142         for (LONG i = 0; i < newJitNestingLevel; i++)
4143         {
4144             printf("  ");
4145         }
4146         /* { editor brace-matching workaround for following printf */
4147         printf("} Jitted Entry %03x at" FMT_ADDR "method %s size %08x%s\n", Compiler::jitTotalMethodCompiled,
4148                DBG_ADDR(methodCodePtr), info.compFullName, methodCodeSize,
4149                isNYI ? " NYI" : (compIsForImportOnly() ? " import only" : ""));
4150     }
4151 #endif // DEBUG
4152 }
4153
4154 //*********************************************************************************************
4155 // #Phases
4156 //
4157 // This is the most interesting 'toplevel' function in the JIT.  It goes through the operations of
4158 // importing, morphing, optimizations and code generation.  This is called from the EE through the
4159 // code:CILJit::compileMethod function.
4160 //
4161 // For an overview of the structure of the JIT, see:
4162 //   https://github.com/dotnet/coreclr/blob/master/Documentation/botr/ryujit-overview.md
4163 //
4164 void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags* compileFlags)
4165 {
4166     if (compIsForInlining())
4167     {
4168         // Notify root instance that an inline attempt is about to import IL
4169         impInlineRoot()->m_inlineStrategy->NoteImport();
4170     }
4171
4172     hashBv::Init(this);
4173
4174     VarSetOps::AssignAllowUninitRhs(this, compCurLife, VarSetOps::UninitVal());
4175
4176     /* The temp holding the secret stub argument is used by fgImport() when importing the intrinsic. */
4177
4178     if (info.compPublishStubParam)
4179     {
4180         assert(lvaStubArgumentVar == BAD_VAR_NUM);
4181         lvaStubArgumentVar                  = lvaGrabTempWithImplicitUse(false DEBUGARG("stub argument"));
4182         lvaTable[lvaStubArgumentVar].lvType = TYP_I_IMPL;
4183     }
4184
4185     EndPhase(PHASE_PRE_IMPORT);
4186
4187     compFunctionTraceStart();
4188
4189     /* Convert the instrs in each basic block to a tree based intermediate representation */
4190
4191     fgImport();
4192
4193     assert(!fgComputePredsDone);
4194     if (fgCheapPredsValid)
4195     {
4196         // Remove cheap predecessors before inlining; allowing the cheap predecessor lists to be inserted
4197         // with inlined blocks causes problems.
4198         fgRemovePreds();
4199     }
4200
4201     EndPhase(PHASE_IMPORTATION);
4202
4203     if (compIsForInlining())
4204     {
4205         /* Quit inlining if fgImport() failed for any reason. */
4206
4207         if (!compDonotInline())
4208         {
4209             /* Filter out unimported BBs */
4210
4211             fgRemoveEmptyBlocks();
4212         }
4213
4214         EndPhase(PHASE_POST_IMPORT);
4215
4216 #ifdef FEATURE_JIT_METHOD_PERF
4217         if (pCompJitTimer != nullptr)
4218         {
4219 #if MEASURE_CLRAPI_CALLS
4220             EndPhase(PHASE_CLR_API);
4221 #endif
4222             pCompJitTimer->Terminate(this, CompTimeSummaryInfo::s_compTimeSummary, false);
4223         }
4224 #endif
4225
4226         return;
4227     }
4228
4229     assert(!compDonotInline());
4230
4231     // Maybe the caller was not interested in generating code
4232     if (compIsForImportOnly())
4233     {
4234         compFunctionTraceEnd(nullptr, 0, false);
4235         return;
4236     }
4237
4238 #if !FEATURE_EH
4239     // If we aren't yet supporting EH in a compiler bring-up, remove as many EH handlers as possible, so
4240     // we can pass tests that contain try/catch EH, but don't actually throw any exceptions.
4241     fgRemoveEH();
4242 #endif // !FEATURE_EH
4243
4244     if (compileFlags->IsSet(JitFlags::JIT_FLAG_BBINSTR))
4245     {
4246         fgInstrumentMethod();
4247     }
4248
4249     // We could allow ESP frames. Just need to reserve space for
4250     // pushing EBP if the method becomes an EBP-frame after an edit.
4251     // Note that requiring a EBP Frame disallows double alignment.  Thus if we change this
4252     // we either have to disallow double alignment for E&C some other way or handle it in EETwain.
4253
4254     if (opts.compDbgEnC)
4255     {
4256         codeGen->setFramePointerRequired(true);
4257
4258         // Since we need a slots for security near ebp, its not possible
4259         // to do this after an Edit without shifting all the locals.
4260         // So we just always reserve space for these slots in case an Edit adds them
4261         opts.compNeedSecurityCheck = true;
4262
4263         // We don't care about localloc right now. If we do support it,
4264         // EECodeManager::FixContextForEnC() needs to handle it smartly
4265         // in case the localloc was actually executed.
4266         //
4267         // compLocallocUsed            = true;
4268     }
4269
4270     EndPhase(PHASE_POST_IMPORT);
4271
4272     /* Initialize the BlockSet epoch */
4273
4274     NewBasicBlockEpoch();
4275
4276     /* Massage the trees so that we can generate code out of them */
4277
4278     fgMorph();
4279     EndPhase(PHASE_MORPH_END);
4280
4281     /* GS security checks for unsafe buffers */
4282     if (getNeedsGSSecurityCookie())
4283     {
4284 #ifdef DEBUG
4285         if (verbose)
4286         {
4287             printf("\n*************** -GS checks for unsafe buffers \n");
4288         }
4289 #endif
4290
4291         gsGSChecksInitCookie();
4292
4293         if (compGSReorderStackLayout)
4294         {
4295             gsCopyShadowParams();
4296         }
4297
4298 #ifdef DEBUG
4299         if (verbose)
4300         {
4301             fgDispBasicBlocks(true);
4302             printf("\n");
4303         }
4304 #endif
4305     }
4306     EndPhase(PHASE_GS_COOKIE);
4307
4308     /* Compute bbNum, bbRefs and bbPreds */
4309
4310     JITDUMP("\nRenumbering the basic blocks for fgComputePred\n");
4311     fgRenumberBlocks();
4312
4313     noway_assert(!fgComputePredsDone); // This is the first time full (not cheap) preds will be computed.
4314     fgComputePreds();
4315     EndPhase(PHASE_COMPUTE_PREDS);
4316
4317     /* If we need to emit GC Poll calls, mark the blocks that need them now.  This is conservative and can
4318      * be optimized later. */
4319     fgMarkGCPollBlocks();
4320     EndPhase(PHASE_MARK_GC_POLL_BLOCKS);
4321
4322     /* From this point on the flowgraph information such as bbNum,
4323      * bbRefs or bbPreds has to be kept updated */
4324
4325     // Compute the edge weights (if we have profile data)
4326     fgComputeEdgeWeights();
4327     EndPhase(PHASE_COMPUTE_EDGE_WEIGHTS);
4328
4329 #if FEATURE_EH_FUNCLETS
4330
4331     /* Create funclets from the EH handlers. */
4332
4333     fgCreateFunclets();
4334     EndPhase(PHASE_CREATE_FUNCLETS);
4335
4336 #endif // FEATURE_EH_FUNCLETS
4337
4338     if (!opts.MinOpts() && !opts.compDbgCode)
4339     {
4340         optOptimizeLayout();
4341         EndPhase(PHASE_OPTIMIZE_LAYOUT);
4342
4343         // Compute reachability sets and dominators.
4344         fgComputeReachability();
4345     }
4346
4347     // Transform each GT_ALLOCOBJ node into either an allocation helper call or
4348     // local variable allocation on the stack.
4349     ObjectAllocator objectAllocator(this);
4350     objectAllocator.Run();
4351
4352     if (!opts.MinOpts() && !opts.compDbgCode)
4353     {
4354         /*  Perform loop inversion (i.e. transform "while" loops into
4355             "repeat" loops) and discover and classify natural loops
4356             (e.g. mark iterative loops as such). Also marks loop blocks
4357             and sets bbWeight to the loop nesting levels
4358         */
4359
4360         optOptimizeLoops();
4361         EndPhase(PHASE_OPTIMIZE_LOOPS);
4362
4363         // Clone loops with optimization opportunities, and
4364         // choose the one based on dynamic condition evaluation.
4365         optCloneLoops();
4366         EndPhase(PHASE_CLONE_LOOPS);
4367
4368         /* Unroll loops */
4369         optUnrollLoops();
4370         EndPhase(PHASE_UNROLL_LOOPS);
4371     }
4372
4373 #ifdef DEBUG
4374     fgDebugCheckLinks();
4375 #endif
4376
4377     /* Create the variable table (and compute variable ref counts) */
4378
4379     lvaMarkLocalVars();
4380     EndPhase(PHASE_MARK_LOCAL_VARS);
4381
4382     // IMPORTANT, after this point, every place where trees are modified or cloned
4383     // the local variable reference counts must be updated
4384     // You can test the value of the following variable to see if
4385     // the local variable ref counts must be updated
4386     //
4387     assert(lvaLocalVarRefCounted == true);
4388
4389     if (!opts.MinOpts() && !opts.compDbgCode)
4390     {
4391         /* Optimize boolean conditions */
4392
4393         optOptimizeBools();
4394         EndPhase(PHASE_OPTIMIZE_BOOLS);
4395
4396         // optOptimizeBools() might have changed the number of blocks; the dominators/reachability might be bad.
4397     }
4398
4399     /* Figure out the order in which operators are to be evaluated */
4400     fgFindOperOrder();
4401     EndPhase(PHASE_FIND_OPER_ORDER);
4402
4403     // Weave the tree lists. Anyone who modifies the tree shapes after
4404     // this point is responsible for calling fgSetStmtSeq() to keep the
4405     // nodes properly linked.
4406     // This can create GC poll calls, and create new BasicBlocks (without updating dominators/reachability).
4407     fgSetBlockOrder();
4408     EndPhase(PHASE_SET_BLOCK_ORDER);
4409
4410     // IMPORTANT, after this point, every place where tree topology changes must redo evaluation
4411     // order (gtSetStmtInfo) and relink nodes (fgSetStmtSeq) if required.
4412     CLANG_FORMAT_COMMENT_ANCHOR;
4413
4414 #ifdef DEBUG
4415     // Now  we have determined the order of evaluation and the gtCosts for every node.
4416     // If verbose, dump the full set of trees here before the optimization phases mutate them
4417     //
4418     if (verbose)
4419     {
4420         fgDispBasicBlocks(true); // 'true' will call fgDumpTrees() after dumping the BasicBlocks
4421         printf("\n");
4422     }
4423 #endif
4424
4425     // At this point we know if we are fully interruptible or not
4426     if (!opts.MinOpts() && !opts.compDbgCode)
4427     {
4428         bool doSsa           = true;
4429         bool doEarlyProp     = true;
4430         bool doValueNum      = true;
4431         bool doLoopHoisting  = true;
4432         bool doCopyProp      = true;
4433         bool doAssertionProp = true;
4434         bool doRangeAnalysis = true;
4435         int  iterations      = 1;
4436
4437 #ifdef DEBUG
4438         doSsa           = (JitConfig.JitDoSsa() != 0);
4439         doEarlyProp     = doSsa && (JitConfig.JitDoEarlyProp() != 0);
4440         doValueNum      = doSsa && (JitConfig.JitDoValueNumber() != 0);
4441         doLoopHoisting  = doValueNum && (JitConfig.JitDoLoopHoisting() != 0);
4442         doCopyProp      = doValueNum && (JitConfig.JitDoCopyProp() != 0);
4443         doAssertionProp = doValueNum && (JitConfig.JitDoAssertionProp() != 0);
4444         doRangeAnalysis = doAssertionProp && (JitConfig.JitDoRangeAnalysis() != 0);
4445
4446         if (opts.optRepeat)
4447         {
4448             iterations = JitConfig.JitOptRepeatCount();
4449         }
4450 #endif
4451
4452         while (iterations > 0)
4453         {
4454             if (doSsa)
4455             {
4456                 fgSsaBuild();
4457                 EndPhase(PHASE_BUILD_SSA);
4458             }
4459
4460             if (doEarlyProp)
4461             {
4462                 /* Propagate array length and rewrite getType() method call */
4463                 optEarlyProp();
4464                 EndPhase(PHASE_EARLY_PROP);
4465             }
4466
4467             if (doValueNum)
4468             {
4469                 fgValueNumber();
4470                 EndPhase(PHASE_VALUE_NUMBER);
4471             }
4472
4473             if (doLoopHoisting)
4474             {
4475                 /* Hoist invariant code out of loops */
4476                 optHoistLoopCode();
4477                 EndPhase(PHASE_HOIST_LOOP_CODE);
4478             }
4479
4480             if (doCopyProp)
4481             {
4482                 /* Perform VN based copy propagation */
4483                 optVnCopyProp();
4484                 EndPhase(PHASE_VN_COPY_PROP);
4485             }
4486
4487 #if FEATURE_ANYCSE
4488             /* Remove common sub-expressions */
4489             optOptimizeCSEs();
4490 #endif // FEATURE_ANYCSE
4491
4492 #if ASSERTION_PROP
4493             if (doAssertionProp)
4494             {
4495                 /* Assertion propagation */
4496                 optAssertionPropMain();
4497                 EndPhase(PHASE_ASSERTION_PROP_MAIN);
4498             }
4499
4500             if (doRangeAnalysis)
4501             {
4502                 /* Optimize array index range checks */
4503                 RangeCheck rc(this);
4504                 rc.OptimizeRangeChecks();
4505                 EndPhase(PHASE_OPTIMIZE_INDEX_CHECKS);
4506             }
4507 #endif // ASSERTION_PROP
4508
4509             /* update the flowgraph if we modified it during the optimization phase*/
4510             if (fgModified)
4511             {
4512                 fgUpdateFlowGraph();
4513                 EndPhase(PHASE_UPDATE_FLOW_GRAPH);
4514
4515                 // Recompute the edge weight if we have modified the flow graph
4516                 fgComputeEdgeWeights();
4517                 EndPhase(PHASE_COMPUTE_EDGE_WEIGHTS2);
4518             }
4519
4520             // Iterate if requested, resetting annotations first.
4521             if (--iterations == 0)
4522             {
4523                 break;
4524             }
4525             ResetOptAnnotations();
4526             RecomputeLoopInfo();
4527         }
4528     }
4529
4530 #ifdef _TARGET_AMD64_
4531     //  Check if we need to add the Quirk for the PPP backward compat issue
4532     compQuirkForPPPflag = compQuirkForPPP();
4533 #endif
4534
4535     fgDetermineFirstColdBlock();
4536     EndPhase(PHASE_DETERMINE_FIRST_COLD_BLOCK);
4537
4538 #ifdef DEBUG
4539     fgDebugCheckLinks(compStressCompile(STRESS_REMORPH_TREES, 50));
4540
4541     // Stash the current estimate of the function's size if necessary.
4542     if (verbose)
4543     {
4544         compSizeEstimate  = 0;
4545         compCycleEstimate = 0;
4546         for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
4547         {
4548             for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->getNextStmt())
4549             {
4550                 compSizeEstimate += stmt->GetCostSz();
4551                 compCycleEstimate += stmt->GetCostEx();
4552             }
4553         }
4554     }
4555 #endif
4556
4557 #ifndef LEGACY_BACKEND
4558     // rationalize trees
4559     Rationalizer rat(this); // PHASE_RATIONALIZE
4560     rat.Run();
4561 #endif // !LEGACY_BACKEND
4562
4563     // Here we do "simple lowering".  When the RyuJIT backend works for all
4564     // platforms, this will be part of the more general lowering phase.  For now, though, we do a separate
4565     // pass of "final lowering."  We must do this before (final) liveness analysis, because this creates
4566     // range check throw blocks, in which the liveness must be correct.
4567     fgSimpleLowering();
4568     EndPhase(PHASE_SIMPLE_LOWERING);
4569
4570 #ifdef LEGACY_BACKEND
4571     /* Local variable liveness */
4572     fgLocalVarLiveness();
4573     EndPhase(PHASE_LCLVARLIVENESS);
4574 #endif // !LEGACY_BACKEND
4575
4576 #ifdef DEBUG
4577     fgDebugCheckBBlist();
4578     fgDebugCheckLinks();
4579 #endif
4580
4581     /* Enable this to gather statistical data such as
4582      * call and register argument info, flowgraph and loop info, etc. */
4583
4584     compJitStats();
4585
4586 #ifdef _TARGET_ARM_
4587     if (compLocallocUsed)
4588     {
4589         // We reserve REG_SAVED_LOCALLOC_SP to store SP on entry for stack unwinding
4590         codeGen->regSet.rsMaskResvd |= RBM_SAVED_LOCALLOC_SP;
4591     }
4592 #endif // _TARGET_ARM_
4593 #ifdef _TARGET_ARMARCH_
4594     if (compRsvdRegCheck(PRE_REGALLOC_FRAME_LAYOUT))
4595     {
4596         // We reserve R10/IP1 in this case to hold the offsets in load/store instructions
4597         codeGen->regSet.rsMaskResvd |= RBM_OPT_RSVD;
4598         assert(REG_OPT_RSVD != REG_FP);
4599     }
4600     // compRsvdRegCheck() has read out the FramePointerUsed property, but doLinearScan()
4601     // tries to overwrite it later. This violates the PhasedVar rule and triggers an assertion.
4602     // TODO-ARM-Bug?: What is the proper way to handle this situation?
4603     codeGen->resetFramePointerUsedWritePhase();
4604
4605 #ifdef DEBUG
4606     //
4607     // Display the pre-regalloc frame offsets that we have tentatively decided upon
4608     //
4609     if (verbose)
4610         lvaTableDump();
4611 #endif
4612 #endif // _TARGET_ARMARCH_
4613
4614     /* Assign registers to variables, etc. */
4615     CLANG_FORMAT_COMMENT_ANCHOR;
4616
4617 #ifndef LEGACY_BACKEND
4618     ///////////////////////////////////////////////////////////////////////////////
4619     // Dominator and reachability sets are no longer valid. They haven't been
4620     // maintained up to here, and shouldn't be used (unless recomputed).
4621     ///////////////////////////////////////////////////////////////////////////////
4622     fgDomsComputed = false;
4623
4624     /* Create LSRA before Lowering, this way Lowering can initialize the TreeNode Map */
4625     m_pLinearScan = getLinearScanAllocator(this);
4626
4627     /* Lower */
4628     Lowering lower(this, m_pLinearScan); // PHASE_LOWERING
4629     lower.Run();
4630
4631     assert(lvaSortAgain == false); // We should have re-run fgLocalVarLiveness() in lower.Run()
4632     lvaTrackedFixed = true;        // We can not add any new tracked variables after this point.
4633
4634     /* Now that lowering is completed we can proceed to perform register allocation */
4635     m_pLinearScan->doLinearScan();
4636     EndPhase(PHASE_LINEAR_SCAN);
4637
4638     // Copied from rpPredictRegUse()
4639     genFullPtrRegMap = (codeGen->genInterruptible || !codeGen->isFramePointerUsed());
4640 #else  // LEGACY_BACKEND
4641
4642     lvaTrackedFixed = true; // We cannot add any new tracked variables after this point.
4643     // For the classic JIT32 at this point lvaSortAgain can be set and raAssignVars() will call lvaSortOnly()
4644
4645     // Now do "classic" register allocation.
4646     raAssignVars();
4647     EndPhase(PHASE_RA_ASSIGN_VARS);
4648 #endif // LEGACY_BACKEND
4649
4650 #ifdef DEBUG
4651     fgDebugCheckLinks();
4652 #endif
4653
4654     /* Generate code */
4655
4656     codeGen->genGenerateCode(methodCodePtr, methodCodeSize);
4657
4658 #ifdef FEATURE_JIT_METHOD_PERF
4659     if (pCompJitTimer)
4660     {
4661 #if MEASURE_CLRAPI_CALLS
4662         EndPhase(PHASE_CLR_API);
4663 #endif
4664         pCompJitTimer->Terminate(this, CompTimeSummaryInfo::s_compTimeSummary, true);
4665     }
4666 #endif
4667
4668     RecordStateAtEndOfCompilation();
4669
4670 #ifdef FEATURE_TRACELOGGING
4671     compJitTelemetry.NotifyEndOfCompilation();
4672 #endif
4673
4674 #if defined(DEBUG)
4675     ++Compiler::jitTotalMethodCompiled;
4676 #endif // defined(DEBUG)
4677
4678     compFunctionTraceEnd(*methodCodePtr, *methodCodeSize, false);
4679
4680 #if FUNC_INFO_LOGGING
4681     if (compJitFuncInfoFile != nullptr)
4682     {
4683         assert(!compIsForInlining());
4684 #ifdef DEBUG // We only have access to info.compFullName in DEBUG builds.
4685         fprintf(compJitFuncInfoFile, "%s\n", info.compFullName);
4686 #elif FEATURE_SIMD
4687         fprintf(compJitFuncInfoFile, " %s\n", eeGetMethodFullName(info.compMethodHnd));
4688 #endif
4689         fprintf(compJitFuncInfoFile, ""); // in our logic this causes a flush
4690     }
4691 #endif // FUNC_INFO_LOGGING
4692 }
4693
4694 //------------------------------------------------------------------------
4695 // ResetOptAnnotations: Clear annotations produced during global optimizations.
4696 //
4697 // Notes:
4698 //    The intent of this method is to clear any information typically assumed
4699 //    to be set only once; it is used between iterations when JitOptRepeat is
4700 //    in effect.
4701
4702 void Compiler::ResetOptAnnotations()
4703 {
4704     assert(opts.optRepeat);
4705     assert(JitConfig.JitOptRepeatCount() > 0);
4706     fgResetForSsa();
4707     vnStore               = nullptr;
4708     m_opAsgnVarDefSsaNums = nullptr;
4709     m_blockToEHPreds      = nullptr;
4710     fgSsaPassesCompleted  = 0;
4711     fgVNPassesCompleted   = 0;
4712
4713     for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
4714     {
4715         for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->getNextStmt())
4716         {
4717             stmt->gtFlags &= ~GTF_STMT_HAS_CSE;
4718
4719             for (GenTreePtr tree = stmt->gtStmt.gtStmtList; tree != nullptr; tree = tree->gtNext)
4720             {
4721                 tree->ClearVN();
4722                 tree->ClearAssertion();
4723                 tree->gtCSEnum = NO_CSE;
4724             }
4725         }
4726     }
4727 }
4728
4729 //------------------------------------------------------------------------
4730 // RecomputeLoopInfo: Recompute loop annotations between opt-repeat iterations.
4731 //
4732 // Notes:
4733 //    The intent of this method is to update loop structure annotations, and those
4734 //    they depend on; these annotations may have become stale during optimization,
4735 //    and need to be up-to-date before running another iteration of optimizations.
4736
4737 void Compiler::RecomputeLoopInfo()
4738 {
4739     assert(opts.optRepeat);
4740     assert(JitConfig.JitOptRepeatCount() > 0);
4741     // Recompute reachability sets, dominators, and loops.
4742     optLoopCount   = 0;
4743     fgDomsComputed = false;
4744     for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
4745     {
4746         block->bbFlags &= ~BBF_LOOP_FLAGS;
4747     }
4748     fgComputeReachability();
4749     // Rebuild the loop tree annotations themselves.  Since this is performed as
4750     // part of 'optOptimizeLoops', this will also re-perform loop rotation, but
4751     // not other optimizations, as the others are not part of 'optOptimizeLoops'.
4752     optOptimizeLoops();
4753 }
4754
4755 /*****************************************************************************/
4756 void Compiler::ProcessShutdownWork(ICorStaticInfo* statInfo)
4757 {
4758 }
4759
4760 #ifdef _TARGET_AMD64_
4761 //  Check if we need to add the Quirk for the PPP backward compat issue.
4762 //  This Quirk addresses a compatibility issue between the new RyuJit and the previous JIT64.
4763 //  A backward compatibity issue called 'PPP' exists where a PInvoke call passes a 32-byte struct
4764 //  into a native API which basically writes 48 bytes of data into the struct.
4765 //  With the stack frame layout used by the RyuJIT the extra 16 bytes written corrupts a
4766 //  caller saved register and this leads to an A/V in the calling method.
4767 //  The older JIT64 jit compiler just happened to have a different stack layout and/or
4768 //  caller saved register set so that it didn't hit the A/V in the caller.
4769 //  By increasing the amount of stack allocted for the struct by 32 bytes we can fix this.
4770 //
4771 //  Return true if we actually perform the Quirk, otherwise return false
4772 //
4773 bool Compiler::compQuirkForPPP()
4774 {
4775     if (lvaCount != 2)
4776     { // We require that there are exactly two locals
4777         return false;
4778     }
4779
4780     if (compTailCallUsed)
4781     { // Don't try this quirk if a tail call was used
4782         return false;
4783     }
4784
4785     bool       hasOutArgs          = false;
4786     LclVarDsc* varDscExposedStruct = nullptr;
4787
4788     unsigned   lclNum;
4789     LclVarDsc* varDsc;
4790
4791     /* Look for struct locals that are address taken */
4792     for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
4793     {
4794         if (varDsc->lvIsParam) // It can't be a parameter
4795         {
4796             continue;
4797         }
4798
4799         // We require that the OutgoingArg space lclVar exists
4800         if (lclNum == lvaOutgoingArgSpaceVar)
4801         {
4802             hasOutArgs = true; // Record that we saw it
4803             continue;
4804         }
4805
4806         // Look for a 32-byte address exposed Struct and record its varDsc
4807         if ((varDsc->TypeGet() == TYP_STRUCT) && varDsc->lvAddrExposed && (varDsc->lvExactSize == 32))
4808         {
4809             varDscExposedStruct = varDsc;
4810         }
4811     }
4812
4813     // We only perform the Quirk when there are two locals
4814     // one of them is a address exposed struct of size 32
4815     // and the other is the outgoing arg space local
4816     //
4817     if (hasOutArgs && (varDscExposedStruct != nullptr))
4818     {
4819 #ifdef DEBUG
4820         if (verbose)
4821         {
4822             printf("\nAdding a backwards compatibility quirk for the 'PPP' issue\n");
4823         }
4824 #endif // DEBUG
4825
4826         // Increase the exact size of this struct by 32 bytes
4827         // This fixes the PPP backward compat issue
4828         varDscExposedStruct->lvExactSize += 32;
4829
4830         return true;
4831     }
4832     return false;
4833 }
4834 #endif // _TARGET_AMD64_
4835
4836 /*****************************************************************************/
4837
4838 #ifdef DEBUG
4839 void* forceFrameJIT; // used to force to frame &useful for fastchecked debugging
4840
4841 bool Compiler::skipMethod()
4842 {
4843     static ConfigMethodRange fJitRange;
4844     fJitRange.EnsureInit(JitConfig.JitRange());
4845     assert(!fJitRange.Error());
4846
4847     // Normally JitConfig.JitRange() is null, we don't want to skip
4848     // jitting any methods.
4849     //
4850     // So, the logic below relies on the fact that a null range string
4851     // passed to ConfigMethodRange represents the set of all methods.
4852
4853     if (!fJitRange.Contains(info.compCompHnd, info.compMethodHnd))
4854     {
4855         return true;
4856     }
4857
4858     if (JitConfig.JitExclude().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
4859     {
4860         return true;
4861     }
4862
4863     if (!JitConfig.JitInclude().isEmpty() &&
4864         !JitConfig.JitInclude().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
4865     {
4866         return true;
4867     }
4868
4869     return false;
4870 }
4871
4872 #endif
4873
4874 /*****************************************************************************/
4875
4876 int Compiler::compCompile(CORINFO_METHOD_HANDLE methodHnd,
4877                           CORINFO_MODULE_HANDLE classPtr,
4878                           COMP_HANDLE           compHnd,
4879                           CORINFO_METHOD_INFO*  methodInfo,
4880                           void**                methodCodePtr,
4881                           ULONG*                methodCodeSize,
4882                           JitFlags*             compileFlags)
4883 {
4884 #ifdef FEATURE_JIT_METHOD_PERF
4885     static bool checkedForJitTimeLog = false;
4886
4887     pCompJitTimer = nullptr;
4888
4889     if (!checkedForJitTimeLog)
4890     {
4891         // Call into VM to get the config strings. FEATURE_JIT_METHOD_PERF is enabled for
4892         // retail builds. Do not call the regular Config helper here as it would pull
4893         // in a copy of the config parser into the clrjit.dll.
4894         InterlockedCompareExchangeT(&Compiler::compJitTimeLogFilename, compHnd->getJitTimeLogFilename(), NULL);
4895
4896         // At a process or module boundary clear the file and start afresh.
4897         JitTimer::PrintCsvHeader();
4898
4899         checkedForJitTimeLog = true;
4900     }
4901     if ((Compiler::compJitTimeLogFilename != nullptr) || (JitTimeLogCsv() != nullptr))
4902     {
4903         pCompJitTimer = JitTimer::Create(this, methodInfo->ILCodeSize);
4904     }
4905 #endif // FEATURE_JIT_METHOD_PERF
4906
4907 #ifdef DEBUG
4908     Compiler* me  = this;
4909     forceFrameJIT = (void*)&me; // let us see the this pointer in fastchecked build
4910     // set this early so we can use it without relying on random memory values
4911     verbose = compIsForInlining() ? impInlineInfo->InlinerCompiler->verbose : false;
4912
4913     this->dumpIR             = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIR : false;
4914     this->dumpIRPhase        = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRPhase : nullptr;
4915     this->dumpIRFormat       = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRFormat : nullptr;
4916     this->dumpIRTypes        = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRTypes : false;
4917     this->dumpIRLocals       = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRLocals : false;
4918     this->dumpIRRegs         = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRRegs : false;
4919     this->dumpIRSsa          = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRSsa : false;
4920     this->dumpIRValnums      = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRValnums : false;
4921     this->dumpIRCosts        = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRCosts : false;
4922     this->dumpIRFlags        = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRFlags : false;
4923     this->dumpIRKinds        = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRKinds : false;
4924     this->dumpIRNodes        = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRNodes : false;
4925     this->dumpIRNoLists      = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRNoLists : false;
4926     this->dumpIRNoLeafs      = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRNoLeafs : false;
4927     this->dumpIRNoStmts      = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRNoStmts : false;
4928     this->dumpIRTrees        = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRTrees : false;
4929     this->dumpIRLinear       = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRLinear : false;
4930     this->dumpIRDataflow     = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRDataflow : false;
4931     this->dumpIRBlockHeaders = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRBlockHeaders : NULL;
4932     this->dumpIRExit         = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRExit : NULL;
4933
4934 #endif
4935
4936 #if defined(DEBUG) || defined(INLINE_DATA)
4937     info.compMethodHashPrivate = 0;
4938 #endif // defined(DEBUG) || defined(INLINE_DATA)
4939
4940 #if FUNC_INFO_LOGGING
4941     LPCWSTR tmpJitFuncInfoFilename = JitConfig.JitFuncInfoFile();
4942
4943     if (tmpJitFuncInfoFilename != nullptr)
4944     {
4945         LPCWSTR oldFuncInfoFileName =
4946             InterlockedCompareExchangeT(&compJitFuncInfoFilename, tmpJitFuncInfoFilename, NULL);
4947         if (oldFuncInfoFileName == nullptr)
4948         {
4949             assert(compJitFuncInfoFile == nullptr);
4950             compJitFuncInfoFile = _wfopen(compJitFuncInfoFilename, W("a"));
4951             if (compJitFuncInfoFile == nullptr)
4952             {
4953 #if defined(DEBUG) && !defined(FEATURE_PAL) // no 'perror' in the PAL
4954                 perror("Failed to open JitFuncInfoLogFile");
4955 #endif // defined(DEBUG) && !defined(FEATURE_PAL)
4956             }
4957         }
4958     }
4959 #endif // FUNC_INFO_LOGGING
4960
4961     // if (s_compMethodsCount==0) setvbuf(jitstdout, NULL, _IONBF, 0);
4962
4963     info.compCompHnd    = compHnd;
4964     info.compMethodHnd  = methodHnd;
4965     info.compMethodInfo = methodInfo;
4966
4967     // Do we have a matched VM? Or are we "abusing" the VM to help us do JIT work (such as using an x86 native VM
4968     // with an ARM-targeting "altjit").
4969     info.compMatchedVM = IMAGE_FILE_MACHINE_TARGET == info.compCompHnd->getExpectedTargetArchitecture();
4970
4971 #if defined(ALT_JIT) && defined(UNIX_AMD64_ABI)
4972     // ToDo: This code is to allow us to run UNIX codegen on Windows for now. Remove when appropriate.
4973     // Make sure that the generated UNIX altjit code is skipped on Windows. The static jit codegen is used to run.
4974     info.compMatchedVM = false;
4975 #endif // UNIX_AMD64_ABI
4976
4977 #if COR_JIT_EE_VERSION > 460
4978     compMaxUncheckedOffsetForNullObject = eeGetEEInfo()->maxUncheckedOffsetForNullObject;
4979 #else  // COR_JIT_EE_VERSION <= 460
4980     compMaxUncheckedOffsetForNullObject = MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT;
4981 #endif // COR_JIT_EE_VERSION > 460
4982
4983     // Set the context for token lookup.
4984     if (compIsForInlining())
4985     {
4986         impTokenLookupContextHandle = impInlineInfo->tokenLookupContextHandle;
4987
4988         assert(impInlineInfo->inlineCandidateInfo->clsHandle == compHnd->getMethodClass(methodHnd));
4989         info.compClassHnd = impInlineInfo->inlineCandidateInfo->clsHandle;
4990
4991         assert(impInlineInfo->inlineCandidateInfo->clsAttr == info.compCompHnd->getClassAttribs(info.compClassHnd));
4992         // printf("%x != %x\n", impInlineInfo->inlineCandidateInfo->clsAttr,
4993         // info.compCompHnd->getClassAttribs(info.compClassHnd));
4994         info.compClassAttr = impInlineInfo->inlineCandidateInfo->clsAttr;
4995     }
4996     else
4997     {
4998         impTokenLookupContextHandle = MAKE_METHODCONTEXT(info.compMethodHnd);
4999
5000         info.compClassHnd  = compHnd->getMethodClass(methodHnd);
5001         info.compClassAttr = info.compCompHnd->getClassAttribs(info.compClassHnd);
5002     }
5003
5004     info.compProfilerCallback = false; // Assume false until we are told to hook this method.
5005
5006 #if defined(DEBUG) || defined(LATE_DISASM)
5007     const char* classNamePtr;
5008
5009     info.compMethodName = eeGetMethodName(methodHnd, &classNamePtr);
5010     unsigned len        = (unsigned)roundUp(strlen(classNamePtr) + 1);
5011     info.compClassName  = (char*)compGetMem(len, CMK_DebugOnly);
5012     strcpy_s((char*)info.compClassName, len, classNamePtr);
5013
5014     info.compFullName = eeGetMethodFullName(methodHnd);
5015 #endif // defined(DEBUG) || defined(LATE_DISASM)
5016
5017 #ifdef DEBUG
5018     if (!compIsForInlining())
5019     {
5020         JitTls::GetLogEnv()->setCompiler(this);
5021     }
5022
5023     // Have we been told to be more selective in our Jitting?
5024     if (skipMethod())
5025     {
5026         if (compIsForInlining())
5027         {
5028             compInlineResult->NoteFatal(InlineObservation::CALLEE_MARKED_AS_SKIPPED);
5029         }
5030         return CORJIT_SKIPPED;
5031     }
5032
5033     // Opt-in to jit stress based on method hash ranges.
5034     //
5035     // Note the default (with JitStressRange not set) is that all
5036     // methods will be subject to stress.
5037     static ConfigMethodRange fJitStressRange;
5038     fJitStressRange.EnsureInit(JitConfig.JitStressRange());
5039     assert(!fJitStressRange.Error());
5040     bRangeAllowStress = fJitStressRange.Contains(info.compCompHnd, info.compMethodHnd);
5041
5042 #endif // DEBUG
5043
5044     // Set this before the first 'BADCODE'
5045     // Skip verification where possible
5046     tiVerificationNeeded = !compileFlags->IsSet(JitFlags::JIT_FLAG_SKIP_VERIFICATION);
5047
5048     assert(!compIsForInlining() || !tiVerificationNeeded); // Inlinees must have been verified.
5049
5050     // assume the code is verifiable unless proven otherwise
5051     tiIsVerifiableCode = TRUE;
5052
5053     tiRuntimeCalloutNeeded = false;
5054
5055     CorInfoInstantiationVerification instVerInfo = INSTVER_GENERIC_PASSED_VERIFICATION;
5056
5057     if (!compIsForInlining() && tiVerificationNeeded)
5058     {
5059         instVerInfo = compHnd->isInstantiationOfVerifiedGeneric(methodHnd);
5060
5061         if (tiVerificationNeeded && (instVerInfo == INSTVER_GENERIC_FAILED_VERIFICATION))
5062         {
5063             CorInfoCanSkipVerificationResult canSkipVerificationResult =
5064                 info.compCompHnd->canSkipMethodVerification(info.compMethodHnd);
5065
5066             switch (canSkipVerificationResult)
5067             {
5068                 case CORINFO_VERIFICATION_CANNOT_SKIP:
5069                     // We cannot verify concrete instantiation.
5070                     // We can only verify the typical/open instantiation
5071                     // The VM should throw a VerificationException instead of allowing this.
5072                     NO_WAY("Verification of closed instantiations is not supported");
5073                     break;
5074
5075                 case CORINFO_VERIFICATION_CAN_SKIP:
5076                     // The VM should first verify the open instantiation. If unverifiable code
5077                     // is detected, it should pass in JitFlags::JIT_FLAG_SKIP_VERIFICATION.
5078                     assert(!"The VM should have used JitFlags::JIT_FLAG_SKIP_VERIFICATION");
5079                     tiVerificationNeeded = false;
5080                     break;
5081
5082                 case CORINFO_VERIFICATION_RUNTIME_CHECK:
5083                     // This is a concrete generic instantiation with unverifiable code, that also
5084                     // needs a runtime callout.
5085                     tiVerificationNeeded   = false;
5086                     tiRuntimeCalloutNeeded = true;
5087                     break;
5088
5089                 case CORINFO_VERIFICATION_DONT_JIT:
5090                     // We cannot verify concrete instantiation.
5091                     // We can only verify the typical/open instantiation
5092                     // The VM should throw a VerificationException instead of allowing this.
5093                     BADCODE("NGEN of unverifiable transparent code is not supported");
5094                     break;
5095             }
5096         }
5097
5098         // load any constraints for verification, noting any cycles to be rejected by the verifying importer
5099         if (tiVerificationNeeded)
5100         {
5101             compHnd->initConstraintsForVerification(methodHnd, &info.hasCircularClassConstraints,
5102                                                     &info.hasCircularMethodConstraints);
5103         }
5104     }
5105
5106     /* Setup an error trap */
5107
5108     struct Param
5109     {
5110         Compiler* pThis;
5111
5112         CORINFO_MODULE_HANDLE classPtr;
5113         COMP_HANDLE           compHnd;
5114         CORINFO_METHOD_INFO*  methodInfo;
5115         void**                methodCodePtr;
5116         ULONG*                methodCodeSize;
5117         JitFlags*             compileFlags;
5118
5119         CorInfoInstantiationVerification instVerInfo;
5120         int                              result;
5121     } param;
5122     param.pThis          = this;
5123     param.classPtr       = classPtr;
5124     param.compHnd        = compHnd;
5125     param.methodInfo     = methodInfo;
5126     param.methodCodePtr  = methodCodePtr;
5127     param.methodCodeSize = methodCodeSize;
5128     param.compileFlags   = compileFlags;
5129     param.instVerInfo    = instVerInfo;
5130     param.result         = CORJIT_INTERNALERROR;
5131
5132     setErrorTrap(compHnd, Param*, pParam, &param) // ERROR TRAP: Start normal block
5133     {
5134         pParam->result = pParam->pThis->compCompileHelper(pParam->classPtr, pParam->compHnd, pParam->methodInfo,
5135                                                           pParam->methodCodePtr, pParam->methodCodeSize,
5136                                                           pParam->compileFlags, pParam->instVerInfo);
5137     }
5138     finallyErrorTrap() // ERROR TRAP: The following block handles errors
5139     {
5140         /* Cleanup  */
5141
5142         if (compIsForInlining())
5143         {
5144             goto DoneCleanUp;
5145         }
5146
5147         /* Tell the emitter that we're done with this function */
5148
5149         genEmitter->emitEndCG();
5150
5151     DoneCleanUp:
5152         compDone();
5153     }
5154     endErrorTrap() // ERROR TRAP: End
5155
5156         return param.result;
5157 }
5158
5159 #if defined(DEBUG) || defined(INLINE_DATA)
5160 unsigned Compiler::Info::compMethodHash() const
5161 {
5162     if (compMethodHashPrivate == 0)
5163     {
5164         compMethodHashPrivate = compCompHnd->getMethodHash(compMethodHnd);
5165     }
5166     return compMethodHashPrivate;
5167 }
5168 #endif // defined(DEBUG) || defined(INLINE_DATA)
5169
5170 void Compiler::compCompileFinish()
5171 {
5172 #if defined(DEBUG) || MEASURE_NODE_SIZE || MEASURE_BLOCK_SIZE || DISPLAY_SIZES || CALL_ARG_STATS
5173     genMethodCnt++;
5174 #endif
5175
5176 #if MEASURE_MEM_ALLOC
5177     {
5178         // Grab the relevant lock.
5179         CritSecHolder statsLock(s_memStatsLock);
5180
5181         // Make the updates.
5182         genMemStats.nraTotalSizeAlloc = compGetAllocator()->getTotalBytesAllocated();
5183         genMemStats.nraTotalSizeUsed  = compGetAllocator()->getTotalBytesUsed();
5184         memAllocHist.record((unsigned)((genMemStats.nraTotalSizeAlloc + 1023) / 1024));
5185         memUsedHist.record((unsigned)((genMemStats.nraTotalSizeUsed + 1023) / 1024));
5186         s_aggMemStats.Add(genMemStats);
5187         if (genMemStats.allocSz > s_maxCompMemStats.allocSz)
5188         {
5189             s_maxCompMemStats = genMemStats;
5190         }
5191     }
5192
5193 #ifdef DEBUG
5194     if (s_dspMemStats || verbose)
5195     {
5196         printf("\nAllocations for %s (MethodHash=%08x)\n", info.compFullName, info.compMethodHash());
5197         genMemStats.Print(jitstdout);
5198     }
5199 #endif // DEBUG
5200 #endif // MEASURE_MEM_ALLOC
5201
5202 #if LOOP_HOIST_STATS
5203     AddLoopHoistStats();
5204 #endif // LOOP_HOIST_STATS
5205
5206 #if MEASURE_NODE_SIZE
5207     genTreeNcntHist.record(static_cast<unsigned>(genNodeSizeStatsPerFunc.genTreeNodeCnt));
5208     genTreeNsizHist.record(static_cast<unsigned>(genNodeSizeStatsPerFunc.genTreeNodeSize));
5209 #endif
5210
5211 #if defined(DEBUG)
5212     // Small methods should fit in ArenaAllocator::getDefaultPageSize(), or else
5213     // we should bump up ArenaAllocator::getDefaultPageSize()
5214
5215     if ((info.compILCodeSize <= 32) &&     // Is it a reasonably small method?
5216         (info.compNativeCodeSize < 512) && // Some trivial methods generate huge native code. eg. pushing a single huge
5217                                            // struct
5218         (impInlinedCodeSize <= 128) &&     // Is the the inlining reasonably bounded?
5219                                            // Small methods cannot meaningfully have a big number of locals
5220                                            // or arguments. We always track arguments at the start of
5221                                            // the prolog which requires memory
5222         (info.compLocalsCount <= 32) && (!opts.MinOpts()) && // We may have too many local variables, etc
5223         (getJitStressLevel() == 0) &&                        // We need extra memory for stress
5224         !opts.optRepeat &&                                   // We need extra memory to repeat opts
5225         !compAllocator->bypassHostAllocator() && // ArenaAllocator::getDefaultPageSize() is artificially low for
5226                                                  // DirectAlloc
5227         (compAllocator->getTotalBytesAllocated() > (2 * ArenaAllocator::getDefaultPageSize())) &&
5228 // Factor of 2x is because data-structures are bigger under DEBUG
5229 #ifndef LEGACY_BACKEND
5230         // RyuJIT backend needs memory tuning! TODO-Cleanup: remove this case when memory tuning is complete.
5231         (compAllocator->getTotalBytesAllocated() > (10 * ArenaAllocator::getDefaultPageSize())) &&
5232 #endif
5233         !verbose) // We allocate lots of memory to convert sets to strings for JitDump
5234     {
5235         genSmallMethodsNeedingExtraMemoryCnt++;
5236
5237         // Less than 1% of all methods should run into this.
5238         // We cannot be more strict as there are always degenerate cases where we
5239         // would need extra memory (like huge structs as locals - see lvaSetStruct()).
5240         assert((genMethodCnt < 500) || (genSmallMethodsNeedingExtraMemoryCnt < (genMethodCnt / 100)));
5241     }
5242 #endif // DEBUG
5243
5244 #if defined(DEBUG) || defined(INLINE_DATA)
5245
5246     m_inlineStrategy->DumpData();
5247     m_inlineStrategy->DumpXml();
5248
5249 #endif
5250
5251 #ifdef DEBUG
5252     if (opts.dspOrder)
5253     {
5254         // mdMethodDef __stdcall CEEInfo::getMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod)
5255         mdMethodDef currentMethodToken = info.compCompHnd->getMethodDefFromMethod(info.compMethodHnd);
5256
5257         unsigned profCallCount = 0;
5258         if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT) && fgHaveProfileData())
5259         {
5260             assert(fgProfileBuffer[0].ILOffset == 0);
5261             profCallCount = fgProfileBuffer[0].ExecutionCount;
5262         }
5263
5264         static bool headerPrinted = false;
5265         if (!headerPrinted)
5266         {
5267             // clang-format off
5268             headerPrinted = true;
5269             printf("         |  Profiled  | Exec-    |   Method has    |   calls   | Num |LclV |AProp| CSE |   Reg   |bytes | %3s code size | \n", Target::g_tgtCPUName);
5270             printf(" mdToken |     |  RGN |    Count | EH | FRM | LOOP | NRM | IND | BBs | Cnt | Cnt | Cnt |  Alloc  |  IL  |   HOT |  COLD | method name \n");
5271             printf("---------+-----+------+----------+----+-----+------+-----+-----+-----+-----+-----+-----+---------+------+-------+-------+-----------\n");
5272             //      06001234 | PRF |  HOT |      219 | EH | ebp | LOOP |  15 |   6 |  12 |  17 |  12 |   8 |   28 p2 |  145 |   211 |   123 | System.Example(int)
5273             // clang-format on
5274         }
5275
5276         printf("%08X | ", currentMethodToken);
5277
5278         CorInfoRegionKind regionKind = info.compMethodInfo->regionKind;
5279
5280         if (opts.altJit)
5281         {
5282             printf("ALT | ");
5283         }
5284         else if (fgHaveProfileData())
5285         {
5286             printf("PRF | ");
5287         }
5288         else
5289         {
5290             printf("    | ");
5291         }
5292
5293         if (regionKind == CORINFO_REGION_NONE)
5294         {
5295             printf("     | ");
5296         }
5297         else if (regionKind == CORINFO_REGION_HOT)
5298         {
5299             printf(" HOT | ");
5300         }
5301         else if (regionKind == CORINFO_REGION_COLD)
5302         {
5303             printf("COLD | ");
5304         }
5305         else if (regionKind == CORINFO_REGION_JIT)
5306         {
5307             printf(" JIT | ");
5308         }
5309         else
5310         {
5311             printf("UNKN | ");
5312         }
5313
5314         printf("%8d | ", profCallCount);
5315
5316         if (compHndBBtabCount > 0)
5317         {
5318             printf("EH | ");
5319         }
5320         else
5321         {
5322             printf("   | ");
5323         }
5324
5325         if (rpFrameType == FT_EBP_FRAME)
5326         {
5327             printf("%3s | ", STR_FPBASE);
5328         }
5329         else if (rpFrameType == FT_ESP_FRAME)
5330         {
5331             printf("%3s | ", STR_SPBASE);
5332         }
5333 #if DOUBLE_ALIGN
5334         else if (rpFrameType == FT_DOUBLE_ALIGN_FRAME)
5335         {
5336             printf("dbl | ");
5337         }
5338 #endif
5339         else // (rpFrameType == FT_NOT_SET)
5340         {
5341             printf("??? | ");
5342         }
5343
5344         if (fgHasLoops)
5345         {
5346             printf("LOOP |");
5347         }
5348         else
5349         {
5350             printf("     |");
5351         }
5352
5353         printf(" %3d |", optCallCount);
5354         printf(" %3d |", optIndirectCallCount);
5355         printf(" %3d |", fgBBcountAtCodegen);
5356         printf(" %3d |", lvaCount);
5357
5358         if (opts.MinOpts())
5359         {
5360             printf("  MinOpts  |");
5361         }
5362         else
5363         {
5364             printf(" %3d |", optAssertionCount);
5365 #if FEATURE_ANYCSE
5366             printf(" %3d |", optCSEcount);
5367 #else
5368             printf(" %3d |", 0);
5369 #endif // FEATURE_ANYCSE
5370         }
5371
5372 #ifndef LEGACY_BACKEND
5373         printf(" LSRA    |"); // TODO-Cleanup: dump some interesting LSRA stat into the order file?
5374 #else // LEGACY_BACKEND
5375         printf("%s%4d p%1d |", (tmpCount > 0) ? "T" : " ", rpStkPredict / BB_UNITY_WEIGHT, rpPasses);
5376 #endif // LEGACY_BACKEND
5377         printf(" %4d |", info.compMethodInfo->ILCodeSize);
5378         printf(" %5d |", info.compTotalHotCodeSize);
5379         printf(" %5d |", info.compTotalColdCodeSize);
5380
5381         printf(" %s\n", eeGetMethodFullName(info.compMethodHnd));
5382         printf(""); // in our logic this causes a flush
5383     }
5384
5385     if (verbose)
5386     {
5387         printf("****** DONE compiling %s\n", info.compFullName);
5388         printf(""); // in our logic this causes a flush
5389     }
5390
5391     // Only call _DbgBreakCheck when we are jitting, not when we are ngen-ing
5392     // For ngen the int3 or breakpoint instruction will be right at the
5393     // start of the ngen method and we will stop when we execute it.
5394     //
5395     if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
5396     {
5397         if (compJitHaltMethod())
5398         {
5399 #if !defined(_TARGET_ARM64_) && !defined(PLATFORM_UNIX)
5400             // TODO-ARM64-NYI: re-enable this when we have an OS that supports a pop-up dialog
5401
5402             // Don't do an assert, but just put up the dialog box so we get just-in-time debugger
5403             // launching.  When you hit 'retry' it will continue and naturally stop at the INT 3
5404             // that the JIT put in the code
5405             _DbgBreakCheck(__FILE__, __LINE__, "JitHalt");
5406 #endif
5407         }
5408     }
5409 #endif // DEBUG
5410 }
5411
5412 #ifdef PSEUDORANDOM_NOP_INSERTION
5413 // this is zlib adler32 checksum.  source came from windows base
5414
5415 #define BASE 65521L // largest prime smaller than 65536
5416 #define NMAX 5552
5417 // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
5418
5419 #define DO1(buf, i)                                                                                                    \
5420     {                                                                                                                  \
5421         s1 += buf[i];                                                                                                  \
5422         s2 += s1;                                                                                                      \
5423     }
5424 #define DO2(buf, i)                                                                                                    \
5425     DO1(buf, i);                                                                                                       \
5426     DO1(buf, i + 1);
5427 #define DO4(buf, i)                                                                                                    \
5428     DO2(buf, i);                                                                                                       \
5429     DO2(buf, i + 2);
5430 #define DO8(buf, i)                                                                                                    \
5431     DO4(buf, i);                                                                                                       \
5432     DO4(buf, i + 4);
5433 #define DO16(buf)                                                                                                      \
5434     DO8(buf, 0);                                                                                                       \
5435     DO8(buf, 8);
5436
5437 unsigned adler32(unsigned adler, char* buf, unsigned int len)
5438 {
5439     unsigned int s1 = adler & 0xffff;
5440     unsigned int s2 = (adler >> 16) & 0xffff;
5441     int          k;
5442
5443     if (buf == NULL)
5444         return 1L;
5445
5446     while (len > 0)
5447     {
5448         k = len < NMAX ? len : NMAX;
5449         len -= k;
5450         while (k >= 16)
5451         {
5452             DO16(buf);
5453             buf += 16;
5454             k -= 16;
5455         }
5456         if (k != 0)
5457             do
5458             {
5459                 s1 += *buf++;
5460                 s2 += s1;
5461             } while (--k);
5462         s1 %= BASE;
5463         s2 %= BASE;
5464     }
5465     return (s2 << 16) | s1;
5466 }
5467 #endif
5468
5469 unsigned getMethodBodyChecksum(__in_z char* code, int size)
5470 {
5471 #ifdef PSEUDORANDOM_NOP_INSERTION
5472     return adler32(0, code, size);
5473 #else
5474     return 0;
5475 #endif
5476 }
5477
5478 int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE            classPtr,
5479                                 COMP_HANDLE                      compHnd,
5480                                 CORINFO_METHOD_INFO*             methodInfo,
5481                                 void**                           methodCodePtr,
5482                                 ULONG*                           methodCodeSize,
5483                                 JitFlags*                        compileFlags,
5484                                 CorInfoInstantiationVerification instVerInfo)
5485 {
5486     CORINFO_METHOD_HANDLE methodHnd = info.compMethodHnd;
5487
5488     info.compCode       = methodInfo->ILCode;
5489     info.compILCodeSize = methodInfo->ILCodeSize;
5490
5491     if (info.compILCodeSize == 0)
5492     {
5493         BADCODE("code size is zero");
5494     }
5495
5496     if (compIsForInlining())
5497     {
5498 #ifdef DEBUG
5499         unsigned methAttr_Old  = impInlineInfo->inlineCandidateInfo->methAttr;
5500         unsigned methAttr_New  = info.compCompHnd->getMethodAttribs(info.compMethodHnd);
5501         unsigned flagsToIgnore = CORINFO_FLG_DONT_INLINE | CORINFO_FLG_FORCEINLINE;
5502         assert((methAttr_Old & (~flagsToIgnore)) == (methAttr_New & (~flagsToIgnore)));
5503 #endif
5504
5505         info.compFlags = impInlineInfo->inlineCandidateInfo->methAttr;
5506     }
5507     else
5508     {
5509         info.compFlags = info.compCompHnd->getMethodAttribs(info.compMethodHnd);
5510 #ifdef PSEUDORANDOM_NOP_INSERTION
5511         info.compChecksum = getMethodBodyChecksum((char*)methodInfo->ILCode, methodInfo->ILCodeSize);
5512 #endif
5513     }
5514
5515     // compInitOptions will set the correct verbose flag.
5516
5517     compInitOptions(compileFlags);
5518
5519 #ifdef ALT_JIT
5520     if (!compIsForInlining() && !opts.altJit)
5521     {
5522         // We're an altjit, but the COMPlus_AltJit configuration did not say to compile this method,
5523         // so skip it.
5524         return CORJIT_SKIPPED;
5525     }
5526 #endif // ALT_JIT
5527
5528 #ifdef DEBUG
5529
5530     if (verbose)
5531     {
5532         printf("IL to import:\n");
5533         dumpILRange(info.compCode, info.compILCodeSize);
5534     }
5535
5536 #endif
5537
5538     // Check for COMPlus_AgressiveInlining
5539     if (JitConfig.JitAggressiveInlining())
5540     {
5541         compDoAggressiveInlining = true;
5542     }
5543
5544     if (compDoAggressiveInlining)
5545     {
5546         info.compFlags |= CORINFO_FLG_FORCEINLINE;
5547     }
5548
5549 #ifdef DEBUG
5550
5551     // Check for ForceInline stress.
5552     if (compStressCompile(STRESS_FORCE_INLINE, 0))
5553     {
5554         info.compFlags |= CORINFO_FLG_FORCEINLINE;
5555     }
5556
5557     if (compIsForInlining())
5558     {
5559         JITLOG((LL_INFO100000, "\nINLINER impTokenLookupContextHandle for %s is 0x%p.\n",
5560                 eeGetMethodFullName(info.compMethodHnd), dspPtr(impTokenLookupContextHandle)));
5561     }
5562
5563     // Force verification if asked to do so
5564     if (JitConfig.JitForceVer())
5565     {
5566         tiVerificationNeeded = (instVerInfo == INSTVER_NOT_INSTANTIATION);
5567     }
5568
5569     if (tiVerificationNeeded)
5570     {
5571         JITLOG((LL_INFO10000, "tiVerificationNeeded initially set to true for %s\n", info.compFullName));
5572     }
5573 #endif // DEBUG
5574
5575     /* Since tiVerificationNeeded can be turned off in the middle of
5576        compiling a method, and it might have caused blocks to be queued up
5577        for reimporting, impCanReimport can be used to check for reimporting. */
5578
5579     impCanReimport = (tiVerificationNeeded || compStressCompile(STRESS_CHK_REIMPORT, 15));
5580
5581     // Need security prolog/epilog callouts when there is a declarative security in the method.
5582     tiSecurityCalloutNeeded = ((info.compFlags & CORINFO_FLG_NOSECURITYWRAP) == 0);
5583
5584     if (tiSecurityCalloutNeeded || (info.compFlags & CORINFO_FLG_SECURITYCHECK))
5585     {
5586         // We need to allocate the security object on the stack
5587         // when the method being compiled has a declarative security
5588         // (i.e. when CORINFO_FLG_NOSECURITYWRAP is reset for the current method).
5589         // This is also the case when we inject a prolog and epilog in the method.
5590         opts.compNeedSecurityCheck = true;
5591     }
5592
5593     /* Initialize set a bunch of global values */
5594
5595     info.compScopeHnd      = classPtr;
5596     info.compXcptnsCount   = methodInfo->EHcount;
5597     info.compMaxStack      = methodInfo->maxStack;
5598     compHndBBtab           = nullptr;
5599     compHndBBtabCount      = 0;
5600     compHndBBtabAllocCount = 0;
5601
5602     info.compNativeCodeSize    = 0;
5603     info.compTotalHotCodeSize  = 0;
5604     info.compTotalColdCodeSize = 0;
5605
5606 #ifdef DEBUG
5607     compCurBB = nullptr;
5608     lvaTable  = nullptr;
5609
5610     // Reset node ID counter
5611     compGenTreeID = 0;
5612 #endif
5613
5614     /* Initialize emitter */
5615
5616     if (!compIsForInlining())
5617     {
5618         codeGen->getEmitter()->emitBegCG(this, compHnd);
5619     }
5620
5621     info.compIsStatic = (info.compFlags & CORINFO_FLG_STATIC) != 0;
5622
5623     info.compIsContextful = (info.compClassAttr & CORINFO_FLG_CONTEXTFUL) != 0;
5624
5625     info.compPublishStubParam = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM);
5626
5627     switch (methodInfo->args.getCallConv())
5628     {
5629         case CORINFO_CALLCONV_VARARG:
5630         case CORINFO_CALLCONV_NATIVEVARARG:
5631             info.compIsVarArgs = true;
5632             break;
5633         case CORINFO_CALLCONV_DEFAULT:
5634             info.compIsVarArgs = false;
5635             break;
5636         default:
5637             BADCODE("bad calling convention");
5638     }
5639     info.compRetNativeType = info.compRetType = JITtype2varType(methodInfo->args.retType);
5640
5641     info.compCallUnmanaged   = 0;
5642     info.compLvFrameListRoot = BAD_VAR_NUM;
5643
5644 #if FEATURE_FIXED_OUT_ARGS
5645     lvaOutgoingArgSpaceSize = 0;
5646 #endif
5647
5648     lvaGenericsContextUsed = false;
5649
5650     info.compInitMem = ((methodInfo->options & CORINFO_OPT_INIT_LOCALS) != 0);
5651
5652     /* Allocate the local variable table */
5653
5654     lvaInitTypeRef();
5655
5656     if (!compIsForInlining())
5657     {
5658         compInitDebuggingInfo();
5659     }
5660
5661     const bool forceInline = !!(info.compFlags & CORINFO_FLG_FORCEINLINE);
5662
5663     if (!compIsForInlining() && opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
5664     {
5665         // We're prejitting the root method. We also will analyze it as
5666         // a potential inline candidate.
5667         InlineResult prejitResult(this, methodHnd, "prejit");
5668
5669         // Do the initial inline screen.
5670         impCanInlineIL(methodHnd, methodInfo, forceInline, &prejitResult);
5671
5672         // Temporarily install the prejitResult as the
5673         // compInlineResult so it's available to fgFindJumpTargets
5674         // and can accumulate more observations as the IL is
5675         // scanned.
5676         //
5677         // We don't pass prejitResult in as a parameter to avoid
5678         // potential aliasing confusion -- the other call to
5679         // fgFindBasicBlocks may have set up compInlineResult and
5680         // the code in fgFindJumpTargets references that data
5681         // member extensively.
5682         assert(compInlineResult == nullptr);
5683         assert(impInlineInfo == nullptr);
5684         compInlineResult = &prejitResult;
5685
5686         // Find the basic blocks. We must do this regardless of
5687         // inlineability, since we are prejitting this method.
5688         //
5689         // This will also update the status of this method as
5690         // an inline candidate.
5691         fgFindBasicBlocks();
5692
5693         // Undo the temporary setup.
5694         assert(compInlineResult == &prejitResult);
5695         compInlineResult = nullptr;
5696
5697         // If still a viable, discretionary inline, assess
5698         // profitability.
5699         if (prejitResult.IsDiscretionaryCandidate())
5700         {
5701             prejitResult.DetermineProfitability(methodInfo);
5702         }
5703
5704         // Handle the results of the inline analysis.
5705         if (prejitResult.IsFailure())
5706         {
5707             // This method is a bad inlinee according to our
5708             // analysis.  We will let the InlineResult destructor
5709             // mark it as noinline in the prejit image to save the
5710             // jit some work.
5711             //
5712             // This decision better not be context-dependent.
5713             assert(prejitResult.IsNever());
5714         }
5715         else
5716         {
5717             // This looks like a viable inline candidate.  Since
5718             // we're not actually inlining, don't report anything.
5719             prejitResult.SetReported();
5720         }
5721     }
5722     else
5723     {
5724         // We are jitting the root method, or inlining.
5725         fgFindBasicBlocks();
5726     }
5727
5728     // If we're inlining and the candidate is bad, bail out.
5729     if (compDonotInline())
5730     {
5731         goto _Next;
5732     }
5733
5734     compSetOptimizationLevel();
5735
5736 #if COUNT_BASIC_BLOCKS
5737     bbCntTable.record(fgBBcount);
5738
5739     if (fgBBcount == 1)
5740     {
5741         bbOneBBSizeTable.record(methodInfo->ILCodeSize);
5742     }
5743 #endif // COUNT_BASIC_BLOCKS
5744
5745 #ifdef DEBUG
5746     if (verbose)
5747     {
5748         printf("Basic block list for '%s'\n", info.compFullName);
5749         fgDispBasicBlocks();
5750     }
5751 #endif
5752
5753 #ifdef DEBUG
5754     /* Give the function a unique number */
5755
5756     if (opts.disAsm || opts.dspEmit || verbose)
5757     {
5758         s_compMethodsCount = ~info.compMethodHash() & 0xffff;
5759     }
5760     else
5761     {
5762         s_compMethodsCount++;
5763     }
5764 #endif
5765
5766     if (compIsForInlining())
5767     {
5768         compInlineResult->NoteInt(InlineObservation::CALLEE_NUMBER_OF_BASIC_BLOCKS, fgBBcount);
5769
5770         if (compInlineResult->IsFailure())
5771         {
5772             goto _Next;
5773         }
5774     }
5775
5776 #ifdef DEBUG
5777     if (JitConfig.DumpJittedMethods() == 1 && !compIsForInlining())
5778     {
5779         printf("Compiling %4d %s::%s, IL size = %u, hsh=0x%x\n", Compiler::jitTotalMethodCompiled, info.compClassName,
5780                info.compMethodName, info.compILCodeSize, info.compMethodHash());
5781     }
5782     if (compIsForInlining())
5783     {
5784         compGenTreeID = impInlineInfo->InlinerCompiler->compGenTreeID;
5785     }
5786 #endif
5787
5788     compCompile(methodCodePtr, methodCodeSize, compileFlags);
5789
5790 #ifdef DEBUG
5791     if (compIsForInlining())
5792     {
5793         impInlineInfo->InlinerCompiler->compGenTreeID = compGenTreeID;
5794     }
5795 #endif
5796
5797 _Next:
5798
5799     if (compDonotInline())
5800     {
5801         // Verify we have only one inline result in play.
5802         assert(impInlineInfo->inlineResult == compInlineResult);
5803     }
5804
5805     if (!compIsForInlining())
5806     {
5807         compCompileFinish();
5808
5809         // Did we just compile for a target architecture that the VM isn't expecting? If so, the VM
5810         // can't used the generated code (and we better be an AltJit!).
5811
5812         if (!info.compMatchedVM)
5813         {
5814             return CORJIT_SKIPPED;
5815         }
5816
5817 #ifdef ALT_JIT
5818 #ifdef DEBUG
5819         if (JitConfig.RunAltJitCode() == 0)
5820         {
5821             return CORJIT_SKIPPED;
5822         }
5823 #endif // DEBUG
5824 #endif // ALT_JIT
5825     }
5826
5827     /* Success! */
5828     return CORJIT_OK;
5829 }
5830
5831 //------------------------------------------------------------------------
5832 // compFindLocalVarLinear: Linear search for variable's scope containing offset.
5833 //
5834 // Arguments:
5835 //     varNum    The variable number to search for in the array of scopes.
5836 //     offs      The offset value which should occur within the life of the variable.
5837 //
5838 // Return Value:
5839 //     VarScopeDsc* of a matching variable that contains the offset within its life
5840 //     begin and life end or nullptr when there is no match found.
5841 //
5842 //  Description:
5843 //     Linear search for matching variables with their life begin and end containing
5844 //     the offset.
5845 //     or NULL if one couldn't be found.
5846 //
5847 //  Note:
5848 //     Usually called for scope count = 4. Could be called for values upto 8.
5849 //
5850 VarScopeDsc* Compiler::compFindLocalVarLinear(unsigned varNum, unsigned offs)
5851 {
5852     for (unsigned i = 0; i < info.compVarScopesCount; i++)
5853     {
5854         VarScopeDsc* dsc = &info.compVarScopes[i];
5855         if ((dsc->vsdVarNum == varNum) && (dsc->vsdLifeBeg <= offs) && (dsc->vsdLifeEnd > offs))
5856         {
5857             return dsc;
5858         }
5859     }
5860     return nullptr;
5861 }
5862
5863 //------------------------------------------------------------------------
5864 // compFindLocalVar: Search for variable's scope containing offset.
5865 //
5866 // Arguments:
5867 //    varNum    The variable number to search for in the array of scopes.
5868 //    offs      The offset value which should occur within the life of the variable.
5869 //
5870 // Return Value:
5871 //    VarScopeDsc* of a matching variable that contains the offset within its life
5872 //    begin and life end.
5873 //    or NULL if one couldn't be found.
5874 //
5875 //  Description:
5876 //     Linear search for matching variables with their life begin and end containing
5877 //     the offset only when the scope count is < MAX_LINEAR_FIND_LCL_SCOPELIST,
5878 //     else use the hashtable lookup.
5879 //
5880 VarScopeDsc* Compiler::compFindLocalVar(unsigned varNum, unsigned offs)
5881 {
5882     if (info.compVarScopesCount < MAX_LINEAR_FIND_LCL_SCOPELIST)
5883     {
5884         return compFindLocalVarLinear(varNum, offs);
5885     }
5886     else
5887     {
5888         VarScopeDsc* ret = compFindLocalVar(varNum, offs, offs);
5889         assert(ret == compFindLocalVarLinear(varNum, offs));
5890         return ret;
5891     }
5892 }
5893
5894 //------------------------------------------------------------------------
5895 // compFindLocalVar: Search for variable's scope containing offset.
5896 //
5897 // Arguments:
5898 //    varNum    The variable number to search for in the array of scopes.
5899 //    lifeBeg   The life begin of the variable's scope
5900 //    lifeEnd   The life end of the variable's scope
5901 //
5902 // Return Value:
5903 //    VarScopeDsc* of a matching variable that contains the offset within its life
5904 //    begin and life end, or NULL if one couldn't be found.
5905 //
5906 //  Description:
5907 //     Following are the steps used:
5908 //     1. Index into the hashtable using varNum.
5909 //     2. Iterate through the linked list at index varNum to find a matching
5910 //        var scope.
5911 //
5912 VarScopeDsc* Compiler::compFindLocalVar(unsigned varNum, unsigned lifeBeg, unsigned lifeEnd)
5913 {
5914     assert(compVarScopeMap != nullptr);
5915
5916     VarScopeMapInfo* info;
5917     if (compVarScopeMap->Lookup(varNum, &info))
5918     {
5919         VarScopeListNode* list = info->head;
5920         while (list != nullptr)
5921         {
5922             if ((list->data->vsdLifeBeg <= lifeBeg) && (list->data->vsdLifeEnd > lifeEnd))
5923             {
5924                 return list->data;
5925             }
5926             list = list->next;
5927         }
5928     }
5929     return nullptr;
5930 }
5931
5932 //-------------------------------------------------------------------------
5933 // compInitVarScopeMap: Create a scope map so it can be looked up by varNum
5934 //
5935 //  Description:
5936 //     Map.K => Map.V :: varNum => List(ScopeDsc)
5937 //
5938 //     Create a scope map that can be indexed by varNum and can be iterated
5939 //     on it's values to look for matching scope when given an offs or
5940 //     lifeBeg and lifeEnd.
5941 //
5942 //  Notes:
5943 //     1. Build the map only when we think linear search is slow, i.e.,
5944 //     MAX_LINEAR_FIND_LCL_SCOPELIST is large.
5945 //     2. Linked list preserves original array order.
5946 //
5947 void Compiler::compInitVarScopeMap()
5948 {
5949     if (info.compVarScopesCount < MAX_LINEAR_FIND_LCL_SCOPELIST)
5950     {
5951         return;
5952     }
5953
5954     assert(compVarScopeMap == nullptr);
5955
5956     compVarScopeMap = new (getAllocator()) VarNumToScopeDscMap(getAllocator());
5957
5958     // 599 prime to limit huge allocations; for ex: duplicated scopes on single var.
5959     compVarScopeMap->Reallocate(min(info.compVarScopesCount, 599));
5960
5961     for (unsigned i = 0; i < info.compVarScopesCount; ++i)
5962     {
5963         unsigned varNum = info.compVarScopes[i].vsdVarNum;
5964
5965         VarScopeListNode* node = VarScopeListNode::Create(&info.compVarScopes[i], getAllocator());
5966
5967         // Index by varNum and if the list exists append "node" to the "list".
5968         VarScopeMapInfo* info;
5969         if (compVarScopeMap->Lookup(varNum, &info))
5970         {
5971             info->tail->next = node;
5972             info->tail       = node;
5973         }
5974         // Create a new list.
5975         else
5976         {
5977             info = VarScopeMapInfo::Create(node, getAllocator());
5978             compVarScopeMap->Set(varNum, info);
5979         }
5980     }
5981 }
5982
5983 static int __cdecl genCmpLocalVarLifeBeg(const void* elem1, const void* elem2)
5984 {
5985     return (*((VarScopeDsc**)elem1))->vsdLifeBeg - (*((VarScopeDsc**)elem2))->vsdLifeBeg;
5986 }
5987
5988 static int __cdecl genCmpLocalVarLifeEnd(const void* elem1, const void* elem2)
5989 {
5990     return (*((VarScopeDsc**)elem1))->vsdLifeEnd - (*((VarScopeDsc**)elem2))->vsdLifeEnd;
5991 }
5992
5993 inline void Compiler::compInitScopeLists()
5994 {
5995     if (info.compVarScopesCount == 0)
5996     {
5997         compEnterScopeList = compExitScopeList = nullptr;
5998         return;
5999     }
6000
6001     // Populate the 'compEnterScopeList' and 'compExitScopeList' lists
6002
6003     compEnterScopeList = new (this, CMK_DebugInfo) VarScopeDsc*[info.compVarScopesCount];
6004     compExitScopeList  = new (this, CMK_DebugInfo) VarScopeDsc*[info.compVarScopesCount];
6005
6006     for (unsigned i = 0; i < info.compVarScopesCount; i++)
6007     {
6008         compEnterScopeList[i] = compExitScopeList[i] = &info.compVarScopes[i];
6009     }
6010
6011     qsort(compEnterScopeList, info.compVarScopesCount, sizeof(*compEnterScopeList), genCmpLocalVarLifeBeg);
6012     qsort(compExitScopeList, info.compVarScopesCount, sizeof(*compExitScopeList), genCmpLocalVarLifeEnd);
6013 }
6014
6015 void Compiler::compResetScopeLists()
6016 {
6017     if (info.compVarScopesCount == 0)
6018     {
6019         return;
6020     }
6021
6022     assert(compEnterScopeList && compExitScopeList);
6023
6024     compNextEnterScope = compNextExitScope = 0;
6025 }
6026
6027 VarScopeDsc* Compiler::compGetNextEnterScope(unsigned offs, bool scan)
6028 {
6029     assert(info.compVarScopesCount);
6030     assert(compEnterScopeList && compExitScopeList);
6031
6032     if (compNextEnterScope < info.compVarScopesCount)
6033     {
6034         assert(compEnterScopeList[compNextEnterScope]);
6035         unsigned nextEnterOff = compEnterScopeList[compNextEnterScope]->vsdLifeBeg;
6036         assert(scan || (offs <= nextEnterOff));
6037
6038         if (!scan)
6039         {
6040             if (offs == nextEnterOff)
6041             {
6042                 return compEnterScopeList[compNextEnterScope++];
6043             }
6044         }
6045         else
6046         {
6047             if (nextEnterOff <= offs)
6048             {
6049                 return compEnterScopeList[compNextEnterScope++];
6050             }
6051         }
6052     }
6053
6054     return nullptr;
6055 }
6056
6057 VarScopeDsc* Compiler::compGetNextExitScope(unsigned offs, bool scan)
6058 {
6059     assert(info.compVarScopesCount);
6060     assert(compEnterScopeList && compExitScopeList);
6061
6062     if (compNextExitScope < info.compVarScopesCount)
6063     {
6064         assert(compExitScopeList[compNextExitScope]);
6065         unsigned nextExitOffs = compExitScopeList[compNextExitScope]->vsdLifeEnd;
6066         assert(scan || (offs <= nextExitOffs));
6067
6068         if (!scan)
6069         {
6070             if (offs == nextExitOffs)
6071             {
6072                 return compExitScopeList[compNextExitScope++];
6073             }
6074         }
6075         else
6076         {
6077             if (nextExitOffs <= offs)
6078             {
6079                 return compExitScopeList[compNextExitScope++];
6080             }
6081         }
6082     }
6083
6084     return nullptr;
6085 }
6086
6087 // The function will call the callback functions for scopes with boundaries
6088 // at instrs from the current status of the scope lists to 'offset',
6089 // ordered by instrs.
6090
6091 void Compiler::compProcessScopesUntil(unsigned   offset,
6092                                       VARSET_TP* inScope,
6093                                       void (Compiler::*enterScopeFn)(VARSET_TP* inScope, VarScopeDsc*),
6094                                       void (Compiler::*exitScopeFn)(VARSET_TP* inScope, VarScopeDsc*))
6095 {
6096     assert(offset != BAD_IL_OFFSET);
6097     assert(inScope != nullptr);
6098
6099     bool         foundExit = false, foundEnter = true;
6100     VarScopeDsc* scope;
6101     VarScopeDsc* nextExitScope  = nullptr;
6102     VarScopeDsc* nextEnterScope = nullptr;
6103     unsigned     offs = offset, curEnterOffs = 0;
6104
6105     goto START_FINDING_SCOPES;
6106
6107     // We need to determine the scopes which are open for the current block.
6108     // This loop walks over the missing blocks between the current and the
6109     // previous block, keeping the enter and exit offsets in lockstep.
6110
6111     do
6112     {
6113         foundExit = foundEnter = false;
6114
6115         if (nextExitScope)
6116         {
6117             (this->*exitScopeFn)(inScope, nextExitScope);
6118             nextExitScope = nullptr;
6119             foundExit     = true;
6120         }
6121
6122         offs = nextEnterScope ? nextEnterScope->vsdLifeBeg : offset;
6123
6124         while ((scope = compGetNextExitScope(offs, true)) != nullptr)
6125         {
6126             foundExit = true;
6127
6128             if (!nextEnterScope || scope->vsdLifeEnd > nextEnterScope->vsdLifeBeg)
6129             {
6130                 // We overshot the last found Enter scope. Save the scope for later
6131                 // and find an entering scope
6132
6133                 nextExitScope = scope;
6134                 break;
6135             }
6136
6137             (this->*exitScopeFn)(inScope, scope);
6138         }
6139
6140         if (nextEnterScope)
6141         {
6142             (this->*enterScopeFn)(inScope, nextEnterScope);
6143             curEnterOffs   = nextEnterScope->vsdLifeBeg;
6144             nextEnterScope = nullptr;
6145             foundEnter     = true;
6146         }
6147
6148         offs = nextExitScope ? nextExitScope->vsdLifeEnd : offset;
6149
6150     START_FINDING_SCOPES:
6151
6152         while ((scope = compGetNextEnterScope(offs, true)) != nullptr)
6153         {
6154             foundEnter = true;
6155
6156             if ((nextExitScope && scope->vsdLifeBeg >= nextExitScope->vsdLifeEnd) || (scope->vsdLifeBeg > curEnterOffs))
6157             {
6158                 // We overshot the last found exit scope. Save the scope for later
6159                 // and find an exiting scope
6160
6161                 nextEnterScope = scope;
6162                 break;
6163             }
6164
6165             (this->*enterScopeFn)(inScope, scope);
6166
6167             if (!nextExitScope)
6168             {
6169                 curEnterOffs = scope->vsdLifeBeg;
6170             }
6171         }
6172     } while (foundExit || foundEnter);
6173 }
6174
6175 #if defined(DEBUG)
6176
6177 void Compiler::compDispScopeLists()
6178 {
6179     unsigned i;
6180
6181     printf("Local variable scopes = %d\n", info.compVarScopesCount);
6182
6183     if (info.compVarScopesCount)
6184     {
6185         printf("    \tVarNum \tLVNum \t      Name \tBeg \tEnd\n");
6186     }
6187
6188     printf("Sorted by enter scope:\n");
6189     for (i = 0; i < info.compVarScopesCount; i++)
6190     {
6191         VarScopeDsc* varScope = compEnterScopeList[i];
6192         assert(varScope);
6193         printf("%2d: \t%02Xh \t%02Xh \t%10s \t%03Xh   \t%03Xh", i, varScope->vsdVarNum, varScope->vsdLVnum,
6194                VarNameToStr(varScope->vsdName) == nullptr ? "UNKNOWN" : VarNameToStr(varScope->vsdName),
6195                varScope->vsdLifeBeg, varScope->vsdLifeEnd);
6196
6197         if (compNextEnterScope == i)
6198         {
6199             printf(" <-- next enter scope");
6200         }
6201
6202         printf("\n");
6203     }
6204
6205     printf("Sorted by exit scope:\n");
6206     for (i = 0; i < info.compVarScopesCount; i++)
6207     {
6208         VarScopeDsc* varScope = compExitScopeList[i];
6209         assert(varScope);
6210         printf("%2d: \t%02Xh \t%02Xh \t%10s \t%03Xh   \t%03Xh", i, varScope->vsdVarNum, varScope->vsdLVnum,
6211                VarNameToStr(varScope->vsdName) == nullptr ? "UNKNOWN" : VarNameToStr(varScope->vsdName),
6212                varScope->vsdLifeBeg, varScope->vsdLifeEnd);
6213
6214         if (compNextExitScope == i)
6215         {
6216             printf(" <-- next exit scope");
6217         }
6218
6219         printf("\n");
6220     }
6221 }
6222
6223 void Compiler::compDispLocalVars()
6224 {
6225     printf("info.compVarScopesCount = %d\n", info.compVarScopesCount);
6226
6227     if (info.compVarScopesCount > 0)
6228     {
6229         printf("    \tVarNum \tLVNum \t      Name \tBeg \tEnd\n");
6230     }
6231
6232     for (unsigned i = 0; i < info.compVarScopesCount; i++)
6233     {
6234         VarScopeDsc* varScope = &info.compVarScopes[i];
6235         printf("%2d: \t%02Xh \t%02Xh \t%10s \t%03Xh   \t%03Xh\n", i, varScope->vsdVarNum, varScope->vsdLVnum,
6236                VarNameToStr(varScope->vsdName) == nullptr ? "UNKNOWN" : VarNameToStr(varScope->vsdName),
6237                varScope->vsdLifeBeg, varScope->vsdLifeEnd);
6238     }
6239 }
6240
6241 #endif // DEBUG
6242
6243 /*****************************************************************************/
6244
6245 #if MEASURE_CLRAPI_CALLS
6246
6247 struct WrapICorJitInfo : public ICorJitInfo
6248 {
6249     //------------------------------------------------------------------------
6250     // WrapICorJitInfo::makeOne: allocate an instance of WrapICorJitInfo
6251     //
6252     // Arguments:
6253     //    alloc      - the allocator to get memory from for the instance
6254     //    compile    - the compiler instance
6255     //    compHndRef - the ICorJitInfo handle from the EE; the caller's
6256     //                 copy may be replaced with a "wrapper" instance
6257     //
6258     // Return Value:
6259     //    If the config flags indicate that ICorJitInfo should be wrapped,
6260     //    we return the "wrapper" instance; otherwise we return "nullptr".
6261
6262     static WrapICorJitInfo* makeOne(ArenaAllocator* alloc, Compiler* compiler, COMP_HANDLE& compHndRef /* INOUT */)
6263     {
6264         WrapICorJitInfo* wrap = nullptr;
6265
6266         if (JitConfig.JitEECallTimingInfo() != 0)
6267         {
6268             // It's too early to use the default allocator, so we do this
6269             // in two steps to be safe (the constructor doesn't need to do
6270             // anything except fill in the vtable pointer, so we let the
6271             // compiler do it).
6272             void* inst = alloc->allocateMemory(roundUp(sizeof(WrapICorJitInfo)));
6273             if (inst != nullptr)
6274             {
6275                 // If you get a build error here due to 'WrapICorJitInfo' being
6276                 // an abstract class, it's very likely that the wrapper bodies
6277                 // in ICorJitInfo_API_wrapper.hpp are no longer in sync with
6278                 // the EE interface; please be kind and update the header file.
6279                 wrap = new (inst, jitstd::placement_t()) WrapICorJitInfo();
6280
6281                 wrap->wrapComp = compiler;
6282
6283                 // Save the real handle and replace it with our wrapped version.
6284                 wrap->wrapHnd = compHndRef;
6285                 compHndRef    = wrap;
6286             }
6287         }
6288
6289         return wrap;
6290     }
6291
6292 private:
6293     Compiler*   wrapComp;
6294     COMP_HANDLE wrapHnd; // the "real thing"
6295
6296 public:
6297 #include "ICorJitInfo_API_wrapper.hpp"
6298 };
6299
6300 #endif // MEASURE_CLRAPI_CALLS
6301
6302 /*****************************************************************************/
6303
6304 // Compile a single method
6305
6306 int jitNativeCode(CORINFO_METHOD_HANDLE methodHnd,
6307                   CORINFO_MODULE_HANDLE classPtr,
6308                   COMP_HANDLE           compHnd,
6309                   CORINFO_METHOD_INFO*  methodInfo,
6310                   void**                methodCodePtr,
6311                   ULONG*                methodCodeSize,
6312                   JitFlags*             compileFlags,
6313                   void*                 inlineInfoPtr)
6314 {
6315     //
6316     // A non-NULL inlineInfo means we are compiling the inlinee method.
6317     //
6318     InlineInfo* inlineInfo = (InlineInfo*)inlineInfoPtr;
6319
6320     bool jitFallbackCompile = false;
6321 START:
6322     int result = CORJIT_INTERNALERROR;
6323
6324     ArenaAllocator* pAlloc = nullptr;
6325     ArenaAllocator  alloc;
6326
6327 #if MEASURE_CLRAPI_CALLS
6328     WrapICorJitInfo* wrapCLR = nullptr;
6329 #endif
6330
6331     if (inlineInfo)
6332     {
6333         // Use inliner's memory allocator when compiling the inlinee.
6334         pAlloc = inlineInfo->InlinerCompiler->compGetAllocator();
6335     }
6336     else
6337     {
6338         IEEMemoryManager* pMemoryManager = compHnd->getMemoryManager();
6339
6340         // Try to reuse the pre-inited allocator
6341         pAlloc = ArenaAllocator::getPooledAllocator(pMemoryManager);
6342
6343         if (pAlloc == nullptr)
6344         {
6345             alloc  = ArenaAllocator(pMemoryManager);
6346             pAlloc = &alloc;
6347         }
6348     }
6349
6350     Compiler* pComp;
6351     pComp = nullptr;
6352
6353     struct Param
6354     {
6355         Compiler*       pComp;
6356         ArenaAllocator* pAlloc;
6357         ArenaAllocator* alloc;
6358         bool            jitFallbackCompile;
6359
6360         CORINFO_METHOD_HANDLE methodHnd;
6361         CORINFO_MODULE_HANDLE classPtr;
6362         COMP_HANDLE           compHnd;
6363         CORINFO_METHOD_INFO*  methodInfo;
6364         void**                methodCodePtr;
6365         ULONG*                methodCodeSize;
6366         JitFlags*             compileFlags;
6367         InlineInfo*           inlineInfo;
6368 #if MEASURE_CLRAPI_CALLS
6369         WrapICorJitInfo* wrapCLR;
6370 #endif
6371
6372         int result;
6373     } param;
6374     param.pComp              = nullptr;
6375     param.pAlloc             = pAlloc;
6376     param.alloc              = &alloc;
6377     param.jitFallbackCompile = jitFallbackCompile;
6378     param.methodHnd          = methodHnd;
6379     param.classPtr           = classPtr;
6380     param.compHnd            = compHnd;
6381     param.methodInfo         = methodInfo;
6382     param.methodCodePtr      = methodCodePtr;
6383     param.methodCodeSize     = methodCodeSize;
6384     param.compileFlags       = compileFlags;
6385     param.inlineInfo         = inlineInfo;
6386 #if MEASURE_CLRAPI_CALLS
6387     param.wrapCLR = nullptr;
6388 #endif
6389     param.result = result;
6390
6391     setErrorTrap(compHnd, Param*, pParamOuter, &param)
6392     {
6393         setErrorTrap(nullptr, Param*, pParam, pParamOuter)
6394         {
6395             if (pParam->inlineInfo)
6396             {
6397                 // Lazily create the inlinee compiler object
6398                 if (pParam->inlineInfo->InlinerCompiler->InlineeCompiler == nullptr)
6399                 {
6400                     pParam->inlineInfo->InlinerCompiler->InlineeCompiler =
6401                         (Compiler*)pParam->pAlloc->allocateMemory(roundUp(sizeof(*pParam->pComp)));
6402                 }
6403
6404                 // Use the inlinee compiler object
6405                 pParam->pComp = pParam->inlineInfo->InlinerCompiler->InlineeCompiler;
6406 #ifdef DEBUG
6407 // memset(pParam->pComp, 0xEE, sizeof(Compiler));
6408 #endif
6409             }
6410             else
6411             {
6412                 // Allocate create the inliner compiler object
6413                 pParam->pComp = (Compiler*)pParam->pAlloc->allocateMemory(roundUp(sizeof(*pParam->pComp)));
6414             }
6415
6416 #if MEASURE_CLRAPI_CALLS
6417             pParam->wrapCLR = WrapICorJitInfo::makeOne(pParam->pAlloc, pParam->pComp, pParam->compHnd);
6418 #endif
6419
6420             // push this compiler on the stack (TLS)
6421             pParam->pComp->prevCompiler = JitTls::GetCompiler();
6422             JitTls::SetCompiler(pParam->pComp);
6423
6424 // PREFIX_ASSUME gets turned into ASSERT_CHECK and we cannot have it here
6425 #if defined(_PREFAST_) || defined(_PREFIX_)
6426             PREFIX_ASSUME(pParam->pComp != NULL);
6427 #else
6428             assert(pParam->pComp != nullptr);
6429 #endif
6430
6431             pParam->pComp->compInit(pParam->pAlloc, pParam->inlineInfo);
6432
6433 #ifdef DEBUG
6434             pParam->pComp->jitFallbackCompile = pParam->jitFallbackCompile;
6435 #endif
6436
6437             // Now generate the code
6438             pParam->result =
6439                 pParam->pComp->compCompile(pParam->methodHnd, pParam->classPtr, pParam->compHnd, pParam->methodInfo,
6440                                            pParam->methodCodePtr, pParam->methodCodeSize, pParam->compileFlags);
6441         }
6442         finallyErrorTrap()
6443         {
6444             // Add a dummy touch to pComp so that it is kept alive, and is easy to get to
6445             // during debugging since all other data can be obtained through it.
6446             //
6447             if (pParamOuter->pComp) // If OOM is thrown when allocating memory for pComp, we will end up here.
6448                                     // In that case, pComp is still NULL.
6449             {
6450                 pParamOuter->pComp->info.compCode = nullptr;
6451
6452                 // pop the compiler off the TLS stack only if it was linked above
6453                 assert(JitTls::GetCompiler() == pParamOuter->pComp);
6454                 JitTls::SetCompiler(JitTls::GetCompiler()->prevCompiler);
6455             }
6456
6457             if (pParamOuter->inlineInfo == nullptr)
6458             {
6459                 // Free up the allocator we were using
6460                 pParamOuter->pAlloc->destroy();
6461             }
6462         }
6463         endErrorTrap()
6464     }
6465     impJitErrorTrap()
6466     {
6467         // If we were looking at an inlinee....
6468         if (inlineInfo != nullptr)
6469         {
6470             // Note that we failed to compile the inlinee, and that
6471             // there's no point trying to inline it again anywhere else.
6472             inlineInfo->inlineResult->NoteFatal(InlineObservation::CALLEE_COMPILATION_ERROR);
6473         }
6474         param.result = __errc;
6475     }
6476     endErrorTrap()
6477
6478         result = param.result;
6479
6480     if (!inlineInfo && (result == CORJIT_INTERNALERROR || result == CORJIT_RECOVERABLEERROR) && !jitFallbackCompile)
6481     {
6482         // If we failed the JIT, reattempt with debuggable code.
6483         jitFallbackCompile = true;
6484
6485         // Update the flags for 'safer' code generation.
6486         compileFlags->Set(JitFlags::JIT_FLAG_MIN_OPT);
6487         compileFlags->Clear(JitFlags::JIT_FLAG_SIZE_OPT);
6488         compileFlags->Clear(JitFlags::JIT_FLAG_SPEED_OPT);
6489
6490         goto START;
6491     }
6492
6493     return result;
6494 }
6495
6496 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
6497
6498 // GetTypeFromClassificationAndSizes:
6499 //   Returns the type of the eightbyte accounting for the classification and size of the eightbyte.
6500 //
6501 // args:
6502 //   classType: classification type
6503 //   size: size of the eightbyte.
6504 //
6505 // static
6506 var_types Compiler::GetTypeFromClassificationAndSizes(SystemVClassificationType classType, int size)
6507 {
6508     var_types type = TYP_UNKNOWN;
6509     switch (classType)
6510     {
6511         case SystemVClassificationTypeInteger:
6512             if (size == 1)
6513             {
6514                 type = TYP_BYTE;
6515             }
6516             else if (size <= 2)
6517             {
6518                 type = TYP_SHORT;
6519             }
6520             else if (size <= 4)
6521             {
6522                 type = TYP_INT;
6523             }
6524             else if (size <= 8)
6525             {
6526                 type = TYP_LONG;
6527             }
6528             else
6529             {
6530                 assert(false && "GetTypeFromClassificationAndSizes Invalid Integer classification type.");
6531             }
6532             break;
6533         case SystemVClassificationTypeIntegerReference:
6534             type = TYP_REF;
6535             break;
6536         case SystemVClassificationTypeIntegerByRef:
6537             type = TYP_BYREF;
6538             break;
6539         case SystemVClassificationTypeSSE:
6540             if (size <= 4)
6541             {
6542                 type = TYP_FLOAT;
6543             }
6544             else if (size <= 8)
6545             {
6546                 type = TYP_DOUBLE;
6547             }
6548             else
6549             {
6550                 assert(false && "GetTypeFromClassificationAndSizes Invalid SSE classification type.");
6551             }
6552             break;
6553
6554         default:
6555             assert(false && "GetTypeFromClassificationAndSizes Invalid classification type.");
6556             break;
6557     }
6558
6559     return type;
6560 }
6561
6562 //-------------------------------------------------------------------
6563 // GetEightByteType: Returns the type of eightbyte slot of a struct
6564 //
6565 // Arguments:
6566 //   structDesc  -  struct classification description.
6567 //   slotNum     -  eightbyte slot number for the struct.
6568 //
6569 // Return Value:
6570 //    type of the eightbyte slot of the struct
6571 //
6572 // static
6573 var_types Compiler::GetEightByteType(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
6574                                      unsigned                                                   slotNum)
6575 {
6576     var_types eightByteType = TYP_UNDEF;
6577     unsigned  len           = structDesc.eightByteSizes[slotNum];
6578
6579     switch (structDesc.eightByteClassifications[slotNum])
6580     {
6581         case SystemVClassificationTypeInteger:
6582             // See typelist.h for jit type definition.
6583             // All the types of size < 4 bytes are of jit type TYP_INT.
6584             if (structDesc.eightByteSizes[slotNum] <= 4)
6585             {
6586                 eightByteType = TYP_INT;
6587             }
6588             else if (structDesc.eightByteSizes[slotNum] <= 8)
6589             {
6590                 eightByteType = TYP_LONG;
6591             }
6592             else
6593             {
6594                 assert(false && "GetEightByteType Invalid Integer classification type.");
6595             }
6596             break;
6597         case SystemVClassificationTypeIntegerReference:
6598             assert(len == REGSIZE_BYTES);
6599             eightByteType = TYP_REF;
6600             break;
6601         case SystemVClassificationTypeIntegerByRef:
6602             assert(len == REGSIZE_BYTES);
6603             eightByteType = TYP_BYREF;
6604             break;
6605         case SystemVClassificationTypeSSE:
6606             if (structDesc.eightByteSizes[slotNum] <= 4)
6607             {
6608                 eightByteType = TYP_FLOAT;
6609             }
6610             else if (structDesc.eightByteSizes[slotNum] <= 8)
6611             {
6612                 eightByteType = TYP_DOUBLE;
6613             }
6614             else
6615             {
6616                 assert(false && "GetEightByteType Invalid SSE classification type.");
6617             }
6618             break;
6619         default:
6620             assert(false && "GetEightByteType Invalid classification type.");
6621             break;
6622     }
6623
6624     return eightByteType;
6625 }
6626
6627 //------------------------------------------------------------------------------------------------------
6628 // GetStructTypeOffset: Gets the type, size and offset of the eightbytes of a struct for System V systems.
6629 //
6630 // Arguments:
6631 //    'structDesc' -  struct description
6632 //    'type0'      -  out param; returns the type of the first eightbyte.
6633 //    'type1'      -  out param; returns the type of the second eightbyte.
6634 //    'offset0'    -  out param; returns the offset of the first eightbyte.
6635 //    'offset1'    -  out param; returns the offset of the second eightbyte.
6636 //
6637 // static
6638 void Compiler::GetStructTypeOffset(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
6639                                    var_types*                                                 type0,
6640                                    var_types*                                                 type1,
6641                                    unsigned __int8*                                           offset0,
6642                                    unsigned __int8*                                           offset1)
6643 {
6644     *offset0 = structDesc.eightByteOffsets[0];
6645     *offset1 = structDesc.eightByteOffsets[1];
6646
6647     *type0 = TYP_UNKNOWN;
6648     *type1 = TYP_UNKNOWN;
6649
6650     // Set the first eightbyte data
6651     if (structDesc.eightByteCount >= 1)
6652     {
6653         *type0 = GetEightByteType(structDesc, 0);
6654     }
6655
6656     // Set the second eight byte data
6657     if (structDesc.eightByteCount == 2)
6658     {
6659         *type1 = GetEightByteType(structDesc, 1);
6660     }
6661 }
6662 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
6663
6664 /*****************************************************************************/
6665 /*****************************************************************************/
6666
6667 #ifdef DEBUG
6668 Compiler::NodeToIntMap* Compiler::FindReachableNodesInNodeTestData()
6669 {
6670     NodeToIntMap* reachable = new (getAllocatorDebugOnly()) NodeToIntMap(getAllocatorDebugOnly());
6671
6672     if (m_nodeTestData == nullptr)
6673     {
6674         return reachable;
6675     }
6676
6677     // Otherwise, iterate.
6678
6679     for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
6680     {
6681         for (GenTreePtr stmt = block->FirstNonPhiDef(); stmt != nullptr; stmt = stmt->gtNext)
6682         {
6683             for (GenTreePtr tree = stmt->gtStmt.gtStmtList; tree; tree = tree->gtNext)
6684             {
6685                 TestLabelAndNum tlAndN;
6686
6687                 // For call nodes, translate late args to what they stand for.
6688                 if (tree->OperGet() == GT_CALL)
6689                 {
6690                     GenTreeCall*    call = tree->AsCall();
6691                     GenTreeArgList* args = call->gtCallArgs;
6692                     unsigned        i    = 0;
6693                     while (args != nullptr)
6694                     {
6695                         GenTreePtr arg = args->Current();
6696                         if (arg->gtFlags & GTF_LATE_ARG)
6697                         {
6698                             // Find the corresponding late arg.
6699                             GenTreePtr lateArg = nullptr;
6700                             for (unsigned j = 0; j < call->fgArgInfo->ArgCount(); j++)
6701                             {
6702                                 if (call->fgArgInfo->ArgTable()[j]->argNum == i)
6703                                 {
6704                                     lateArg = call->fgArgInfo->ArgTable()[j]->node;
6705                                     break;
6706                                 }
6707                             }
6708                             assert(lateArg != nullptr);
6709                             if (GetNodeTestData()->Lookup(lateArg, &tlAndN))
6710                             {
6711                                 reachable->Set(lateArg, 0);
6712                             }
6713                         }
6714                         i++;
6715                         args = args->Rest();
6716                     }
6717                 }
6718
6719                 if (GetNodeTestData()->Lookup(tree, &tlAndN))
6720                 {
6721                     reachable->Set(tree, 0);
6722                 }
6723             }
6724         }
6725     }
6726     return reachable;
6727 }
6728
6729 void Compiler::TransferTestDataToNode(GenTreePtr from, GenTreePtr to)
6730 {
6731     TestLabelAndNum tlAndN;
6732     // We can't currently associate multiple annotations with a single node.
6733     // If we need to, we can fix this...
6734
6735     // If the table is null, don't create it just to do the lookup, which would fail...
6736     if (m_nodeTestData != nullptr && GetNodeTestData()->Lookup(from, &tlAndN))
6737     {
6738         assert(!GetNodeTestData()->Lookup(to, &tlAndN));
6739         // We can't currently associate multiple annotations with a single node.
6740         // If we need to, we can fix this...
6741         TestLabelAndNum tlAndNTo;
6742         assert(!GetNodeTestData()->Lookup(to, &tlAndNTo));
6743
6744         GetNodeTestData()->Remove(from);
6745         GetNodeTestData()->Set(to, tlAndN);
6746     }
6747 }
6748
6749 void Compiler::CopyTestDataToCloneTree(GenTreePtr from, GenTreePtr to)
6750 {
6751     if (m_nodeTestData == nullptr)
6752     {
6753         return;
6754     }
6755     if (from == nullptr)
6756     {
6757         assert(to == nullptr);
6758         return;
6759     }
6760     // Otherwise...
6761     TestLabelAndNum tlAndN;
6762     if (GetNodeTestData()->Lookup(from, &tlAndN))
6763     {
6764         // We can't currently associate multiple annotations with a single node.
6765         // If we need to, we can fix this...
6766         TestLabelAndNum tlAndNTo;
6767         assert(!GetNodeTestData()->Lookup(to, &tlAndNTo));
6768         GetNodeTestData()->Set(to, tlAndN);
6769     }
6770     // Now recurse, in parallel on both trees.
6771
6772     genTreeOps oper = from->OperGet();
6773     unsigned   kind = from->OperKind();
6774     assert(oper == to->OperGet());
6775
6776     // Cconstant or leaf nodes have no children.
6777     if (kind & (GTK_CONST | GTK_LEAF))
6778     {
6779         return;
6780     }
6781
6782     // Otherwise, is it a 'simple' unary/binary operator?
6783
6784     if (kind & GTK_SMPOP)
6785     {
6786         if (from->gtOp.gtOp1 != nullptr)
6787         {
6788             assert(to->gtOp.gtOp1 != nullptr);
6789             CopyTestDataToCloneTree(from->gtOp.gtOp1, to->gtOp.gtOp1);
6790         }
6791         else
6792         {
6793             assert(to->gtOp.gtOp1 == nullptr);
6794         }
6795
6796         if (from->gtGetOp2() != nullptr)
6797         {
6798             assert(to->gtGetOp2() != nullptr);
6799             CopyTestDataToCloneTree(from->gtGetOp2(), to->gtGetOp2());
6800         }
6801         else
6802         {
6803             assert(to->gtGetOp2() == nullptr);
6804         }
6805
6806         return;
6807     }
6808
6809     // Otherwise, see what kind of a special operator we have here.
6810
6811     switch (oper)
6812     {
6813         case GT_STMT:
6814             CopyTestDataToCloneTree(from->gtStmt.gtStmtExpr, to->gtStmt.gtStmtExpr);
6815             return;
6816
6817         case GT_CALL:
6818             CopyTestDataToCloneTree(from->gtCall.gtCallObjp, to->gtCall.gtCallObjp);
6819             CopyTestDataToCloneTree(from->gtCall.gtCallArgs, to->gtCall.gtCallArgs);
6820             CopyTestDataToCloneTree(from->gtCall.gtCallLateArgs, to->gtCall.gtCallLateArgs);
6821
6822             if (from->gtCall.gtCallType == CT_INDIRECT)
6823             {
6824                 CopyTestDataToCloneTree(from->gtCall.gtCallCookie, to->gtCall.gtCallCookie);
6825                 CopyTestDataToCloneTree(from->gtCall.gtCallAddr, to->gtCall.gtCallAddr);
6826             }
6827             // The other call types do not have additional GenTree arguments.
6828
6829             return;
6830
6831         case GT_FIELD:
6832             CopyTestDataToCloneTree(from->gtField.gtFldObj, to->gtField.gtFldObj);
6833             return;
6834
6835         case GT_ARR_ELEM:
6836             assert(from->gtArrElem.gtArrRank == to->gtArrElem.gtArrRank);
6837             for (unsigned dim = 0; dim < from->gtArrElem.gtArrRank; dim++)
6838             {
6839                 CopyTestDataToCloneTree(from->gtArrElem.gtArrInds[dim], to->gtArrElem.gtArrInds[dim]);
6840             }
6841             CopyTestDataToCloneTree(from->gtArrElem.gtArrObj, to->gtArrElem.gtArrObj);
6842             return;
6843
6844         case GT_CMPXCHG:
6845             CopyTestDataToCloneTree(from->gtCmpXchg.gtOpLocation, to->gtCmpXchg.gtOpLocation);
6846             CopyTestDataToCloneTree(from->gtCmpXchg.gtOpValue, to->gtCmpXchg.gtOpValue);
6847             CopyTestDataToCloneTree(from->gtCmpXchg.gtOpComparand, to->gtCmpXchg.gtOpComparand);
6848             return;
6849
6850         case GT_ARR_BOUNDS_CHECK:
6851 #ifdef FEATURE_SIMD
6852         case GT_SIMD_CHK:
6853 #endif // FEATURE_SIMD
6854             CopyTestDataToCloneTree(from->gtBoundsChk.gtArrLen, to->gtBoundsChk.gtArrLen);
6855             CopyTestDataToCloneTree(from->gtBoundsChk.gtIndex, to->gtBoundsChk.gtIndex);
6856             return;
6857
6858         default:
6859             unreached();
6860     }
6861 }
6862
6863 #endif // DEBUG
6864
6865 /*
6866 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6867 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6868 XX                                                                           XX
6869 XX                          jvc                                              XX
6870 XX                                                                           XX
6871 XX  Functions for the stand-alone version of the JIT .                       XX
6872 XX                                                                           XX
6873 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6874 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6875 */
6876
6877 /*****************************************************************************/
6878 void codeGeneratorCodeSizeBeg()
6879 {
6880 }
6881 /*****************************************************************************/
6882
6883 /*****************************************************************************
6884  *
6885  *  If any temporary tables are smaller than 'genMinSize2free' we won't bother
6886  *  freeing them.
6887  */
6888
6889 const size_t genMinSize2free = 64;
6890
6891 /*****************************************************************************/
6892
6893 /*****************************************************************************
6894  *
6895  *  Used for counting pointer assignments.
6896  */
6897
6898 /*****************************************************************************/
6899 void codeGeneratorCodeSizeEnd()
6900 {
6901 }
6902 /*****************************************************************************
6903  *
6904  *  Gather statistics - mainly used for the standalone
6905  *  Enable various #ifdef's to get the information you need
6906  */
6907
6908 void Compiler::compJitStats()
6909 {
6910 #if CALL_ARG_STATS
6911
6912     /* Method types and argument statistics */
6913     compCallArgStats();
6914 #endif // CALL_ARG_STATS
6915 }
6916
6917 #if CALL_ARG_STATS
6918
6919 /*****************************************************************************
6920  *
6921  *  Gather statistics about method calls and arguments
6922  */
6923
6924 void Compiler::compCallArgStats()
6925 {
6926     GenTreePtr args;
6927     GenTreePtr argx;
6928
6929     BasicBlock* block;
6930     GenTreePtr  stmt;
6931     GenTreePtr  call;
6932
6933     unsigned argNum;
6934
6935     unsigned argDWordNum;
6936     unsigned argLngNum;
6937     unsigned argFltNum;
6938     unsigned argDblNum;
6939
6940     unsigned regArgNum;
6941     unsigned regArgDeferred;
6942     unsigned regArgTemp;
6943
6944     unsigned regArgLclVar;
6945     unsigned regArgConst;
6946
6947     unsigned argTempsThisMethod = 0;
6948
6949     assert(fgStmtListThreaded);
6950
6951     for (block = fgFirstBB; block; block = block->bbNext)
6952     {
6953         for (stmt = block->bbTreeList; stmt; stmt = stmt->gtNext)
6954         {
6955             assert(stmt->gtOper == GT_STMT);
6956
6957             for (call = stmt->gtStmt.gtStmtList; call; call = call->gtNext)
6958             {
6959                 if (call->gtOper != GT_CALL)
6960                     continue;
6961
6962                 argNum =
6963
6964                     regArgNum = regArgDeferred = regArgTemp =
6965
6966                         regArgConst = regArgLclVar =
6967
6968                             argDWordNum = argLngNum = argFltNum = argDblNum = 0;
6969
6970                 argTotalCalls++;
6971
6972                 if (!call->gtCall.gtCallObjp)
6973                 {
6974                     if (call->gtCall.gtCallType == CT_HELPER)
6975                     {
6976                         argHelperCalls++;
6977                     }
6978                     else
6979                     {
6980                         argStaticCalls++;
6981                     }
6982                 }
6983                 else
6984                 {
6985                     /* We have a 'this' pointer */
6986
6987                     argDWordNum++;
6988                     argNum++;
6989                     regArgNum++;
6990                     regArgDeferred++;
6991                     argTotalObjPtr++;
6992
6993                     if (call->gtFlags & (GTF_CALL_VIRT_VTABLE | GTF_CALL_VIRT_STUB))
6994                     {
6995                         /* virtual function */
6996                         argVirtualCalls++;
6997                     }
6998                     else
6999                     {
7000                         argNonVirtualCalls++;
7001                     }
7002                 }
7003
7004 #ifdef LEGACY_BACKEND
7005                 // TODO-Cleaenup: We need to add support below for additional node types that RyuJIT backend has in the
7006                 // IR.
7007                 // Gather arguments information.
7008
7009                 for (args = call->gtCall.gtCallArgs; args; args = args->gtOp.gtOp2)
7010                 {
7011                     argx = args->gtOp.gtOp1;
7012
7013                     argNum++;
7014
7015                     switch (genActualType(argx->TypeGet()))
7016                     {
7017                         case TYP_INT:
7018                         case TYP_REF:
7019                         case TYP_BYREF:
7020                             argDWordNum++;
7021                             break;
7022
7023                         case TYP_LONG:
7024                             argLngNum++;
7025                             break;
7026
7027                         case TYP_FLOAT:
7028                             argFltNum++;
7029                             break;
7030
7031                         case TYP_DOUBLE:
7032                             argDblNum++;
7033                             break;
7034
7035                         case TYP_VOID:
7036                             /* This is a deferred register argument */
7037                             assert(argx->gtOper == GT_NOP);
7038                             assert(argx->gtFlags & GTF_LATE_ARG);
7039                             argDWordNum++;
7040                             break;
7041                     }
7042
7043                     /* Is this argument a register argument? */
7044
7045                     if (argx->gtFlags & GTF_LATE_ARG)
7046                     {
7047                         regArgNum++;
7048
7049                         /* We either have a deferred argument or a temp */
7050
7051                         if (argx->gtOper == GT_NOP)
7052                         {
7053                             regArgDeferred++;
7054                         }
7055                         else
7056                         {
7057                             assert(argx->gtOper == GT_ASG);
7058                             regArgTemp++;
7059                         }
7060                     }
7061                 }
7062
7063                 /* Look at the register arguments and count how many constants, local vars */
7064
7065                 for (args = call->gtCall.gtCallLateArgs; args; args = args->gtOp.gtOp2)
7066                 {
7067                     argx = args->gtOp.gtOp1;
7068
7069                     switch (argx->gtOper)
7070                     {
7071                         case GT_CNS_INT:
7072                             regArgConst++;
7073                             break;
7074
7075                         case GT_LCL_VAR:
7076                             regArgLclVar++;
7077                             break;
7078                     }
7079                 }
7080
7081                 assert(argNum == argDWordNum + argLngNum + argFltNum + argDblNum);
7082                 assert(regArgNum == regArgDeferred + regArgTemp);
7083
7084                 argTotalArgs += argNum;
7085                 argTotalRegArgs += regArgNum;
7086
7087                 argTotalDWordArgs += argDWordNum;
7088                 argTotalLongArgs += argLngNum;
7089                 argTotalFloatArgs += argFltNum;
7090                 argTotalDoubleArgs += argDblNum;
7091
7092                 argTotalDeferred += regArgDeferred;
7093                 argTotalTemps += regArgTemp;
7094                 argTotalConst += regArgConst;
7095                 argTotalLclVar += regArgLclVar;
7096
7097                 argTempsThisMethod += regArgTemp;
7098
7099                 argCntTable.record(argNum);
7100                 argDWordCntTable.record(argDWordNum);
7101                 argDWordLngCntTable.record(argDWordNum + (2 * argLngNum));
7102 #endif // LEGACY_BACKEND
7103             }
7104         }
7105     }
7106
7107     argTempsCntTable.record(argTempsThisMethod);
7108
7109     if (argMaxTempsPerMethod < argTempsThisMethod)
7110     {
7111         argMaxTempsPerMethod = argTempsThisMethod;
7112     }
7113 }
7114
7115 /* static */
7116 void Compiler::compDispCallArgStats(FILE* fout)
7117 {
7118     if (argTotalCalls == 0)
7119         return;
7120
7121     fprintf(fout, "\n");
7122     fprintf(fout, "--------------------------------------------------\n");
7123     fprintf(fout, "Call stats\n");
7124     fprintf(fout, "--------------------------------------------------\n");
7125     fprintf(fout, "Total # of calls = %d, calls / method = %.3f\n\n", argTotalCalls,
7126             (float)argTotalCalls / genMethodCnt);
7127
7128     fprintf(fout, "Percentage of      helper calls = %4.2f %%\n", (float)(100 * argHelperCalls) / argTotalCalls);
7129     fprintf(fout, "Percentage of      static calls = %4.2f %%\n", (float)(100 * argStaticCalls) / argTotalCalls);
7130     fprintf(fout, "Percentage of     virtual calls = %4.2f %%\n", (float)(100 * argVirtualCalls) / argTotalCalls);
7131     fprintf(fout, "Percentage of non-virtual calls = %4.2f %%\n\n", (float)(100 * argNonVirtualCalls) / argTotalCalls);
7132
7133     fprintf(fout, "Average # of arguments per call = %.2f%%\n\n", (float)argTotalArgs / argTotalCalls);
7134
7135     fprintf(fout, "Percentage of DWORD  arguments   = %.2f %%\n", (float)(100 * argTotalDWordArgs) / argTotalArgs);
7136     fprintf(fout, "Percentage of LONG   arguments   = %.2f %%\n", (float)(100 * argTotalLongArgs) / argTotalArgs);
7137     fprintf(fout, "Percentage of FLOAT  arguments   = %.2f %%\n", (float)(100 * argTotalFloatArgs) / argTotalArgs);
7138     fprintf(fout, "Percentage of DOUBLE arguments   = %.2f %%\n\n", (float)(100 * argTotalDoubleArgs) / argTotalArgs);
7139
7140     if (argTotalRegArgs == 0)
7141         return;
7142
7143     /*
7144         fprintf(fout, "Total deferred arguments     = %d \n", argTotalDeferred);
7145
7146         fprintf(fout, "Total temp arguments         = %d \n\n", argTotalTemps);
7147
7148         fprintf(fout, "Total 'this' arguments       = %d \n", argTotalObjPtr);
7149         fprintf(fout, "Total local var arguments    = %d \n", argTotalLclVar);
7150         fprintf(fout, "Total constant arguments     = %d \n\n", argTotalConst);
7151     */
7152
7153     fprintf(fout, "\nRegister Arguments:\n\n");
7154
7155     fprintf(fout, "Percentage of deferred arguments = %.2f %%\n", (float)(100 * argTotalDeferred) / argTotalRegArgs);
7156     fprintf(fout, "Percentage of temp arguments     = %.2f %%\n\n", (float)(100 * argTotalTemps) / argTotalRegArgs);
7157
7158     fprintf(fout, "Maximum # of temps per method    = %d\n\n", argMaxTempsPerMethod);
7159
7160     fprintf(fout, "Percentage of ObjPtr arguments   = %.2f %%\n", (float)(100 * argTotalObjPtr) / argTotalRegArgs);
7161     // fprintf(fout, "Percentage of global arguments   = %.2f %%\n", (float)(100 * argTotalDWordGlobEf) /
7162     // argTotalRegArgs);
7163     fprintf(fout, "Percentage of constant arguments = %.2f %%\n", (float)(100 * argTotalConst) / argTotalRegArgs);
7164     fprintf(fout, "Percentage of lcl var arguments  = %.2f %%\n\n", (float)(100 * argTotalLclVar) / argTotalRegArgs);
7165
7166     fprintf(fout, "--------------------------------------------------\n");
7167     fprintf(fout, "Argument count frequency table (includes ObjPtr):\n");
7168     fprintf(fout, "--------------------------------------------------\n");
7169     argCntTable.dump(fout);
7170     fprintf(fout, "--------------------------------------------------\n");
7171
7172     fprintf(fout, "--------------------------------------------------\n");
7173     fprintf(fout, "DWORD argument count frequency table (w/o LONG):\n");
7174     fprintf(fout, "--------------------------------------------------\n");
7175     argDWordCntTable.dump(fout);
7176     fprintf(fout, "--------------------------------------------------\n");
7177
7178     fprintf(fout, "--------------------------------------------------\n");
7179     fprintf(fout, "Temps count frequency table (per method):\n");
7180     fprintf(fout, "--------------------------------------------------\n");
7181     argTempsCntTable.dump(fout);
7182     fprintf(fout, "--------------------------------------------------\n");
7183
7184     /*
7185         fprintf(fout, "--------------------------------------------------\n");
7186         fprintf(fout, "DWORD argument count frequency table (w/ LONG):\n");
7187         fprintf(fout, "--------------------------------------------------\n");
7188         argDWordLngCntTable.dump(fout);
7189         fprintf(fout, "--------------------------------------------------\n");
7190     */
7191 }
7192
7193 #endif // CALL_ARG_STATS
7194
7195 // JIT time end to end, and by phases.
7196
7197 #ifdef FEATURE_JIT_METHOD_PERF
7198 // Static variables
7199 CritSecObject       CompTimeSummaryInfo::s_compTimeSummaryLock;
7200 CompTimeSummaryInfo CompTimeSummaryInfo::s_compTimeSummary;
7201 #if MEASURE_CLRAPI_CALLS
7202 double JitTimer::s_cyclesPerSec = CycleTimer::CyclesPerSecond();
7203 #endif
7204 #endif // FEATURE_JIT_METHOD_PERF
7205
7206 #if defined(FEATURE_JIT_METHOD_PERF) || DUMP_FLOWGRAPHS || defined(FEATURE_TRACELOGGING)
7207 const char* PhaseNames[] = {
7208 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent) string_nm,
7209 #include "compphases.h"
7210 };
7211
7212 const char* PhaseEnums[] = {
7213 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent) #enum_nm,
7214 #include "compphases.h"
7215 };
7216
7217 const LPCWSTR PhaseShortNames[] = {
7218 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent) W(short_nm),
7219 #include "compphases.h"
7220 };
7221 #endif // defined(FEATURE_JIT_METHOD_PERF) || DUMP_FLOWGRAPHS
7222
7223 #ifdef FEATURE_JIT_METHOD_PERF
7224 bool PhaseHasChildren[] = {
7225 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent) hasChildren,
7226 #include "compphases.h"
7227 };
7228
7229 int PhaseParent[] = {
7230 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent) parent,
7231 #include "compphases.h"
7232 };
7233
7234 CompTimeInfo::CompTimeInfo(unsigned byteCodeBytes)
7235     : m_byteCodeBytes(byteCodeBytes)
7236     , m_totalCycles(0)
7237     , m_parentPhaseEndSlop(0)
7238     , m_timerFailure(false)
7239 #if MEASURE_CLRAPI_CALLS
7240     , m_allClrAPIcalls(0)
7241     , m_allClrAPIcycles(0)
7242 #endif
7243 {
7244     for (int i = 0; i < PHASE_NUMBER_OF; i++)
7245     {
7246         m_invokesByPhase[i] = 0;
7247         m_cyclesByPhase[i]  = 0;
7248 #if MEASURE_CLRAPI_CALLS
7249         m_CLRinvokesByPhase[i] = 0;
7250         m_CLRcyclesByPhase[i]  = 0;
7251 #endif
7252     }
7253
7254 #if MEASURE_CLRAPI_CALLS
7255     assert(ARRAYSIZE(m_perClrAPIcalls) == API_ICorJitInfo_Names::API_COUNT);
7256     assert(ARRAYSIZE(m_perClrAPIcycles) == API_ICorJitInfo_Names::API_COUNT);
7257     assert(ARRAYSIZE(m_maxClrAPIcycles) == API_ICorJitInfo_Names::API_COUNT);
7258     for (int i = 0; i < API_ICorJitInfo_Names::API_COUNT; i++)
7259     {
7260         m_perClrAPIcalls[i]  = 0;
7261         m_perClrAPIcycles[i] = 0;
7262         m_maxClrAPIcycles[i] = 0;
7263     }
7264 #endif
7265 }
7266
7267 bool CompTimeSummaryInfo::IncludedInFilteredData(CompTimeInfo& info)
7268 {
7269     return false; // info.m_byteCodeBytes < 10;
7270 }
7271
7272 //------------------------------------------------------------------------
7273 // CompTimeSummaryInfo::AddInfo: Record timing info from one compile.
7274 //
7275 // Arguments:
7276 //    info          - The timing information to record.
7277 //    includePhases - If "true", the per-phase info in "info" is valid,
7278 //                    which means that a "normal" compile has ended; if
7279 //                    the value is "false" we are recording the results
7280 //                    of a partial compile (typically an import-only run
7281 //                    on behalf of the inliner) in which case the phase
7282 //                    info is not valid and so we only record EE call
7283 //                    overhead.
7284 void CompTimeSummaryInfo::AddInfo(CompTimeInfo& info, bool includePhases)
7285 {
7286     if (info.m_timerFailure)
7287     {
7288         return; // Don't update if there was a failure.
7289     }
7290
7291     CritSecHolder timeLock(s_compTimeSummaryLock);
7292
7293     if (includePhases)
7294     {
7295         bool includeInFiltered = IncludedInFilteredData(info);
7296
7297         m_numMethods++;
7298
7299         // Update the totals and maxima.
7300         m_total.m_byteCodeBytes += info.m_byteCodeBytes;
7301         m_maximum.m_byteCodeBytes = max(m_maximum.m_byteCodeBytes, info.m_byteCodeBytes);
7302         m_total.m_totalCycles += info.m_totalCycles;
7303         m_maximum.m_totalCycles = max(m_maximum.m_totalCycles, info.m_totalCycles);
7304
7305 #if MEASURE_CLRAPI_CALLS
7306         // Update the CLR-API values.
7307         m_total.m_allClrAPIcalls += info.m_allClrAPIcalls;
7308         m_maximum.m_allClrAPIcalls = max(m_maximum.m_allClrAPIcalls, info.m_allClrAPIcalls);
7309         m_total.m_allClrAPIcycles += info.m_allClrAPIcycles;
7310         m_maximum.m_allClrAPIcycles = max(m_maximum.m_allClrAPIcycles, info.m_allClrAPIcycles);
7311 #endif
7312
7313         if (includeInFiltered)
7314         {
7315             m_numFilteredMethods++;
7316             m_filtered.m_byteCodeBytes += info.m_byteCodeBytes;
7317             m_filtered.m_totalCycles += info.m_totalCycles;
7318             m_filtered.m_parentPhaseEndSlop += info.m_parentPhaseEndSlop;
7319         }
7320
7321         for (int i = 0; i < PHASE_NUMBER_OF; i++)
7322         {
7323             m_total.m_invokesByPhase[i] += info.m_invokesByPhase[i];
7324             m_total.m_cyclesByPhase[i] += info.m_cyclesByPhase[i];
7325
7326 #if MEASURE_CLRAPI_CALLS
7327             m_total.m_CLRinvokesByPhase[i] += info.m_CLRinvokesByPhase[i];
7328             m_total.m_CLRcyclesByPhase[i] += info.m_CLRcyclesByPhase[i];
7329 #endif
7330
7331             if (includeInFiltered)
7332             {
7333                 m_filtered.m_invokesByPhase[i] += info.m_invokesByPhase[i];
7334                 m_filtered.m_cyclesByPhase[i] += info.m_cyclesByPhase[i];
7335 #if MEASURE_CLRAPI_CALLS
7336                 m_filtered.m_CLRinvokesByPhase[i] += info.m_CLRinvokesByPhase[i];
7337                 m_filtered.m_CLRcyclesByPhase[i] += info.m_CLRcyclesByPhase[i];
7338 #endif
7339             }
7340             m_maximum.m_cyclesByPhase[i] = max(m_maximum.m_cyclesByPhase[i], info.m_cyclesByPhase[i]);
7341
7342 #if MEASURE_CLRAPI_CALLS
7343             m_maximum.m_CLRcyclesByPhase[i] = max(m_maximum.m_CLRcyclesByPhase[i], info.m_CLRcyclesByPhase[i]);
7344 #endif
7345         }
7346         m_total.m_parentPhaseEndSlop += info.m_parentPhaseEndSlop;
7347         m_maximum.m_parentPhaseEndSlop = max(m_maximum.m_parentPhaseEndSlop, info.m_parentPhaseEndSlop);
7348     }
7349 #if MEASURE_CLRAPI_CALLS
7350     else
7351     {
7352         m_totMethods++;
7353
7354         // Update the "global" CLR-API values.
7355         m_total.m_allClrAPIcalls += info.m_allClrAPIcalls;
7356         m_maximum.m_allClrAPIcalls = max(m_maximum.m_allClrAPIcalls, info.m_allClrAPIcalls);
7357         m_total.m_allClrAPIcycles += info.m_allClrAPIcycles;
7358         m_maximum.m_allClrAPIcycles = max(m_maximum.m_allClrAPIcycles, info.m_allClrAPIcycles);
7359
7360         // Update the per-phase CLR-API values.
7361         m_total.m_invokesByPhase[PHASE_CLR_API] += info.m_allClrAPIcalls;
7362         m_maximum.m_invokesByPhase[PHASE_CLR_API] =
7363             max(m_maximum.m_perClrAPIcalls[PHASE_CLR_API], info.m_allClrAPIcalls);
7364         m_total.m_cyclesByPhase[PHASE_CLR_API] += info.m_allClrAPIcycles;
7365         m_maximum.m_cyclesByPhase[PHASE_CLR_API] =
7366             max(m_maximum.m_cyclesByPhase[PHASE_CLR_API], info.m_allClrAPIcycles);
7367     }
7368
7369     for (int i = 0; i < API_ICorJitInfo_Names::API_COUNT; i++)
7370     {
7371         m_total.m_perClrAPIcalls[i] += info.m_perClrAPIcalls[i];
7372         m_maximum.m_perClrAPIcalls[i] = max(m_maximum.m_perClrAPIcalls[i], info.m_perClrAPIcalls[i]);
7373
7374         m_total.m_perClrAPIcycles[i] += info.m_perClrAPIcycles[i];
7375         m_maximum.m_perClrAPIcycles[i] = max(m_maximum.m_perClrAPIcycles[i], info.m_perClrAPIcycles[i]);
7376
7377         m_maximum.m_maxClrAPIcycles[i] = max(m_maximum.m_maxClrAPIcycles[i], info.m_maxClrAPIcycles[i]);
7378     }
7379 #endif
7380 }
7381
7382 // Static
7383 LPCWSTR Compiler::compJitTimeLogFilename = nullptr;
7384
7385 void CompTimeSummaryInfo::Print(FILE* f)
7386 {
7387     if (f == nullptr)
7388     {
7389         return;
7390     }
7391     // Otherwise...
7392     double countsPerSec = CycleTimer::CyclesPerSecond();
7393     if (countsPerSec == 0.0)
7394     {
7395         fprintf(f, "Processor does not have a high-frequency timer.\n");
7396         return;
7397     }
7398
7399     bool   extraInfo  = (JitConfig.JitEECallTimingInfo() != 0);
7400     double totTime_ms = 0.0;
7401
7402     fprintf(f, "JIT Compilation time report:\n");
7403     fprintf(f, "  Compiled %d methods.\n", m_numMethods);
7404     if (m_numMethods != 0)
7405     {
7406         fprintf(f, "  Compiled %d bytecodes total (%d max, %8.2f avg).\n", m_total.m_byteCodeBytes,
7407                 m_maximum.m_byteCodeBytes, (double)m_total.m_byteCodeBytes / (double)m_numMethods);
7408         totTime_ms = ((double)m_total.m_totalCycles / countsPerSec) * 1000.0;
7409         fprintf(f, "  Time: total: %10.3f Mcycles/%10.3f ms\n", ((double)m_total.m_totalCycles / 1000000.0),
7410                 totTime_ms);
7411         fprintf(f, "          max: %10.3f Mcycles/%10.3f ms\n", ((double)m_maximum.m_totalCycles) / 1000000.0,
7412                 ((double)m_maximum.m_totalCycles / countsPerSec) * 1000.0);
7413         fprintf(f, "          avg: %10.3f Mcycles/%10.3f ms\n",
7414                 ((double)m_total.m_totalCycles) / 1000000.0 / (double)m_numMethods, totTime_ms / (double)m_numMethods);
7415
7416         const char* extraHdr1 = "";
7417         const char* extraHdr2 = "";
7418 #if MEASURE_CLRAPI_CALLS
7419         if (extraInfo)
7420         {
7421             extraHdr1 = "    CLRs/meth   % in CLR";
7422             extraHdr2 = "-----------------------";
7423         }
7424 #endif
7425
7426         fprintf(f, "\n  Total time by phases:\n");
7427         fprintf(f, "     PHASE                          inv/meth   Mcycles    time (ms)  %% of total    max (ms)%s\n",
7428                 extraHdr1);
7429         fprintf(f, "     ---------------------------------------------------------------------------------------%s\n",
7430                 extraHdr2);
7431
7432         // Ensure that at least the names array and the Phases enum have the same number of entries:
7433         assert(sizeof(PhaseNames) / sizeof(const char*) == PHASE_NUMBER_OF);
7434         for (int i = 0; i < PHASE_NUMBER_OF; i++)
7435         {
7436             double phase_tot_ms  = (((double)m_total.m_cyclesByPhase[i]) / countsPerSec) * 1000.0;
7437             double phase_max_ms  = (((double)m_maximum.m_cyclesByPhase[i]) / countsPerSec) * 1000.0;
7438             double phase_tot_pct = 100.0 * phase_tot_ms / totTime_ms;
7439
7440 #if MEASURE_CLRAPI_CALLS
7441             // Skip showing CLR API call info if we didn't collect any
7442             if (i == PHASE_CLR_API && !extraInfo)
7443                 continue;
7444 #endif
7445
7446             // Indent nested phases, according to depth.
7447             int ancPhase = PhaseParent[i];
7448             while (ancPhase != -1)
7449             {
7450                 fprintf(f, "  ");
7451                 ancPhase = PhaseParent[ancPhase];
7452             }
7453             fprintf(f, "     %-30s %6.2f  %10.2f   %9.3f   %8.2f%%    %8.3f", PhaseNames[i],
7454                     ((double)m_total.m_invokesByPhase[i]) / ((double)m_numMethods),
7455                     ((double)m_total.m_cyclesByPhase[i]) / 1000000.0, phase_tot_ms, (phase_tot_ms * 100.0 / totTime_ms),
7456                     phase_max_ms);
7457
7458 #if MEASURE_CLRAPI_CALLS
7459             if (extraInfo && i != PHASE_CLR_API)
7460             {
7461                 double nest_tot_ms  = (((double)m_total.m_CLRcyclesByPhase[i]) / countsPerSec) * 1000.0;
7462                 double nest_percent = nest_tot_ms * 100.0 / totTime_ms;
7463                 double calls_per_fn = ((double)m_total.m_CLRinvokesByPhase[i]) / ((double)m_numMethods);
7464
7465                 if (nest_percent > 0.1 || calls_per_fn > 10)
7466                     fprintf(f, "       %5.1f   %8.2f%%", calls_per_fn, nest_percent);
7467             }
7468 #endif
7469             fprintf(f, "\n");
7470         }
7471
7472         // Show slop if it's over a certain percentage of the total
7473         double pslop_pct = 100.0 * m_total.m_parentPhaseEndSlop * 1000.0 / countsPerSec / totTime_ms;
7474         if (pslop_pct >= 1.0)
7475         {
7476             fprintf(f, "\n  'End phase slop' should be very small (if not, there's unattributed time): %9.3f Mcycles = "
7477                        "%3.1f%% of total.\n\n",
7478                     m_total.m_parentPhaseEndSlop / 1000000.0, pslop_pct);
7479         }
7480     }
7481     if (m_numFilteredMethods > 0)
7482     {
7483         fprintf(f, "  Compiled %d methods that meet the filter requirement.\n", m_numFilteredMethods);
7484         fprintf(f, "  Compiled %d bytecodes total (%8.2f avg).\n", m_filtered.m_byteCodeBytes,
7485                 (double)m_filtered.m_byteCodeBytes / (double)m_numFilteredMethods);
7486         double totTime_ms = ((double)m_filtered.m_totalCycles / countsPerSec) * 1000.0;
7487         fprintf(f, "  Time: total: %10.3f Mcycles/%10.3f ms\n", ((double)m_filtered.m_totalCycles / 1000000.0),
7488                 totTime_ms);
7489         fprintf(f, "          avg: %10.3f Mcycles/%10.3f ms\n",
7490                 ((double)m_filtered.m_totalCycles) / 1000000.0 / (double)m_numFilteredMethods,
7491                 totTime_ms / (double)m_numFilteredMethods);
7492
7493         fprintf(f, "  Total time by phases:\n");
7494         fprintf(f, "     PHASE                            inv/meth Mcycles    time (ms)  %% of total\n");
7495         fprintf(f, "     --------------------------------------------------------------------------------------\n");
7496         // Ensure that at least the names array and the Phases enum have the same number of entries:
7497         assert(sizeof(PhaseNames) / sizeof(const char*) == PHASE_NUMBER_OF);
7498         for (int i = 0; i < PHASE_NUMBER_OF; i++)
7499         {
7500             double phase_tot_ms = (((double)m_filtered.m_cyclesByPhase[i]) / countsPerSec) * 1000.0;
7501             // Indent nested phases, according to depth.
7502             int ancPhase = PhaseParent[i];
7503             while (ancPhase != -1)
7504             {
7505                 fprintf(f, "  ");
7506                 ancPhase = PhaseParent[ancPhase];
7507             }
7508             fprintf(f, "     %-30s  %5.2f  %10.2f   %9.3f   %8.2f%%\n", PhaseNames[i],
7509                     ((double)m_filtered.m_invokesByPhase[i]) / ((double)m_numFilteredMethods),
7510                     ((double)m_filtered.m_cyclesByPhase[i]) / 1000000.0, phase_tot_ms,
7511                     (phase_tot_ms * 100.0 / totTime_ms));
7512         }
7513
7514         double fslop_ms = m_filtered.m_parentPhaseEndSlop * 1000.0 / countsPerSec;
7515         if (fslop_ms > 1.0)
7516         {
7517             fprintf(f,
7518                     "\n  'End phase slop' should be very small (if not, there's unattributed time): %9.3f Mcycles.\n",
7519                     m_filtered.m_parentPhaseEndSlop);
7520         }
7521     }
7522
7523 #if MEASURE_CLRAPI_CALLS
7524     if (m_total.m_allClrAPIcalls > 0 && m_total.m_allClrAPIcycles > 0)
7525     {
7526         fprintf(f, "\n");
7527         if (m_totMethods > 0)
7528             fprintf(f, "  Imported %u methods.\n\n", m_numMethods + m_totMethods);
7529
7530         fprintf(f, "     CLR API                                   # calls   total time    max time     avg time   %% "
7531                    "of total\n");
7532         fprintf(f, "     -------------------------------------------------------------------------------");
7533         fprintf(f, "---------------------\n");
7534
7535         static const char* APInames[] = {
7536 #define DEF_CLR_API(name) #name,
7537 #include "ICorJitInfo_API_names.h"
7538         };
7539
7540         unsigned shownCalls  = 0;
7541         double   shownMillis = 0.0;
7542 #ifdef DEBUG
7543         unsigned checkedCalls  = 0;
7544         double   checkedMillis = 0.0;
7545 #endif
7546
7547         for (unsigned pass = 0; pass < 2; pass++)
7548         {
7549             for (unsigned i = 0; i < API_ICorJitInfo_Names::API_COUNT; i++)
7550             {
7551                 unsigned calls = m_total.m_perClrAPIcalls[i];
7552                 if (calls == 0)
7553                     continue;
7554
7555                 unsigned __int64 cycles = m_total.m_perClrAPIcycles[i];
7556                 double           millis = 1000.0 * cycles / countsPerSec;
7557
7558                 // Don't show the small fry to keep the results manageable
7559                 if (millis < 0.5)
7560                 {
7561                     // We always show the following API because it is always called
7562                     // exactly once for each method and its body is the simplest one
7563                     // possible (it just returns an integer constant), and therefore
7564                     // it can be used to measure the overhead of adding the CLR API
7565                     // timing code. Roughly speaking, on a 3GHz x64 box the overhead
7566                     // per call should be around 40 ns when using RDTSC, compared to
7567                     // about 140 ns when using GetThreadCycles() under Windows.
7568                     if (i != API_ICorJitInfo_Names::API_getExpectedTargetArchitecture)
7569                         continue;
7570                 }
7571
7572                 // In the first pass we just compute the totals.
7573                 if (pass == 0)
7574                 {
7575                     shownCalls += m_total.m_perClrAPIcalls[i];
7576                     shownMillis += millis;
7577                     continue;
7578                 }
7579
7580                 unsigned __int32 maxcyc = m_maximum.m_maxClrAPIcycles[i];
7581                 double           max_ms = 1000.0 * maxcyc / countsPerSec;
7582
7583                 fprintf(f, "     %-40s", APInames[i]);                                 // API name
7584                 fprintf(f, " %8u %9.1f ms", calls, millis);                            // #calls, total time
7585                 fprintf(f, " %8.1f ms  %8.1f ns", max_ms, 1000000.0 * millis / calls); // max, avg time
7586                 fprintf(f, "     %5.1f%%\n", 100.0 * millis / shownMillis);            // % of total
7587
7588 #ifdef DEBUG
7589                 checkedCalls += m_total.m_perClrAPIcalls[i];
7590                 checkedMillis += millis;
7591 #endif
7592             }
7593         }
7594
7595 #ifdef DEBUG
7596         assert(checkedCalls == shownCalls);
7597         assert(checkedMillis == shownMillis);
7598 #endif
7599
7600         if (shownCalls > 0 || shownMillis > 0)
7601         {
7602             fprintf(f, "     -------------------------");
7603             fprintf(f, "---------------------------------------------------------------------------\n");
7604             fprintf(f, "     Total for calls shown above              %8u %10.1f ms", shownCalls, shownMillis);
7605             if (totTime_ms > 0.0)
7606                 fprintf(f, " (%4.1lf%% of overall JIT time)", shownMillis * 100.0 / totTime_ms);
7607             fprintf(f, "\n");
7608         }
7609         fprintf(f, "\n");
7610     }
7611 #endif
7612
7613     fprintf(f, "\n");
7614 }
7615
7616 JitTimer::JitTimer(unsigned byteCodeSize) : m_info(byteCodeSize)
7617 {
7618 #if MEASURE_CLRAPI_CALLS
7619     m_CLRcallInvokes = 0;
7620     m_CLRcallCycles  = 0;
7621 #endif
7622
7623 #ifdef DEBUG
7624     m_lastPhase = (Phases)-1;
7625 #if MEASURE_CLRAPI_CALLS
7626     m_CLRcallAPInum = -1;
7627 #endif
7628 #endif
7629
7630     unsigned __int64 threadCurCycles;
7631     if (_our_GetThreadCycles(&threadCurCycles))
7632     {
7633         m_start         = threadCurCycles;
7634         m_curPhaseStart = threadCurCycles;
7635     }
7636 }
7637
7638 void JitTimer::EndPhase(Phases phase)
7639 {
7640     // Otherwise...
7641     // We re-run some phases currently, so this following assert doesn't work.
7642     // assert((int)phase > (int)m_lastPhase);  // We should end phases in increasing order.
7643
7644     unsigned __int64 threadCurCycles;
7645     if (_our_GetThreadCycles(&threadCurCycles))
7646     {
7647         unsigned __int64 phaseCycles = (threadCurCycles - m_curPhaseStart);
7648
7649         // If this is not a leaf phase, the assumption is that the last subphase must have just recently ended.
7650         // Credit the duration to "slop", the total of which should be very small.
7651         if (PhaseHasChildren[phase])
7652         {
7653             m_info.m_parentPhaseEndSlop += phaseCycles;
7654         }
7655         else
7656         {
7657             // It is a leaf phase.  Credit duration to it.
7658             m_info.m_invokesByPhase[phase]++;
7659             m_info.m_cyclesByPhase[phase] += phaseCycles;
7660
7661 #if MEASURE_CLRAPI_CALLS
7662             // Record the CLR API timing info as well.
7663             m_info.m_CLRinvokesByPhase[phase] += m_CLRcallInvokes;
7664             m_info.m_CLRcyclesByPhase[phase] += m_CLRcallCycles;
7665 #endif
7666
7667             // Credit the phase's ancestors, if any.
7668             int ancPhase = PhaseParent[phase];
7669             while (ancPhase != -1)
7670             {
7671                 m_info.m_cyclesByPhase[ancPhase] += phaseCycles;
7672                 ancPhase = PhaseParent[ancPhase];
7673             }
7674
7675 #if MEASURE_CLRAPI_CALLS
7676             const Phases lastPhase = PHASE_CLR_API;
7677 #else
7678             const Phases lastPhase = PHASE_NUMBER_OF;
7679 #endif
7680             if (phase + 1 == lastPhase)
7681             {
7682                 m_info.m_totalCycles = (threadCurCycles - m_start);
7683             }
7684             else
7685             {
7686                 m_curPhaseStart = threadCurCycles;
7687             }
7688         }
7689     }
7690
7691 #ifdef DEBUG
7692     m_lastPhase = phase;
7693 #endif
7694 #if MEASURE_CLRAPI_CALLS
7695     m_CLRcallInvokes = 0;
7696     m_CLRcallCycles  = 0;
7697 #endif
7698 }
7699
7700 #if MEASURE_CLRAPI_CALLS
7701
7702 //------------------------------------------------------------------------
7703 // JitTimer::CLRApiCallEnter: Start the stopwatch for an EE call.
7704 //
7705 // Arguments:
7706 //    apix - The API index - an "enum API_ICorJitInfo_Names" value.
7707 //
7708
7709 void JitTimer::CLRApiCallEnter(unsigned apix)
7710 {
7711     assert(m_CLRcallAPInum == -1); // Nested calls not allowed
7712     m_CLRcallAPInum = apix;
7713
7714     // If we can't get the cycles, we'll just ignore this call
7715     if (!_our_GetThreadCycles(&m_CLRcallStart))
7716         m_CLRcallStart = 0;
7717 }
7718
7719 //------------------------------------------------------------------------
7720 // JitTimer::CLRApiCallLeave: compute / record time spent in an EE call.
7721 //
7722 // Arguments:
7723 //    apix - The API's "enum API_ICorJitInfo_Names" value; this value
7724 //           should match the value passed to the most recent call to
7725 //           "CLRApiCallEnter" (i.e. these must come as matched pairs),
7726 //           and they also may not nest.
7727 //
7728
7729 void JitTimer::CLRApiCallLeave(unsigned apix)
7730 {
7731     // Make sure we're actually inside a measured CLR call.
7732     assert(m_CLRcallAPInum != -1);
7733     m_CLRcallAPInum = -1;
7734
7735     // Ignore this one if we don't have a valid starting counter.
7736     if (m_CLRcallStart != 0)
7737     {
7738         if (JitConfig.JitEECallTimingInfo() != 0)
7739         {
7740             unsigned __int64 threadCurCycles;
7741             if (_our_GetThreadCycles(&threadCurCycles))
7742             {
7743                 // Compute the cycles spent in the call.
7744                 threadCurCycles -= m_CLRcallStart;
7745
7746                 // Add the cycles to the 'phase' and bump its use count.
7747                 m_info.m_cyclesByPhase[PHASE_CLR_API] += threadCurCycles;
7748                 m_info.m_invokesByPhase[PHASE_CLR_API] += 1;
7749
7750                 // Add the values to the "per API" info.
7751                 m_info.m_allClrAPIcycles += threadCurCycles;
7752                 m_info.m_allClrAPIcalls += 1;
7753
7754                 m_info.m_perClrAPIcalls[apix] += 1;
7755                 m_info.m_perClrAPIcycles[apix] += threadCurCycles;
7756                 m_info.m_maxClrAPIcycles[apix] = max(m_info.m_maxClrAPIcycles[apix], (unsigned __int32)threadCurCycles);
7757
7758                 // Subtract the cycles from the enclosing phase by bumping its start time
7759                 m_curPhaseStart += threadCurCycles;
7760
7761                 // Update the running totals.
7762                 m_CLRcallInvokes += 1;
7763                 m_CLRcallCycles += threadCurCycles;
7764             }
7765         }
7766
7767         m_CLRcallStart = 0;
7768     }
7769
7770     assert(m_CLRcallAPInum != -1); // No longer in this API call.
7771     m_CLRcallAPInum = -1;
7772 }
7773
7774 #endif // MEASURE_CLRAPI_CALLS
7775
7776 CritSecObject JitTimer::s_csvLock;
7777
7778 LPCWSTR Compiler::JitTimeLogCsv()
7779 {
7780     LPCWSTR jitTimeLogCsv = JitConfig.JitTimeLogCsv();
7781     return jitTimeLogCsv;
7782 }
7783
7784 void JitTimer::PrintCsvHeader()
7785 {
7786     LPCWSTR jitTimeLogCsv = Compiler::JitTimeLogCsv();
7787     if (jitTimeLogCsv == nullptr)
7788     {
7789         return;
7790     }
7791
7792     CritSecHolder csvLock(s_csvLock);
7793
7794     FILE* fp = _wfopen(jitTimeLogCsv, W("a"));
7795     if (fp != nullptr)
7796     {
7797         // Write the header if the file is empty
7798         if (ftell(fp) == 0)
7799         {
7800             fprintf(fp, "\"Method Name\",");
7801             fprintf(fp, "\"Method Index\",");
7802             fprintf(fp, "\"IL Bytes\",");
7803             fprintf(fp, "\"Basic Blocks\",");
7804             fprintf(fp, "\"Opt Level\",");
7805             fprintf(fp, "\"Loops Cloned\",");
7806
7807             for (int i = 0; i < PHASE_NUMBER_OF; i++)
7808             {
7809                 fprintf(fp, "\"%s\",", PhaseNames[i]);
7810             }
7811
7812             InlineStrategy::DumpCsvHeader(fp);
7813
7814             fprintf(fp, "\"Total Cycles\",");
7815             fprintf(fp, "\"CPS\"\n");
7816         }
7817         fclose(fp);
7818     }
7819 }
7820
7821 extern ICorJitHost* g_jitHost;
7822
7823 void JitTimer::PrintCsvMethodStats(Compiler* comp)
7824 {
7825     LPCWSTR jitTimeLogCsv = Compiler::JitTimeLogCsv();
7826     if (jitTimeLogCsv == nullptr)
7827     {
7828         return;
7829     }
7830
7831     // eeGetMethodFullName uses locks, so don't enter crit sec before this call.
7832     const char* methName = comp->eeGetMethodFullName(comp->info.compMethodHnd);
7833
7834     // Try and access the SPMI index to report in the data set.
7835     //
7836     // If the jit is not hosted under SPMI this will return the
7837     // default value of zero.
7838     //
7839     // Query the jit host directly here instead of going via the
7840     // config cache, since value will change for each method.
7841     int index = g_jitHost->getIntConfigValue(W("SuperPMIMethodContextNumber"), 0);
7842
7843     CritSecHolder csvLock(s_csvLock);
7844
7845     FILE* fp = _wfopen(jitTimeLogCsv, W("a"));
7846     fprintf(fp, "\"%s\",", methName);
7847     fprintf(fp, "%d,", index);
7848     fprintf(fp, "%u,", comp->info.compILCodeSize);
7849     fprintf(fp, "%u,", comp->fgBBcount);
7850     fprintf(fp, "%u,", comp->opts.MinOpts());
7851     fprintf(fp, "%u,", comp->optLoopsCloned);
7852     unsigned __int64 totCycles = 0;
7853     for (int i = 0; i < PHASE_NUMBER_OF; i++)
7854     {
7855         if (!PhaseHasChildren[i])
7856         {
7857             totCycles += m_info.m_cyclesByPhase[i];
7858         }
7859         fprintf(fp, "%I64u,", m_info.m_cyclesByPhase[i]);
7860     }
7861
7862     comp->m_inlineStrategy->DumpCsvData(fp);
7863
7864     fprintf(fp, "%I64u,", m_info.m_totalCycles);
7865     fprintf(fp, "%f\n", CycleTimer::CyclesPerSecond());
7866     fclose(fp);
7867 }
7868
7869 // Completes the timing of the current method, and adds it to "sum".
7870 void JitTimer::Terminate(Compiler* comp, CompTimeSummaryInfo& sum, bool includePhases)
7871 {
7872     if (includePhases)
7873     {
7874         PrintCsvMethodStats(comp);
7875     }
7876
7877     sum.AddInfo(m_info, includePhases);
7878 }
7879 #endif // FEATURE_JIT_METHOD_PERF
7880
7881 #if MEASURE_MEM_ALLOC
7882 // static vars.
7883 CritSecObject               Compiler::s_memStatsLock;    // Default constructor.
7884 Compiler::AggregateMemStats Compiler::s_aggMemStats;     // Default constructor.
7885 Compiler::MemStats          Compiler::s_maxCompMemStats; // Default constructor.
7886
7887 const char* Compiler::MemStats::s_CompMemKindNames[] = {
7888 #define CompMemKindMacro(kind) #kind,
7889 #include "compmemkind.h"
7890 };
7891
7892 void Compiler::MemStats::Print(FILE* f)
7893 {
7894     fprintf(f, "count: %10u, size: %10llu, max = %10llu\n", allocCnt, allocSz, allocSzMax);
7895     fprintf(f, "allocateMemory: %10llu, nraUsed: %10llu\n", nraTotalSizeAlloc, nraTotalSizeUsed);
7896     PrintByKind(f);
7897 }
7898
7899 void Compiler::MemStats::PrintByKind(FILE* f)
7900 {
7901     fprintf(f, "\nAlloc'd bytes by kind:\n  %20s | %10s | %7s\n", "kind", "size", "pct");
7902     fprintf(f, "  %20s-+-%10s-+-%7s\n", "--------------------", "----------", "-------");
7903     float allocSzF = static_cast<float>(allocSz);
7904     for (int cmk = 0; cmk < CMK_Count; cmk++)
7905     {
7906         float pct = 100.0f * static_cast<float>(allocSzByKind[cmk]) / allocSzF;
7907         fprintf(f, "  %20s | %10llu | %6.2f%%\n", s_CompMemKindNames[cmk], allocSzByKind[cmk], pct);
7908     }
7909     fprintf(f, "\n");
7910 }
7911
7912 void Compiler::AggregateMemStats::Print(FILE* f)
7913 {
7914     fprintf(f, "For %9u methods:\n", nMethods);
7915     if (nMethods == 0)
7916     {
7917         return;
7918     }
7919     fprintf(f, "  count:       %12u (avg %7u per method)\n", allocCnt, allocCnt / nMethods);
7920     fprintf(f, "  alloc size : %12llu (avg %7llu per method)\n", allocSz, allocSz / nMethods);
7921     fprintf(f, "  max alloc  : %12llu\n", allocSzMax);
7922     fprintf(f, "\n");
7923     fprintf(f, "  allocateMemory   : %12llu (avg %7llu per method)\n", nraTotalSizeAlloc, nraTotalSizeAlloc / nMethods);
7924     fprintf(f, "  nraUsed    : %12llu (avg %7llu per method)\n", nraTotalSizeUsed, nraTotalSizeUsed / nMethods);
7925     PrintByKind(f);
7926 }
7927 #endif // MEASURE_MEM_ALLOC
7928
7929 #if LOOP_HOIST_STATS
7930 // Static fields.
7931 CritSecObject Compiler::s_loopHoistStatsLock; // Default constructor.
7932 unsigned      Compiler::s_loopsConsidered             = 0;
7933 unsigned      Compiler::s_loopsWithHoistedExpressions = 0;
7934 unsigned      Compiler::s_totalHoistedExpressions     = 0;
7935
7936 // static
7937 void Compiler::PrintAggregateLoopHoistStats(FILE* f)
7938 {
7939     fprintf(f, "\n");
7940     fprintf(f, "---------------------------------------------------\n");
7941     fprintf(f, "Loop hoisting stats\n");
7942     fprintf(f, "---------------------------------------------------\n");
7943
7944     double pctWithHoisted = 0.0;
7945     if (s_loopsConsidered > 0)
7946     {
7947         pctWithHoisted = 100.0 * (double(s_loopsWithHoistedExpressions) / double(s_loopsConsidered));
7948     }
7949     double exprsPerLoopWithExpr = 0.0;
7950     if (s_loopsWithHoistedExpressions > 0)
7951     {
7952         exprsPerLoopWithExpr = double(s_totalHoistedExpressions) / double(s_loopsWithHoistedExpressions);
7953     }
7954     fprintf(f, "Considered %d loops.  Of these, we hoisted expressions out of %d (%6.2f%%).\n", s_loopsConsidered,
7955             s_loopsWithHoistedExpressions, pctWithHoisted);
7956     fprintf(f, "  A total of %d expressions were hoisted, an average of %5.2f per loop-with-hoisted-expr.\n",
7957             s_totalHoistedExpressions, exprsPerLoopWithExpr);
7958 }
7959
7960 void Compiler::AddLoopHoistStats()
7961 {
7962     CritSecHolder statsLock(s_loopHoistStatsLock);
7963
7964     s_loopsConsidered += m_loopsConsidered;
7965     s_loopsWithHoistedExpressions += m_loopsWithHoistedExpressions;
7966     s_totalHoistedExpressions += m_totalHoistedExpressions;
7967 }
7968
7969 void Compiler::PrintPerMethodLoopHoistStats()
7970 {
7971     double pctWithHoisted = 0.0;
7972     if (m_loopsConsidered > 0)
7973     {
7974         pctWithHoisted = 100.0 * (double(m_loopsWithHoistedExpressions) / double(m_loopsConsidered));
7975     }
7976     double exprsPerLoopWithExpr = 0.0;
7977     if (m_loopsWithHoistedExpressions > 0)
7978     {
7979         exprsPerLoopWithExpr = double(m_totalHoistedExpressions) / double(m_loopsWithHoistedExpressions);
7980     }
7981     printf("Considered %d loops.  Of these, we hoisted expressions out of %d (%5.2f%%).\n", m_loopsConsidered,
7982            m_loopsWithHoistedExpressions, pctWithHoisted);
7983     printf("  A total of %d expressions were hoisted, an average of %5.2f per loop-with-hoisted-expr.\n",
7984            m_totalHoistedExpressions, exprsPerLoopWithExpr);
7985 }
7986 #endif // LOOP_HOIST_STATS
7987
7988 //------------------------------------------------------------------------
7989 // RecordStateAtEndOfInlining: capture timing data (if enabled) after
7990 // inlining as completed.
7991 //
7992 // Note:
7993 // Records data needed for SQM and inlining data dumps.  Should be
7994 // called after inlining is complete.  (We do this after inlining
7995 // because this marks the last point at which the JIT is likely to
7996 // cause type-loading and class initialization).
7997
7998 void Compiler::RecordStateAtEndOfInlining()
7999 {
8000 #if defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
8001
8002     m_compCyclesAtEndOfInlining    = 0;
8003     m_compTickCountAtEndOfInlining = 0;
8004     bool b                         = CycleTimer::GetThreadCyclesS(&m_compCyclesAtEndOfInlining);
8005     if (!b)
8006     {
8007         return; // We don't have a thread cycle counter.
8008     }
8009     m_compTickCountAtEndOfInlining = GetTickCount();
8010
8011 #endif // defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
8012 }
8013
8014 //------------------------------------------------------------------------
8015 // RecordStateAtEndOfCompilation: capture timing data (if enabled) after
8016 // compilation is completed.
8017
8018 void Compiler::RecordStateAtEndOfCompilation()
8019 {
8020 #if defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
8021
8022     // Common portion
8023     m_compCycles = 0;
8024     unsigned __int64 compCyclesAtEnd;
8025     bool             b = CycleTimer::GetThreadCyclesS(&compCyclesAtEnd);
8026     if (!b)
8027     {
8028         return; // We don't have a thread cycle counter.
8029     }
8030     assert(compCyclesAtEnd >= m_compCyclesAtEndOfInlining);
8031
8032     m_compCycles = compCyclesAtEnd - m_compCyclesAtEndOfInlining;
8033
8034 #endif // defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
8035
8036 #ifdef FEATURE_CLRSQM
8037
8038     // SQM only portion
8039     unsigned __int64 mcycles64 = m_compCycles / ((unsigned __int64)1000000);
8040     unsigned         mcycles;
8041     if (mcycles64 > UINT32_MAX)
8042     {
8043         mcycles = UINT32_MAX;
8044     }
8045     else
8046     {
8047         mcycles = (unsigned)mcycles64;
8048     }
8049
8050     DWORD ticksAtEnd = GetTickCount();
8051     assert(ticksAtEnd >= m_compTickCountAtEndOfInlining);
8052     DWORD compTicks = ticksAtEnd - m_compTickCountAtEndOfInlining;
8053
8054     if (mcycles >= 1000)
8055     {
8056         info.compCompHnd->logSQMLongJitEvent(mcycles, compTicks, info.compILCodeSize, fgBBcount, opts.MinOpts(),
8057                                              info.compMethodHnd);
8058     }
8059
8060 #endif // FEATURE_CLRSQM
8061 }
8062
8063 #if FUNC_INFO_LOGGING
8064 // static
8065 LPCWSTR Compiler::compJitFuncInfoFilename = nullptr;
8066
8067 // static
8068 FILE* Compiler::compJitFuncInfoFile = nullptr;
8069 #endif // FUNC_INFO_LOGGING
8070
8071 #ifdef DEBUG
8072
8073 // dumpConvertedVarSet() is just like dumpVarSet(), except we assume the varset bits are tracked
8074 // variable indices, and we convert them to variable numbers, sort the variable numbers, and
8075 // print them as variable numbers. To do this, we use a temporary set indexed by
8076 // variable number. We can't use the "all varset" type because it is still size-limited, and might
8077 // not be big enough to handle all possible variable numbers.
8078 void dumpConvertedVarSet(Compiler* comp, VARSET_VALARG_TP vars)
8079 {
8080     BYTE* pVarNumSet; // trivial set: one byte per varNum, 0 means not in set, 1 means in set.
8081
8082     size_t varNumSetBytes = comp->lvaCount * sizeof(BYTE);
8083     pVarNumSet            = (BYTE*)_alloca(varNumSetBytes);
8084     memset(pVarNumSet, 0, varNumSetBytes); // empty the set
8085
8086     VARSET_ITER_INIT(comp, iter, vars, varIndex);
8087     while (iter.NextElem(comp, &varIndex))
8088     {
8089         unsigned varNum = comp->lvaTrackedToVarNum[varIndex];
8090         assert(varNum < comp->lvaCount);
8091         pVarNumSet[varNum] = 1; // This varNum is in the set
8092     }
8093
8094     bool first = true;
8095     printf("{");
8096     for (size_t varNum = 0; varNum < comp->lvaCount; varNum++)
8097     {
8098         if (pVarNumSet[varNum] == 1)
8099         {
8100             if (!first)
8101             {
8102                 printf(" ");
8103             }
8104             printf("V%02u", varNum);
8105             first = false;
8106         }
8107     }
8108     printf("}");
8109 }
8110
8111 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8112 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8113 XX                                                                           XX
8114 XX                          Debugging helpers                                XX
8115 XX                                                                           XX
8116 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8117 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8118 */
8119
8120 /*****************************************************************************/
8121 /* The following functions are intended to be called from the debugger, to dump
8122  * various data structures.
8123  *
8124  * The versions that start with 'c' take a Compiler* as the first argument.
8125  * The versions that start with 'd' use the tlsCompiler, so don't require a Compiler*.
8126  *
8127  * Summary:
8128  *      cBlock,      dBlock         : Display a basic block (call fgDispBasicBlock()).
8129  *      cBlocks,     dBlocks        : Display all the basic blocks of a function (call fgDispBasicBlocks()).
8130  *      cBlocksV,    dBlocksV       : Display all the basic blocks of a function (call fgDispBasicBlocks(true)).
8131  *                                    "V" means "verbose", and will dump all the trees.
8132  *      cTree,       dTree          : Display a tree (call gtDispTree()).
8133  *      cTrees,      dTrees         : Display all the trees in a function (call fgDumpTrees()).
8134  *      cEH,         dEH            : Display the EH handler table (call fgDispHandlerTab()).
8135  *      cVar,        dVar           : Display a local variable given its number (call lvaDumpEntry()).
8136  *      cVarDsc,     dVarDsc        : Display a local variable given a LclVarDsc* (call lvaDumpEntry()).
8137  *      cVars,       dVars          : Display the local variable table (call lvaTableDump()).
8138  *      cVarsFinal,  dVarsFinal     : Display the local variable table (call lvaTableDump(FINAL_FRAME_LAYOUT)).
8139  *      cBlockCheapPreds, dBlockCheapPreds : Display a block's cheap predecessors (call block->dspCheapPreds()).
8140  *      cBlockPreds, dBlockPreds    : Display a block's predecessors (call block->dspPreds()).
8141  *      cBlockSuccs, dBlockSuccs    : Display a block's successors (call block->dspSuccs(compiler)).
8142  *      cReach,      dReach         : Display all block reachability (call fgDispReach()).
8143  *      cDoms,       dDoms          : Display all block dominators (call fgDispDoms()).
8144  *      cLiveness,   dLiveness      : Display per-block variable liveness (call fgDispBBLiveness()).
8145  *      cCVarSet,    dCVarSet       : Display a "converted" VARSET_TP: the varset is assumed to be tracked variable
8146  *                                    indices. These are converted to variable numbers and sorted. (Calls
8147  *                                    dumpConvertedVarSet()).
8148  *
8149  *      cFuncIR,     dFuncIR        : Display all the basic blocks of a function in linear IR form.
8150  *      cLoopIR,     dLoopIR        : Display a loop in linear IR form.
8151  *                   dLoopNumIR     : Display a loop (given number) in linear IR form.
8152  *      cBlockIR,    dBlockIR       : Display a basic block in linear IR form.
8153  *      cTreeIR,     dTreeIR        : Display a tree in linear IR form.
8154  *                   dTabStopIR     : Display spaces to the next tab stop column
8155  *      cTreeTypeIR  dTreeTypeIR    : Display tree type
8156  *      cTreeKindsIR dTreeKindsIR   : Display tree kinds
8157  *      cTreeFlagsIR dTreeFlagsIR   : Display tree flags
8158  *      cOperandIR   dOperandIR     : Display tree operand
8159  *      cLeafIR      dLeafIR        : Display tree leaf
8160  *      cIndirIR     dIndirIR       : Display indir tree as [t#] or [leaf]
8161  *      cListIR      dListIR        : Display tree list
8162  *      cSsaNumIR    dSsaNumIR      : Display SSA number as <u|d:#>
8163  *      cValNumIR    dValNumIR      : Display Value number as <v{l|c}:#{,R}>
8164  *      cDependsIR                  : Display dependencies of a tree DEP(t# ...) node
8165  *                                    based on child comma tree nodes
8166  *                   dFormatIR      : Display dump format specified on command line
8167  *
8168  *
8169  * The following don't require a Compiler* to work:
8170  *      dVarSet                     : Display a VARSET_TP (call dumpVarSet()).
8171  *      dRegMask                    : Display a regMaskTP (call dspRegMask(mask)).
8172  */
8173
8174 void cBlock(Compiler* comp, BasicBlock* block)
8175 {
8176     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8177     printf("===================================================================== *Block %u\n", sequenceNumber++);
8178     comp->fgTableDispBasicBlock(block);
8179 }
8180
8181 void cBlocks(Compiler* comp)
8182 {
8183     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8184     printf("===================================================================== *Blocks %u\n", sequenceNumber++);
8185     comp->fgDispBasicBlocks();
8186 }
8187
8188 void cBlocksV(Compiler* comp)
8189 {
8190     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8191     printf("===================================================================== *BlocksV %u\n", sequenceNumber++);
8192     comp->fgDispBasicBlocks(true);
8193 }
8194
8195 void cTree(Compiler* comp, GenTree* tree)
8196 {
8197     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8198     printf("===================================================================== *Tree %u\n", sequenceNumber++);
8199     comp->gtDispTree(tree, nullptr, ">>>");
8200 }
8201
8202 void cTrees(Compiler* comp)
8203 {
8204     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8205     printf("===================================================================== *Trees %u\n", sequenceNumber++);
8206     comp->fgDumpTrees(comp->fgFirstBB, nullptr);
8207 }
8208
8209 void cEH(Compiler* comp)
8210 {
8211     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8212     printf("===================================================================== *EH %u\n", sequenceNumber++);
8213     comp->fgDispHandlerTab();
8214 }
8215
8216 void cVar(Compiler* comp, unsigned lclNum)
8217 {
8218     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8219     printf("===================================================================== *Var %u\n", sequenceNumber++);
8220     comp->lvaDumpEntry(lclNum, Compiler::FINAL_FRAME_LAYOUT);
8221 }
8222
8223 void cVarDsc(Compiler* comp, LclVarDsc* varDsc)
8224 {
8225     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8226     printf("===================================================================== *VarDsc %u\n", sequenceNumber++);
8227     unsigned lclNum = (unsigned)(varDsc - comp->lvaTable);
8228     comp->lvaDumpEntry(lclNum, Compiler::FINAL_FRAME_LAYOUT);
8229 }
8230
8231 void cVars(Compiler* comp)
8232 {
8233     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8234     printf("===================================================================== *Vars %u\n", sequenceNumber++);
8235     comp->lvaTableDump();
8236 }
8237
8238 void cVarsFinal(Compiler* comp)
8239 {
8240     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8241     printf("===================================================================== *Vars %u\n", sequenceNumber++);
8242     comp->lvaTableDump(Compiler::FINAL_FRAME_LAYOUT);
8243 }
8244
8245 void cBlockCheapPreds(Compiler* comp, BasicBlock* block)
8246 {
8247     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8248     printf("===================================================================== *BlockCheapPreds %u\n",
8249            sequenceNumber++);
8250     block->dspCheapPreds();
8251 }
8252
8253 void cBlockPreds(Compiler* comp, BasicBlock* block)
8254 {
8255     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8256     printf("===================================================================== *BlockPreds %u\n", sequenceNumber++);
8257     block->dspPreds();
8258 }
8259
8260 void cBlockSuccs(Compiler* comp, BasicBlock* block)
8261 {
8262     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8263     printf("===================================================================== *BlockSuccs %u\n", sequenceNumber++);
8264     block->dspSuccs(comp);
8265 }
8266
8267 void cReach(Compiler* comp)
8268 {
8269     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8270     printf("===================================================================== *Reach %u\n", sequenceNumber++);
8271     comp->fgDispReach();
8272 }
8273
8274 void cDoms(Compiler* comp)
8275 {
8276     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8277     printf("===================================================================== *Doms %u\n", sequenceNumber++);
8278     comp->fgDispDoms();
8279 }
8280
8281 void cLiveness(Compiler* comp)
8282 {
8283     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8284     printf("===================================================================== *Liveness %u\n", sequenceNumber++);
8285     comp->fgDispBBLiveness();
8286 }
8287
8288 void cCVarSet(Compiler* comp, VARSET_VALARG_TP vars)
8289 {
8290     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8291     printf("===================================================================== dCVarSet %u\n", sequenceNumber++);
8292     dumpConvertedVarSet(comp, vars);
8293     printf("\n"); // dumpConvertedVarSet() doesn't emit a trailing newline
8294 }
8295
8296 void dBlock(BasicBlock* block)
8297 {
8298     cBlock(JitTls::GetCompiler(), block);
8299 }
8300
8301 void dBlocks()
8302 {
8303     cBlocks(JitTls::GetCompiler());
8304 }
8305
8306 void dBlocksV()
8307 {
8308     cBlocksV(JitTls::GetCompiler());
8309 }
8310
8311 void dTree(GenTree* tree)
8312 {
8313     cTree(JitTls::GetCompiler(), tree);
8314 }
8315
8316 void dTrees()
8317 {
8318     cTrees(JitTls::GetCompiler());
8319 }
8320
8321 void dEH()
8322 {
8323     cEH(JitTls::GetCompiler());
8324 }
8325
8326 void dVar(unsigned lclNum)
8327 {
8328     cVar(JitTls::GetCompiler(), lclNum);
8329 }
8330
8331 void dVarDsc(LclVarDsc* varDsc)
8332 {
8333     cVarDsc(JitTls::GetCompiler(), varDsc);
8334 }
8335
8336 void dVars()
8337 {
8338     cVars(JitTls::GetCompiler());
8339 }
8340
8341 void dVarsFinal()
8342 {
8343     cVarsFinal(JitTls::GetCompiler());
8344 }
8345
8346 void dBlockPreds(BasicBlock* block)
8347 {
8348     cBlockPreds(JitTls::GetCompiler(), block);
8349 }
8350
8351 void dBlockCheapPreds(BasicBlock* block)
8352 {
8353     cBlockCheapPreds(JitTls::GetCompiler(), block);
8354 }
8355
8356 void dBlockSuccs(BasicBlock* block)
8357 {
8358     cBlockSuccs(JitTls::GetCompiler(), block);
8359 }
8360
8361 void dReach()
8362 {
8363     cReach(JitTls::GetCompiler());
8364 }
8365
8366 void dDoms()
8367 {
8368     cDoms(JitTls::GetCompiler());
8369 }
8370
8371 void dLiveness()
8372 {
8373     cLiveness(JitTls::GetCompiler());
8374 }
8375
8376 void dCVarSet(VARSET_VALARG_TP vars)
8377 {
8378     cCVarSet(JitTls::GetCompiler(), vars);
8379 }
8380
8381 void dRegMask(regMaskTP mask)
8382 {
8383     static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8384     printf("===================================================================== dRegMask %u\n", sequenceNumber++);
8385     dspRegMask(mask);
8386     printf("\n"); // dspRegMask() doesn't emit a trailing newline
8387 }
8388
8389 void dBlockList(BasicBlockList* list)
8390 {
8391     printf("WorkList: ");
8392     while (list != nullptr)
8393     {
8394         printf("BB%02u ", list->block->bbNum);
8395         list = list->next;
8396     }
8397     printf("\n");
8398 }
8399
8400 // Global variables available in debug mode.  That are set by debug APIs for finding
8401 // Trees, Stmts, and/or Blocks using id or bbNum.
8402 // That can be used in watch window or as a way to get address of fields for data break points.
8403
8404 GenTree*     dbTree;
8405 GenTreeStmt* dbStmt;
8406 BasicBlock*  dbTreeBlock;
8407 BasicBlock*  dbBlock;
8408
8409 // Debug APIs for finding Trees, Stmts, and/or Blocks.
8410 // As a side effect, they set the debug variables above.
8411
8412 GenTree* dFindTree(GenTree* tree, unsigned id)
8413 {
8414     GenTree* child;
8415
8416     if (tree == nullptr)
8417     {
8418         return nullptr;
8419     }
8420
8421     if (tree->gtTreeID == id)
8422     {
8423         dbTree = tree;
8424         return tree;
8425     }
8426
8427     unsigned childCount = tree->NumChildren();
8428     for (unsigned childIndex = 0; childIndex < childCount; childIndex++)
8429     {
8430         child = tree->GetChild(childIndex);
8431         child = dFindTree(child, id);
8432         if (child != nullptr)
8433         {
8434             return child;
8435         }
8436     }
8437
8438     return nullptr;
8439 }
8440
8441 GenTree* dFindTree(unsigned id)
8442 {
8443     Compiler*   comp = JitTls::GetCompiler();
8444     BasicBlock* block;
8445     GenTree*    tree;
8446
8447     dbTreeBlock = nullptr;
8448     dbTree      = nullptr;
8449
8450     for (block = comp->fgFirstBB; block != nullptr; block = block->bbNext)
8451     {
8452         for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
8453         {
8454             tree = dFindTree(stmt, id);
8455             if (tree != nullptr)
8456             {
8457                 dbTreeBlock = block;
8458                 return tree;
8459             }
8460         }
8461     }
8462
8463     return nullptr;
8464 }
8465
8466 GenTreeStmt* dFindStmt(unsigned id)
8467 {
8468     Compiler*   comp = JitTls::GetCompiler();
8469     BasicBlock* block;
8470
8471     dbStmt = nullptr;
8472
8473     unsigned stmtId = 0;
8474     for (block = comp->fgFirstBB; block != nullptr; block = block->bbNext)
8475     {
8476         for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
8477         {
8478             stmtId++;
8479             if (stmtId == id)
8480             {
8481                 dbStmt = stmt;
8482                 return stmt;
8483             }
8484         }
8485     }
8486
8487     return nullptr;
8488 }
8489
8490 BasicBlock* dFindBlock(unsigned bbNum)
8491 {
8492     Compiler*   comp  = JitTls::GetCompiler();
8493     BasicBlock* block = nullptr;
8494
8495     dbBlock = nullptr;
8496     for (block = comp->fgFirstBB; block != nullptr; block = block->bbNext)
8497     {
8498         if (block->bbNum == bbNum)
8499         {
8500             dbBlock = block;
8501             break;
8502         }
8503     }
8504
8505     return block;
8506 }
8507
8508 /*****************************************************************************
8509  *
8510  *  COMPlus_JitDumpIR support - dump out function in linear IR form
8511  */
8512
8513 void cFuncIR(Compiler* comp)
8514 {
8515     BasicBlock* block;
8516
8517     printf("Method %s::%s, hsh=0x%x\n", comp->info.compClassName, comp->info.compMethodName,
8518            comp->info.compMethodHash());
8519
8520     printf("\n");
8521
8522     for (block = comp->fgFirstBB; block != nullptr; block = block->bbNext)
8523     {
8524         cBlockIR(comp, block);
8525     }
8526 }
8527
8528 /*****************************************************************************
8529  *
8530  *  COMPlus_JitDumpIR support - dump out the format specifiers from COMPlus_JitDumpIRFormat
8531  */
8532
8533 void dFormatIR()
8534 {
8535     Compiler* comp = JitTls::GetCompiler();
8536
8537     if (comp->dumpIRFormat != nullptr)
8538     {
8539         printf("COMPlus_JitDumpIRFormat=%ls", comp->dumpIRFormat);
8540     }
8541 }
8542
8543 /*****************************************************************************
8544  *
8545  *  COMPlus_JitDumpIR support - dump out function in linear IR form
8546  */
8547
8548 void dFuncIR()
8549 {
8550     cFuncIR(JitTls::GetCompiler());
8551 }
8552
8553 /*****************************************************************************
8554  *
8555  *  COMPlus_JitDumpIR support - dump out loop in linear IR form
8556  */
8557
8558 void cLoopIR(Compiler* comp, Compiler::LoopDsc* loop)
8559 {
8560     BasicBlock* blockHead   = loop->lpHead;
8561     BasicBlock* blockFirst  = loop->lpFirst;
8562     BasicBlock* blockTop    = loop->lpTop;
8563     BasicBlock* blockEntry  = loop->lpEntry;
8564     BasicBlock* blockBottom = loop->lpBottom;
8565     BasicBlock* blockExit   = loop->lpExit;
8566     BasicBlock* blockLast   = blockBottom->bbNext;
8567     BasicBlock* block;
8568
8569     printf("LOOP\n");
8570     printf("\n");
8571     printf("HEAD   BB%02u\n", blockHead->bbNum);
8572     printf("FIRST  BB%02u\n", blockFirst->bbNum);
8573     printf("TOP    BB%02u\n", blockTop->bbNum);
8574     printf("ENTRY  BB%02u\n", blockEntry->bbNum);
8575     if (loop->lpExitCnt == 1)
8576     {
8577         printf("EXIT   BB%02u\n", blockExit->bbNum);
8578     }
8579     else
8580     {
8581         printf("EXITS  %u", loop->lpExitCnt);
8582     }
8583     printf("BOTTOM BB%02u\n", blockBottom->bbNum);
8584     printf("\n");
8585
8586     cBlockIR(comp, blockHead);
8587     for (block = blockFirst; ((block != nullptr) && (block != blockLast)); block = block->bbNext)
8588     {
8589         cBlockIR(comp, block);
8590     }
8591 }
8592
8593 /*****************************************************************************
8594  *
8595  *  COMPlus_JitDumpIR support - dump out loop in linear IR form
8596  */
8597
8598 void dLoopIR(Compiler::LoopDsc* loop)
8599 {
8600     cLoopIR(JitTls::GetCompiler(), loop);
8601 }
8602
8603 /*****************************************************************************
8604  *
8605  *  COMPlus_JitDumpIR support - dump out loop (given loop number) in linear IR form
8606  */
8607
8608 void dLoopNumIR(unsigned loopNum)
8609 {
8610     Compiler* comp = JitTls::GetCompiler();
8611
8612     if (loopNum >= comp->optLoopCount)
8613     {
8614         printf("loopNum %u out of range\n");
8615         return;
8616     }
8617
8618     Compiler::LoopDsc* loop = &comp->optLoopTable[loopNum];
8619     cLoopIR(JitTls::GetCompiler(), loop);
8620 }
8621
8622 /*****************************************************************************
8623  *
8624  *  COMPlus_JitDumpIR support - dump spaces to specified tab stop
8625  */
8626
8627 int dTabStopIR(int curr, int tabstop)
8628 {
8629     int chars = 0;
8630
8631     if (tabstop <= curr)
8632     {
8633         chars += printf(" ");
8634     }
8635
8636     for (int i = curr; i < tabstop; i++)
8637     {
8638         chars += printf(" ");
8639     }
8640
8641     return chars;
8642 }
8643
8644 void cNodeIR(Compiler* comp, GenTree* tree);
8645
8646 /*****************************************************************************
8647  *
8648  *  COMPlus_JitDumpIR support - dump out block in linear IR form
8649  */
8650
8651 void cBlockIR(Compiler* comp, BasicBlock* block)
8652 {
8653     bool noStmts = comp->dumpIRNoStmts;
8654     bool trees   = comp->dumpIRTrees;
8655
8656     if (comp->dumpIRBlockHeaders)
8657     {
8658         block->dspBlockHeader(comp);
8659     }
8660     else
8661     {
8662         printf("BB%02u:\n", block->bbNum);
8663     }
8664
8665     printf("\n");
8666
8667     if (!block->IsLIR())
8668     {
8669         for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
8670         {
8671             // Print current stmt.
8672
8673             if (trees)
8674             {
8675                 cTree(comp, stmt);
8676                 printf("\n");
8677                 printf("=====================================================================\n");
8678             }
8679
8680             if (comp->compRationalIRForm)
8681             {
8682                 GenTree* tree;
8683
8684                 foreach_treenode_execution_order(tree, stmt)
8685                 {
8686                     cNodeIR(comp, tree);
8687                 }
8688             }
8689             else
8690             {
8691                 cTreeIR(comp, stmt);
8692             }
8693
8694             if (!noStmts && !trees)
8695             {
8696                 printf("\n");
8697             }
8698         }
8699     }
8700     else
8701     {
8702         for (GenTree* node = block->bbTreeList; node != nullptr; node = node->gtNext)
8703         {
8704             cNodeIR(comp, node);
8705         }
8706     }
8707
8708     int chars = 0;
8709
8710     chars += dTabStopIR(chars, COLUMN_OPCODE);
8711
8712     chars += printf("   ");
8713     switch (block->bbJumpKind)
8714     {
8715         case BBJ_EHFINALLYRET:
8716             chars += printf("BRANCH(EHFINALLYRET)");
8717             break;
8718
8719         case BBJ_EHFILTERRET:
8720             chars += printf("BRANCH(EHFILTERRET)");
8721             break;
8722
8723         case BBJ_EHCATCHRET:
8724             chars += printf("BRANCH(EHCATCHRETURN)");
8725             chars += dTabStopIR(chars, COLUMN_OPERANDS);
8726             chars += printf(" BB%02u", block->bbJumpDest->bbNum);
8727             break;
8728
8729         case BBJ_THROW:
8730             chars += printf("BRANCH(THROW)");
8731             break;
8732
8733         case BBJ_RETURN:
8734             chars += printf("BRANCH(RETURN)");
8735             break;
8736
8737         case BBJ_NONE:
8738             // For fall-through blocks
8739             chars += printf("BRANCH(NONE)");
8740             break;
8741
8742         case BBJ_ALWAYS:
8743             chars += printf("BRANCH(ALWAYS)");
8744             chars += dTabStopIR(chars, COLUMN_OPERANDS);
8745             chars += printf(" BB%02u", block->bbJumpDest->bbNum);
8746             if (block->bbFlags & BBF_KEEP_BBJ_ALWAYS)
8747             {
8748                 chars += dTabStopIR(chars, COLUMN_KINDS);
8749                 chars += printf("; [KEEP_BBJ_ALWAYS]");
8750             }
8751             break;
8752
8753         case BBJ_LEAVE:
8754             chars += printf("BRANCH(LEAVE)");
8755             chars += dTabStopIR(chars, COLUMN_OPERANDS);
8756             chars += printf(" BB%02u", block->bbJumpDest->bbNum);
8757             break;
8758
8759         case BBJ_CALLFINALLY:
8760             chars += printf("BRANCH(CALLFINALLY)");
8761             chars += dTabStopIR(chars, COLUMN_OPERANDS);
8762             chars += printf(" BB%02u", block->bbJumpDest->bbNum);
8763             break;
8764
8765         case BBJ_COND:
8766             chars += printf("BRANCH(COND)");
8767             chars += dTabStopIR(chars, COLUMN_OPERANDS);
8768             chars += printf(" BB%02u", block->bbJumpDest->bbNum);
8769             break;
8770
8771         case BBJ_SWITCH:
8772             chars += printf("BRANCH(SWITCH)");
8773             chars += dTabStopIR(chars, COLUMN_OPERANDS);
8774
8775             unsigned jumpCnt;
8776             jumpCnt = block->bbJumpSwt->bbsCount;
8777             BasicBlock** jumpTab;
8778             jumpTab = block->bbJumpSwt->bbsDstTab;
8779             do
8780             {
8781                 chars += printf("%c BB%02u", (jumpTab == block->bbJumpSwt->bbsDstTab) ? ' ' : ',', (*jumpTab)->bbNum);
8782             } while (++jumpTab, --jumpCnt);
8783             break;
8784
8785         default:
8786             unreached();
8787             break;
8788     }
8789
8790     printf("\n");
8791     if (block->bbNext != nullptr)
8792     {
8793         printf("\n");
8794     }
8795 }
8796
8797 /*****************************************************************************
8798  *
8799  *  COMPlus_JitDumpIR support - dump out block in linear IR form
8800  */
8801
8802 void dBlockIR(BasicBlock* block)
8803 {
8804     cBlockIR(JitTls::GetCompiler(), block);
8805 }
8806
8807 /*****************************************************************************
8808  *
8809  *  COMPlus_JitDumpIR support - dump out tree node type for linear IR form
8810  */
8811
8812 int cTreeTypeIR(Compiler* comp, GenTree* tree)
8813 {
8814     int chars = 0;
8815
8816     var_types type = tree->TypeGet();
8817
8818     const char* typeName = varTypeName(type);
8819     chars += printf(".%s", typeName);
8820
8821     return chars;
8822 }
8823
8824 /*****************************************************************************
8825  *
8826  *  COMPlus_JitDumpIR support - dump out tree node type for linear IR form
8827  */
8828
8829 int dTreeTypeIR(GenTree* tree)
8830 {
8831     int chars = cTreeTypeIR(JitTls::GetCompiler(), tree);
8832
8833     return chars;
8834 }
8835
8836 /*****************************************************************************
8837  *
8838  *  COMPlus_JitDumpIR support - dump out tree node kind for linear IR form
8839  */
8840
8841 int cTreeKindsIR(Compiler* comp, GenTree* tree)
8842 {
8843     int chars = 0;
8844
8845     unsigned kind = tree->OperKind();
8846
8847     chars += printf("kinds=");
8848     if (kind == GTK_SPECIAL)
8849     {
8850         chars += printf("[SPECIAL]");
8851     }
8852     if (kind & GTK_CONST)
8853     {
8854         chars += printf("[CONST]");
8855     }
8856     if (kind & GTK_LEAF)
8857     {
8858         chars += printf("[LEAF]");
8859     }
8860     if (kind & GTK_UNOP)
8861     {
8862         chars += printf("[UNOP]");
8863     }
8864     if (kind & GTK_BINOP)
8865     {
8866         chars += printf("[BINOP]");
8867     }
8868     if (kind & GTK_LOGOP)
8869     {
8870         chars += printf("[LOGOP]");
8871     }
8872     if (kind & GTK_ASGOP)
8873     {
8874         chars += printf("[ASGOP]");
8875     }
8876     if (kind & GTK_COMMUTE)
8877     {
8878         chars += printf("[COMMUTE]");
8879     }
8880     if (kind & GTK_EXOP)
8881     {
8882         chars += printf("[EXOP]");
8883     }
8884     if (kind & GTK_LOCAL)
8885     {
8886         chars += printf("[LOCAL]");
8887     }
8888     if (kind & GTK_SMPOP)
8889     {
8890         chars += printf("[SMPOP]");
8891     }
8892
8893     return chars;
8894 }
8895
8896 /*****************************************************************************
8897  *
8898  *  COMPlus_JitDumpIR support - dump out tree node kind for linear IR form
8899  */
8900
8901 int dTreeKindsIR(GenTree* tree)
8902 {
8903     int chars = cTreeKindsIR(JitTls::GetCompiler(), tree);
8904
8905     return chars;
8906 }
8907
8908 /*****************************************************************************
8909  *
8910  *  COMPlus_JitDumpIR support - dump out tree node flags for linear IR form
8911  */
8912
8913 int cTreeFlagsIR(Compiler* comp, GenTree* tree)
8914 {
8915     int chars = 0;
8916
8917     if (tree->gtFlags != 0)
8918     {
8919         chars += printf("flags=");
8920
8921         // Node flags
8922         CLANG_FORMAT_COMMENT_ANCHOR;
8923
8924 #if defined(DEBUG)
8925 #if SMALL_TREE_NODES
8926         if (comp->dumpIRNodes)
8927         {
8928             if (tree->gtDebugFlags & GTF_DEBUG_NODE_LARGE)
8929             {
8930                 chars += printf("[NODE_LARGE]");
8931             }
8932             if (tree->gtDebugFlags & GTF_DEBUG_NODE_SMALL)
8933             {
8934                 chars += printf("[NODE_SMALL]");
8935             }
8936         }
8937 #endif // SMALL_TREE_NODES
8938         if (tree->gtDebugFlags & GTF_DEBUG_NODE_MORPHED)
8939         {
8940             chars += printf("[MORPHED]");
8941         }
8942 #endif // defined(DEBUG)
8943
8944         if (tree->gtFlags & GTF_COLON_COND)
8945         {
8946             chars += printf("[COLON_COND]");
8947         }
8948
8949         // Operator flags
8950
8951         genTreeOps op = tree->OperGet();
8952         switch (op)
8953         {
8954
8955             case GT_LCL_VAR:
8956             case GT_LCL_VAR_ADDR:
8957             case GT_LCL_FLD:
8958             case GT_LCL_FLD_ADDR:
8959             case GT_STORE_LCL_FLD:
8960             case GT_STORE_LCL_VAR:
8961             case GT_REG_VAR:
8962
8963                 if (tree->gtFlags & GTF_VAR_DEF)
8964                 {
8965                     chars += printf("[VAR_DEF]");
8966                 }
8967                 if (tree->gtFlags & GTF_VAR_USEASG)
8968                 {
8969                     chars += printf("[VAR_USEASG]");
8970                 }
8971                 if (tree->gtFlags & GTF_VAR_USEDEF)
8972                 {
8973                     chars += printf("[VAR_USEDEF]");
8974                 }
8975                 if (tree->gtFlags & GTF_VAR_CAST)
8976                 {
8977                     chars += printf("[VAR_CAST]");
8978                 }
8979                 if (tree->gtFlags & GTF_VAR_ITERATOR)
8980                 {
8981                     chars += printf("[VAR_ITERATOR]");
8982                 }
8983                 if (tree->gtFlags & GTF_VAR_CLONED)
8984                 {
8985                     chars += printf("[VAR_CLONED]");
8986                 }
8987                 if (tree->gtFlags & GTF_VAR_DEATH)
8988                 {
8989                     chars += printf("[VAR_DEATH]");
8990                 }
8991                 if (tree->gtFlags & GTF_VAR_ARR_INDEX)
8992                 {
8993                     chars += printf("[VAR_ARR_INDEX]");
8994                 }
8995 #if defined(DEBUG)
8996                 if (tree->gtDebugFlags & GTF_DEBUG_VAR_CSE_REF)
8997                 {
8998                     chars += printf("[VAR_CSE_REF]");
8999                 }
9000 #endif
9001                 if (op == GT_REG_VAR)
9002                 {
9003                     if (tree->gtFlags & GTF_REG_BIRTH)
9004                     {
9005                         chars += printf("[REG_BIRTH]");
9006                     }
9007                 }
9008                 break;
9009
9010             case GT_NOP:
9011
9012                 if (tree->gtFlags & GTF_NOP_DEATH)
9013                 {
9014                     chars += printf("[NOP_DEATH]");
9015                 }
9016                 break;
9017
9018             case GT_NO_OP:
9019
9020                 if (tree->gtFlags & GTF_NO_OP_NO)
9021                 {
9022                     chars += printf("[NO_OP_NO]");
9023                 }
9024                 break;
9025
9026             case GT_FIELD:
9027
9028                 if (tree->gtFlags & GTF_FLD_NULLCHECK)
9029                 {
9030                     chars += printf("[FLD_NULLCHECK]");
9031                 }
9032                 if (tree->gtFlags & GTF_FLD_VOLATILE)
9033                 {
9034                     chars += printf("[FLD_VOLATILE]");
9035                 }
9036                 break;
9037
9038             case GT_INDEX:
9039
9040                 if (tree->gtFlags & GTF_INX_RNGCHK)
9041                 {
9042                     chars += printf("[INX_RNGCHK]");
9043                 }
9044                 if (tree->gtFlags & GTF_INX_REFARR_LAYOUT)
9045                 {
9046                     chars += printf("[INX_REFARR_LAYOUT]");
9047                 }
9048                 if (tree->gtFlags & GTF_INX_STRING_LAYOUT)
9049                 {
9050                     chars += printf("[INX_STRING_LAYOUT]");
9051                 }
9052                 break;
9053
9054             case GT_IND:
9055             case GT_STOREIND:
9056
9057                 if (tree->gtFlags & GTF_IND_VOLATILE)
9058                 {
9059                     chars += printf("[IND_VOLATILE]");
9060                 }
9061                 if (tree->gtFlags & GTF_IND_REFARR_LAYOUT)
9062                 {
9063                     chars += printf("[IND_REFARR_LAYOUT]");
9064                 }
9065                 if (tree->gtFlags & GTF_IND_TGTANYWHERE)
9066                 {
9067                     chars += printf("[IND_TGTANYWHERE]");
9068                 }
9069                 if (tree->gtFlags & GTF_IND_TLS_REF)
9070                 {
9071                     chars += printf("[IND_TLS_REF]");
9072                 }
9073                 if (tree->gtFlags & GTF_IND_ASG_LHS)
9074                 {
9075                     chars += printf("[IND_ASG_LHS]");
9076                 }
9077                 if (tree->gtFlags & GTF_IND_UNALIGNED)
9078                 {
9079                     chars += printf("[IND_UNALIGNED]");
9080                 }
9081                 if (tree->gtFlags & GTF_IND_INVARIANT)
9082                 {
9083                     chars += printf("[IND_INVARIANT]");
9084                 }
9085                 if (tree->gtFlags & GTF_IND_ARR_LEN)
9086                 {
9087                     chars += printf("[IND_ARR_INDEX]");
9088                 }
9089                 break;
9090
9091             case GT_CLS_VAR:
9092
9093                 if (tree->gtFlags & GTF_CLS_VAR_ASG_LHS)
9094                 {
9095                     chars += printf("[CLS_VAR_ASG_LHS]");
9096                 }
9097                 break;
9098
9099             case GT_ADDR:
9100
9101                 if (tree->gtFlags & GTF_ADDR_ONSTACK)
9102                 {
9103                     chars += printf("[ADDR_ONSTACK]");
9104                 }
9105                 break;
9106
9107             case GT_MUL:
9108 #if defined(_TARGET_X86_) && !defined(LEGACY_BACKEND)
9109             case GT_MUL_LONG:
9110 #endif
9111
9112                 if (tree->gtFlags & GTF_MUL_64RSLT)
9113                 {
9114                     chars += printf("[64RSLT]");
9115                 }
9116                 if (tree->gtFlags & GTF_ADDRMODE_NO_CSE)
9117                 {
9118                     chars += printf("[ADDRMODE_NO_CSE]");
9119                 }
9120                 break;
9121
9122             case GT_ADD:
9123
9124                 if (tree->gtFlags & GTF_ADDRMODE_NO_CSE)
9125                 {
9126                     chars += printf("[ADDRMODE_NO_CSE]");
9127                 }
9128                 break;
9129
9130             case GT_LSH:
9131
9132                 if (tree->gtFlags & GTF_ADDRMODE_NO_CSE)
9133                 {
9134                     chars += printf("[ADDRMODE_NO_CSE]");
9135                 }
9136                 break;
9137
9138             case GT_MOD:
9139             case GT_UMOD:
9140
9141                 if (tree->gtFlags & GTF_MOD_INT_RESULT)
9142                 {
9143                     chars += printf("[MOD_INT_RESULT]");
9144                 }
9145                 break;
9146
9147             case GT_EQ:
9148             case GT_NE:
9149             case GT_LT:
9150             case GT_LE:
9151             case GT_GT:
9152             case GT_GE:
9153
9154                 if (tree->gtFlags & GTF_RELOP_NAN_UN)
9155                 {
9156                     chars += printf("[RELOP_NAN_UN]");
9157                 }
9158                 if (tree->gtFlags & GTF_RELOP_JMP_USED)
9159                 {
9160                     chars += printf("[RELOP_JMP_USED]");
9161                 }
9162                 if (tree->gtFlags & GTF_RELOP_QMARK)
9163                 {
9164                     chars += printf("[RELOP_QMARK]");
9165                 }
9166                 if (tree->gtFlags & GTF_RELOP_SMALL)
9167                 {
9168                     chars += printf("[RELOP_SMALL]");
9169                 }
9170                 break;
9171
9172             case GT_QMARK:
9173
9174                 if (tree->gtFlags & GTF_QMARK_CAST_INSTOF)
9175                 {
9176                     chars += printf("[QMARK_CAST_INSTOF]");
9177                 }
9178                 break;
9179
9180             case GT_BOX:
9181
9182                 if (tree->gtFlags & GTF_BOX_VALUE)
9183                 {
9184                     chars += printf("[BOX_VALUE]");
9185                 }
9186                 break;
9187
9188             case GT_CNS_INT:
9189
9190             {
9191                 unsigned handleKind = (tree->gtFlags & GTF_ICON_HDL_MASK);
9192
9193                 switch (handleKind)
9194                 {
9195
9196                     case GTF_ICON_SCOPE_HDL:
9197
9198                         chars += printf("[ICON_SCOPE_HDL]");
9199                         break;
9200
9201                     case GTF_ICON_CLASS_HDL:
9202
9203                         chars += printf("[ICON_CLASS_HDL]");
9204                         break;
9205
9206                     case GTF_ICON_METHOD_HDL:
9207
9208                         chars += printf("[ICON_METHOD_HDL]");
9209                         break;
9210
9211                     case GTF_ICON_FIELD_HDL:
9212
9213                         chars += printf("[ICON_FIELD_HDL]");
9214                         break;
9215
9216                     case GTF_ICON_STATIC_HDL:
9217
9218                         chars += printf("[ICON_STATIC_HDL]");
9219                         break;
9220
9221                     case GTF_ICON_STR_HDL:
9222
9223                         chars += printf("[ICON_STR_HDL]");
9224                         break;
9225
9226                     case GTF_ICON_PSTR_HDL:
9227
9228                         chars += printf("[ICON_PSTR_HDL]");
9229                         break;
9230
9231                     case GTF_ICON_PTR_HDL:
9232
9233                         chars += printf("[ICON_PTR_HDL]");
9234                         break;
9235
9236                     case GTF_ICON_VARG_HDL:
9237
9238                         chars += printf("[ICON_VARG_HDL]");
9239                         break;
9240
9241                     case GTF_ICON_PINVKI_HDL:
9242
9243                         chars += printf("[ICON_PINVKI_HDL]");
9244                         break;
9245
9246                     case GTF_ICON_TOKEN_HDL:
9247
9248                         chars += printf("[ICON_TOKEN_HDL]");
9249                         break;
9250
9251                     case GTF_ICON_TLS_HDL:
9252
9253                         chars += printf("[ICON_TLD_HDL]");
9254                         break;
9255
9256                     case GTF_ICON_FTN_ADDR:
9257
9258                         chars += printf("[ICON_FTN_ADDR]");
9259                         break;
9260
9261                     case GTF_ICON_CIDMID_HDL:
9262
9263                         chars += printf("[ICON_CIDMID_HDL]");
9264                         break;
9265
9266                     case GTF_ICON_BBC_PTR:
9267
9268                         chars += printf("[ICON_BBC_PTR]");
9269                         break;
9270
9271                     case GTF_ICON_FIELD_OFF:
9272
9273                         chars += printf("[ICON_FIELD_OFF]");
9274                         break;
9275                 }
9276             }
9277             break;
9278
9279             case GT_OBJ:
9280             case GT_STORE_OBJ:
9281                 if (tree->AsObj()->HasGCPtr())
9282                 {
9283                     chars += printf("[BLK_HASGCPTR]");
9284                 }
9285                 __fallthrough;
9286
9287             case GT_BLK:
9288             case GT_DYN_BLK:
9289             case GT_STORE_BLK:
9290             case GT_STORE_DYN_BLK:
9291
9292                 if (tree->gtFlags & GTF_BLK_VOLATILE)
9293                 {
9294                     chars += printf("[BLK_VOLATILE]");
9295                 }
9296                 if (tree->AsBlk()->IsUnaligned())
9297                 {
9298                     chars += printf("[BLK_UNALIGNED]");
9299                 }
9300                 break;
9301
9302             case GT_CALL:
9303
9304                 if (tree->gtFlags & GTF_CALL_UNMANAGED)
9305                 {
9306                     chars += printf("[CALL_UNMANAGED]");
9307                 }
9308                 if (tree->gtFlags & GTF_CALL_INLINE_CANDIDATE)
9309                 {
9310                     chars += printf("[CALL_INLINE_CANDIDATE]");
9311                 }
9312                 if (tree->gtFlags & GTF_CALL_NONVIRT)
9313                 {
9314                     chars += printf("[CALL_NONVIRT]");
9315                 }
9316                 if (tree->gtFlags & GTF_CALL_VIRT_VTABLE)
9317                 {
9318                     chars += printf("[CALL_VIRT_VTABLE]");
9319                 }
9320                 if (tree->gtFlags & GTF_CALL_VIRT_STUB)
9321                 {
9322                     chars += printf("[CALL_VIRT_STUB]");
9323                 }
9324                 if (tree->gtFlags & GTF_CALL_NULLCHECK)
9325                 {
9326                     chars += printf("[CALL_NULLCHECK]");
9327                 }
9328                 if (tree->gtFlags & GTF_CALL_POP_ARGS)
9329                 {
9330                     chars += printf("[CALL_POP_ARGS]");
9331                 }
9332                 if (tree->gtFlags & GTF_CALL_HOISTABLE)
9333                 {
9334                     chars += printf("[CALL_HOISTABLE]");
9335                 }
9336                 if (tree->gtFlags & GTF_CALL_REG_SAVE)
9337                 {
9338                     chars += printf("[CALL_REG_SAVE]");
9339                 }
9340
9341                 // More flags associated with calls.
9342
9343                 {
9344                     GenTreeCall* call = tree->AsCall();
9345
9346                     if (call->gtCallMoreFlags & GTF_CALL_M_EXPLICIT_TAILCALL)
9347                     {
9348                         chars += printf("[CALL_M_EXPLICIT_TAILCALL]");
9349                     }
9350                     if (call->gtCallMoreFlags & GTF_CALL_M_TAILCALL)
9351                     {
9352                         chars += printf("[CALL_M_TAILCALL]");
9353                     }
9354                     if (call->gtCallMoreFlags & GTF_CALL_M_VARARGS)
9355                     {
9356                         chars += printf("[CALL_M_VARARGS]");
9357                     }
9358                     if (call->gtCallMoreFlags & GTF_CALL_M_RETBUFFARG)
9359                     {
9360                         chars += printf("[CALL_M_RETBUFFARG]");
9361                     }
9362                     if (call->gtCallMoreFlags & GTF_CALL_M_DELEGATE_INV)
9363                     {
9364                         chars += printf("[CALL_M_DELEGATE_INV]");
9365                     }
9366                     if (call->gtCallMoreFlags & GTF_CALL_M_NOGCCHECK)
9367                     {
9368                         chars += printf("[CALL_M_NOGCCHECK]");
9369                     }
9370                     if (call->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC)
9371                     {
9372                         chars += printf("[CALL_M_SPECIAL_INTRINSIC]");
9373                     }
9374
9375                     if (call->IsUnmanaged())
9376                     {
9377                         if (call->gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
9378                         {
9379                             chars += printf("[CALL_M_UNMGD_THISCALL]");
9380                         }
9381                     }
9382                     else if (call->IsVirtualStub())
9383                     {
9384                         if (call->gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT)
9385                         {
9386                             chars += printf("[CALL_M_VIRTSTUB_REL_INDIRECT]");
9387                         }
9388                     }
9389                     else if (!call->IsVirtual())
9390                     {
9391                         if (call->gtCallMoreFlags & GTF_CALL_M_NONVIRT_SAME_THIS)
9392                         {
9393                             chars += printf("[CALL_M_NONVIRT_SAME_THIS]");
9394                         }
9395                     }
9396
9397                     if (call->gtCallMoreFlags & GTF_CALL_M_FRAME_VAR_DEATH)
9398                     {
9399                         chars += printf("[CALL_M_FRAME_VAR_DEATH]");
9400                     }
9401 #ifndef LEGACY_BACKEND
9402                     if (call->gtCallMoreFlags & GTF_CALL_M_TAILCALL_VIA_HELPER)
9403                     {
9404                         chars += printf("[CALL_M_TAILCALL_VIA_HELPER]");
9405                     }
9406 #endif
9407 #if FEATURE_TAILCALL_OPT
9408                     if (call->gtCallMoreFlags & GTF_CALL_M_IMPLICIT_TAILCALL)
9409                     {
9410                         chars += printf("[CALL_M_IMPLICIT_TAILCALL]");
9411                     }
9412 #endif
9413                     if (call->gtCallMoreFlags & GTF_CALL_M_PINVOKE)
9414                     {
9415                         chars += printf("[CALL_M_PINVOKE]");
9416                     }
9417                 }
9418                 break;
9419
9420             case GT_STMT:
9421
9422                 if (tree->gtFlags & GTF_STMT_CMPADD)
9423                 {
9424                     chars += printf("[STMT_CMPADD]");
9425                 }
9426                 if (tree->gtFlags & GTF_STMT_HAS_CSE)
9427                 {
9428                     chars += printf("[STMT_HAS_CSE]");
9429                 }
9430                 break;
9431
9432             default:
9433
9434             {
9435                 unsigned flags = (tree->gtFlags & (~(unsigned)(GTF_COMMON_MASK | GTF_OVERFLOW)));
9436                 if (flags != 0)
9437                 {
9438                     chars += printf("[%08X]", flags);
9439                 }
9440             }
9441             break;
9442         }
9443
9444         // Common flags.
9445
9446         if (tree->gtFlags & GTF_ASG)
9447         {
9448             chars += printf("[ASG]");
9449         }
9450         if (tree->gtFlags & GTF_CALL)
9451         {
9452             chars += printf("[CALL]");
9453         }
9454         switch (op)
9455         {
9456             case GT_MUL:
9457             case GT_CAST:
9458             case GT_ADD:
9459             case GT_SUB:
9460             case GT_ASG_ADD:
9461             case GT_ASG_SUB:
9462                 if (tree->gtFlags & GTF_OVERFLOW)
9463                 {
9464                     chars += printf("[OVERFLOW]");
9465                 }
9466                 break;
9467             default:
9468                 break;
9469         }
9470         if (tree->gtFlags & GTF_EXCEPT)
9471         {
9472             chars += printf("[EXCEPT]");
9473         }
9474         if (tree->gtFlags & GTF_GLOB_REF)
9475         {
9476             chars += printf("[GLOB_REF]");
9477         }
9478         if (tree->gtFlags & GTF_ORDER_SIDEEFF)
9479         {
9480             chars += printf("[ORDER_SIDEEFF]");
9481         }
9482         if (tree->gtFlags & GTF_REVERSE_OPS)
9483         {
9484             if (op != GT_LCL_VAR)
9485             {
9486                 chars += printf("[REVERSE_OPS]");
9487             }
9488         }
9489         if (tree->gtFlags & GTF_REG_VAL)
9490         {
9491             chars += printf("[REG_VAL]");
9492         }
9493         if (tree->gtFlags & GTF_SPILLED)
9494         {
9495             chars += printf("[SPILLED_OPER]");
9496         }
9497 #if defined(LEGACY_BACKEND)
9498         if (tree->gtFlags & GTF_SPILLED_OP2)
9499         {
9500             chars += printf("[SPILLED_OP2]");
9501         }
9502 #endif
9503         if (tree->gtFlags & GTF_ZSF_SET)
9504         {
9505             chars += printf("[ZSF_SET]");
9506         }
9507 #if FEATURE_SET_FLAGS
9508         if (tree->gtFlags & GTF_SET_FLAGS)
9509         {
9510             if ((op != GT_IND) && (op != GT_STOREIND))
9511             {
9512                 chars += printf("[ZSF_SET_FLAGS]");
9513             }
9514         }
9515 #endif
9516         if (tree->gtFlags & GTF_IND_NONFAULTING)
9517         {
9518             if ((op == GT_IND) || (op == GT_STOREIND))
9519             {
9520                 chars += printf("[IND_NONFAULTING]");
9521             }
9522         }
9523         if (tree->gtFlags & GTF_MAKE_CSE)
9524         {
9525             chars += printf("[MAKE_CSE]");
9526         }
9527         if (tree->gtFlags & GTF_DONT_CSE)
9528         {
9529             chars += printf("[DONT_CSE]");
9530         }
9531         if (tree->gtFlags & GTF_BOOLEAN)
9532         {
9533             chars += printf("[BOOLEAN]");
9534         }
9535         if (tree->gtFlags & GTF_SMALL_OK)
9536         {
9537             chars += printf("[SMALL_OK]");
9538         }
9539         if (tree->gtFlags & GTF_UNSIGNED)
9540         {
9541             chars += printf("[SMALL_UNSIGNED]");
9542         }
9543         if (tree->gtFlags & GTF_LATE_ARG)
9544         {
9545             chars += printf("[SMALL_LATE_ARG]");
9546         }
9547         if (tree->gtFlags & GTF_SPILL)
9548         {
9549             chars += printf("[SPILL]");
9550         }
9551         if (tree->gtFlags & GTF_SPILL_HIGH)
9552         {
9553             chars += printf("[SPILL_HIGH]");
9554         }
9555         if (tree->gtFlags & GTF_REUSE_REG_VAL)
9556         {
9557             if (op == GT_CNS_INT)
9558             {
9559                 chars += printf("[REUSE_REG_VAL]");
9560             }
9561         }
9562     }
9563
9564     return chars;
9565 }
9566
9567 /*****************************************************************************
9568  *
9569  *  COMPlus_JitDumpIR support - dump out tree node flags for linear IR form
9570  */
9571
9572 int dTreeFlagsIR(GenTree* tree)
9573 {
9574     int chars = cTreeFlagsIR(JitTls::GetCompiler(), tree);
9575
9576     return chars;
9577 }
9578
9579 /*****************************************************************************
9580  *
9581  *  COMPlus_JitDumpIR support - dump out SSA number on tree node for linear IR form
9582  */
9583
9584 int cSsaNumIR(Compiler* comp, GenTree* tree)
9585 {
9586     int chars = 0;
9587
9588     if (tree->gtLclVarCommon.HasSsaName())
9589     {
9590         if (tree->gtFlags & GTF_VAR_USEASG)
9591         {
9592             assert(tree->gtFlags & GTF_VAR_DEF);
9593             chars += printf("<u:%d><d:%d>", tree->gtLclVarCommon.gtSsaNum, comp->GetSsaNumForLocalVarDef(tree));
9594         }
9595         else
9596         {
9597             chars += printf("<%s:%d>", (tree->gtFlags & GTF_VAR_DEF) ? "d" : "u", tree->gtLclVarCommon.gtSsaNum);
9598         }
9599     }
9600
9601     return chars;
9602 }
9603
9604 /*****************************************************************************
9605  *
9606  *  COMPlus_JitDumpIR support - dump out SSA number on tree node for linear IR form
9607  */
9608
9609 int dSsaNumIR(GenTree* tree)
9610 {
9611     int chars = cSsaNumIR(JitTls::GetCompiler(), tree);
9612
9613     return chars;
9614 }
9615
9616 /*****************************************************************************
9617  *
9618  *  COMPlus_JitDumpIR support - dump out Value Number on tree node for linear IR form
9619  */
9620
9621 int cValNumIR(Compiler* comp, GenTree* tree)
9622 {
9623     int chars = 0;
9624
9625     if (tree->gtVNPair.GetLiberal() != ValueNumStore::NoVN)
9626     {
9627         assert(tree->gtVNPair.GetConservative() != ValueNumStore::NoVN);
9628         ValueNumPair vnp = tree->gtVNPair;
9629         ValueNum     vn;
9630         if (vnp.BothEqual())
9631         {
9632             chars += printf("<v:");
9633             vn = vnp.GetLiberal();
9634             chars += printf(STR_VN "%x", vn);
9635             if (ValueNumStore::isReservedVN(vn))
9636             {
9637                 chars += printf("R");
9638             }
9639             chars += printf(">");
9640         }
9641         else
9642         {
9643             vn = vnp.GetLiberal();
9644             chars += printf("<v:");
9645             chars += printf(STR_VN "%x", vn);
9646             if (ValueNumStore::isReservedVN(vn))
9647             {
9648                 chars += printf("R");
9649             }
9650             chars += printf(",");
9651             vn = vnp.GetConservative();
9652             chars += printf(STR_VN "%x", vn);
9653             if (ValueNumStore::isReservedVN(vn))
9654             {
9655                 chars += printf("R");
9656             }
9657             chars += printf(">");
9658         }
9659     }
9660
9661     return chars;
9662 }
9663
9664 /*****************************************************************************
9665  *
9666  *  COMPlus_JitDumpIR support - dump out Value Number on tree node for linear IR form
9667  */
9668
9669 int dValNumIR(GenTree* tree)
9670 {
9671     int chars = cValNumIR(JitTls::GetCompiler(), tree);
9672
9673     return chars;
9674 }
9675
9676 /*****************************************************************************
9677  *
9678  *  COMPlus_JitDumpIR support - dump out tree leaf node for linear IR form
9679  */
9680
9681 int cLeafIR(Compiler* comp, GenTree* tree)
9682 {
9683     int         chars  = 0;
9684     genTreeOps  op     = tree->OperGet();
9685     const char* ilKind = nullptr;
9686     const char* ilName = nullptr;
9687     unsigned    ilNum  = 0;
9688     unsigned    lclNum = 0;
9689     bool        hasSsa = false;
9690
9691     switch (op)
9692     {
9693
9694         case GT_PHI_ARG:
9695         case GT_LCL_VAR:
9696         case GT_LCL_VAR_ADDR:
9697         case GT_STORE_LCL_VAR:
9698         case GT_REG_VAR:
9699
9700             lclNum = tree->gtLclVarCommon.gtLclNum;
9701             comp->gtGetLclVarNameInfo(lclNum, &ilKind, &ilName, &ilNum);
9702             if (ilName != nullptr)
9703             {
9704                 chars += printf("%s", ilName);
9705             }
9706             else
9707             {
9708                 LclVarDsc* varDsc = comp->lvaTable + lclNum;
9709                 chars += printf("%s%d", ilKind, ilNum);
9710                 if (comp->dumpIRLocals)
9711                 {
9712                     chars += printf("(V%02u", lclNum);
9713                     if (varDsc->lvTracked)
9714                     {
9715                         chars += printf(":T%02u", varDsc->lvVarIndex);
9716                     }
9717                     if (comp->dumpIRRegs)
9718                     {
9719                         if (varDsc->lvRegister)
9720                         {
9721                             if (isRegPairType(varDsc->TypeGet()))
9722                             {
9723                                 chars += printf(":%s:%s",
9724                                                 getRegName(varDsc->lvOtherReg), // hi32
9725                                                 getRegName(varDsc->lvRegNum));  // lo32
9726                             }
9727                             else
9728                             {
9729                                 chars += printf(":%s", getRegName(varDsc->lvRegNum));
9730                             }
9731                         }
9732                         else
9733                         {
9734                             switch (tree->GetRegTag())
9735                             {
9736                                 case GenTree::GT_REGTAG_REG:
9737                                     chars += printf(":%s", comp->compRegVarName(tree->gtRegNum));
9738                                     break;
9739 #if CPU_LONG_USES_REGPAIR
9740                                 case GenTree::GT_REGTAG_REGPAIR:
9741                                     chars += printf(":%s", comp->compRegPairName(tree->gtRegPair));
9742                                     break;
9743 #endif
9744                                 default:
9745                                     break;
9746                             }
9747                         }
9748                     }
9749                     chars += printf(")");
9750                 }
9751                 else if (comp->dumpIRRegs)
9752                 {
9753                     if (varDsc->lvRegister)
9754                     {
9755                         chars += printf("(");
9756                         if (isRegPairType(varDsc->TypeGet()))
9757                         {
9758                             chars += printf("%s:%s",
9759                                             getRegName(varDsc->lvOtherReg), // hi32
9760                                             getRegName(varDsc->lvRegNum));  // lo32
9761                         }
9762                         else
9763                         {
9764                             chars += printf("%s", getRegName(varDsc->lvRegNum));
9765                         }
9766                         chars += printf(")");
9767                     }
9768                     else
9769                     {
9770                         switch (tree->GetRegTag())
9771                         {
9772                             case GenTree::GT_REGTAG_REG:
9773                                 chars += printf("(%s)", comp->compRegVarName(tree->gtRegNum));
9774                                 break;
9775 #if CPU_LONG_USES_REGPAIR
9776                             case GenTree::GT_REGTAG_REGPAIR:
9777                                 chars += printf("(%s)", comp->compRegPairName(tree->gtRegPair));
9778                                 break;
9779 #endif
9780                             default:
9781                                 break;
9782                         }
9783                     }
9784                 }
9785             }
9786
9787             if (op == GT_REG_VAR)
9788             {
9789                 if (isFloatRegType(tree->gtType))
9790                 {
9791                     assert(tree->gtRegVar.gtRegNum == tree->gtRegNum);
9792                     chars += printf("(FPV%u)", tree->gtRegNum);
9793                 }
9794                 else
9795                 {
9796                     chars += printf("(%s)", comp->compRegVarName(tree->gtRegVar.gtRegNum));
9797                 }
9798             }
9799
9800             hasSsa = true;
9801             break;
9802
9803         case GT_LCL_FLD:
9804         case GT_LCL_FLD_ADDR:
9805         case GT_STORE_LCL_FLD:
9806
9807             lclNum = tree->gtLclVarCommon.gtLclNum;
9808             comp->gtGetLclVarNameInfo(lclNum, &ilKind, &ilName, &ilNum);
9809             if (ilName != nullptr)
9810             {
9811                 chars += printf("%s+%u", ilName, tree->gtLclFld.gtLclOffs);
9812             }
9813             else
9814             {
9815                 chars += printf("%s%d+%u", ilKind, ilNum, tree->gtLclFld.gtLclOffs);
9816                 LclVarDsc* varDsc = comp->lvaTable + lclNum;
9817                 if (comp->dumpIRLocals)
9818                 {
9819                     chars += printf("(V%02u", lclNum);
9820                     if (varDsc->lvTracked)
9821                     {
9822                         chars += printf(":T%02u", varDsc->lvVarIndex);
9823                     }
9824                     if (comp->dumpIRRegs)
9825                     {
9826                         if (varDsc->lvRegister)
9827                         {
9828                             if (isRegPairType(varDsc->TypeGet()))
9829                             {
9830                                 chars += printf(":%s:%s",
9831                                                 getRegName(varDsc->lvOtherReg), // hi32
9832                                                 getRegName(varDsc->lvRegNum));  // lo32
9833                             }
9834                             else
9835                             {
9836                                 chars += printf(":%s", getRegName(varDsc->lvRegNum));
9837                             }
9838                         }
9839                         else
9840                         {
9841                             switch (tree->GetRegTag())
9842                             {
9843                                 case GenTree::GT_REGTAG_REG:
9844                                     chars += printf(":%s", comp->compRegVarName(tree->gtRegNum));
9845                                     break;
9846 #if CPU_LONG_USES_REGPAIR
9847                                 case GenTree::GT_REGTAG_REGPAIR:
9848                                     chars += printf(":%s", comp->compRegPairName(tree->gtRegPair));
9849                                     break;
9850 #endif
9851                                 default:
9852                                     break;
9853                             }
9854                         }
9855                     }
9856                     chars += printf(")");
9857                 }
9858                 else if (comp->dumpIRRegs)
9859                 {
9860                     if (varDsc->lvRegister)
9861                     {
9862                         chars += printf("(");
9863                         if (isRegPairType(varDsc->TypeGet()))
9864                         {
9865                             chars += printf("%s:%s",
9866                                             getRegName(varDsc->lvOtherReg), // hi32
9867                                             getRegName(varDsc->lvRegNum));  // lo32
9868                         }
9869                         else
9870                         {
9871                             chars += printf("%s", getRegName(varDsc->lvRegNum));
9872                         }
9873                         chars += printf(")");
9874                     }
9875                     else
9876                     {
9877                         switch (tree->GetRegTag())
9878                         {
9879                             case GenTree::GT_REGTAG_REG:
9880                                 chars += printf("(%s)", comp->compRegVarName(tree->gtRegNum));
9881                                 break;
9882 #if CPU_LONG_USES_REGPAIR
9883                             case GenTree::GT_REGTAG_REGPAIR:
9884                                 chars += printf("(%s)", comp->compRegPairName(tree->gtRegPair));
9885                                 break;
9886 #endif
9887                             default:
9888                                 break;
9889                         }
9890                     }
9891                 }
9892             }
9893
9894             // TODO: We probably want to expand field sequence.
9895             // gtDispFieldSeq(tree->gtLclFld.gtFieldSeq);
9896
9897             hasSsa = true;
9898             break;
9899
9900         case GT_CNS_INT:
9901
9902             if (tree->IsIconHandle())
9903             {
9904 #if 0
9905             // TODO: Commented out because sometimes the CLR throws
9906             // and exception when asking the names of some handles.
9907             // Need to investigate.
9908
9909             const char* className;
9910             const char* fieldName;
9911             const char* methodName;
9912             const wchar_t* str;
9913
9914             switch (tree->GetIconHandleFlag())
9915             {
9916
9917             case GTF_ICON_SCOPE_HDL:
9918
9919                 chars += printf("SCOPE(?)");
9920                 break;
9921
9922             case GTF_ICON_CLASS_HDL:
9923
9924                 className = comp->eeGetClassName((CORINFO_CLASS_HANDLE)tree->gtIntCon.gtIconVal);
9925                 chars += printf("CLASS(%s)", className);
9926                 break;
9927
9928             case GTF_ICON_METHOD_HDL:
9929
9930                 methodName = comp->eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtIntCon.gtIconVal,
9931                     &className);
9932                 chars += printf("METHOD(%s.%s)", className, methodName);
9933                 break;
9934
9935             case GTF_ICON_FIELD_HDL:
9936
9937                 fieldName = comp->eeGetFieldName((CORINFO_FIELD_HANDLE)tree->gtIntCon.gtIconVal,
9938                     &className);
9939                 chars += printf("FIELD(%s.%s) ", className, fieldName);
9940                 break;
9941
9942             case GTF_ICON_STATIC_HDL:
9943
9944                 fieldName = comp->eeGetFieldName((CORINFO_FIELD_HANDLE)tree->gtIntCon.gtIconVal,
9945                     &className);
9946                 chars += printf("STATIC_FIELD(%s.%s)", className, fieldName);
9947                 break;
9948
9949             case GTF_ICON_STR_HDL:
9950
9951                 str = comp->eeGetCPString(tree->gtIntCon.gtIconVal);
9952                 chars += printf("\"%S\"", str);
9953                 break;
9954
9955             case GTF_ICON_PSTR_HDL:
9956
9957                 chars += printf("PSTR(?)");
9958                 break;
9959
9960             case GTF_ICON_PTR_HDL:
9961
9962                 chars += printf("PTR(?)");
9963                 break;
9964
9965             case GTF_ICON_VARG_HDL:
9966
9967                 chars += printf("VARARG(?)");
9968                 break;
9969
9970             case GTF_ICON_PINVKI_HDL:
9971
9972                 chars += printf("PINVOKE(?)");
9973                 break;
9974
9975             case GTF_ICON_TOKEN_HDL:
9976
9977                 chars += printf("TOKEN(%08X)", tree->gtIntCon.gtIconVal);
9978                 break;
9979
9980             case GTF_ICON_TLS_HDL:
9981
9982                 chars += printf("TLS(?)");
9983                 break;
9984
9985             case GTF_ICON_FTN_ADDR:
9986
9987                 chars += printf("FTN(?)");
9988                 break;
9989
9990             case GTF_ICON_CIDMID_HDL:
9991
9992                 chars += printf("CIDMID(?)");
9993                 break;
9994
9995             case GTF_ICON_BBC_PTR:
9996
9997                 chars += printf("BBC(?)");
9998                 break;
9999
10000             default:
10001
10002                 chars += printf("HANDLE(?)");
10003                 break;
10004             }
10005 #else
10006 #ifdef _TARGET_64BIT_
10007                 if ((tree->gtIntCon.gtIconVal & 0xFFFFFFFF00000000LL) != 0)
10008                 {
10009                     chars += printf("HANDLE(0x%llx)", dspPtr(tree->gtIntCon.gtIconVal));
10010                 }
10011                 else
10012 #endif
10013                 {
10014                     chars += printf("HANDLE(0x%0x)", dspPtr(tree->gtIntCon.gtIconVal));
10015                 }
10016 #endif
10017             }
10018             else
10019             {
10020                 if (tree->TypeGet() == TYP_REF)
10021                 {
10022                     assert(tree->gtIntCon.gtIconVal == 0);
10023                     chars += printf("null");
10024                 }
10025 #ifdef _TARGET_64BIT_
10026                 else if ((tree->gtIntCon.gtIconVal & 0xFFFFFFFF00000000LL) != 0)
10027                 {
10028                     chars += printf("0x%llx", tree->gtIntCon.gtIconVal);
10029                 }
10030                 else
10031 #endif
10032                 {
10033                     chars += printf("%ld(0x%x)", tree->gtIntCon.gtIconVal, tree->gtIntCon.gtIconVal);
10034                 }
10035             }
10036             break;
10037
10038         case GT_CNS_LNG:
10039
10040             chars += printf("CONST(LONG)");
10041             break;
10042
10043         case GT_CNS_DBL:
10044
10045             chars += printf("CONST(DOUBLE)");
10046             break;
10047
10048         case GT_CNS_STR:
10049
10050             chars += printf("CONST(STR)");
10051             break;
10052
10053         case GT_JMP:
10054
10055         {
10056             const char* methodName;
10057             const char* className;
10058
10059             methodName = comp->eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtVal.gtVal1, &className);
10060             chars += printf(" %s.%s", className, methodName);
10061         }
10062         break;
10063
10064         case GT_NO_OP:
10065         case GT_START_NONGC:
10066         case GT_PROF_HOOK:
10067         case GT_CATCH_ARG:
10068         case GT_MEMORYBARRIER:
10069         case GT_ARGPLACE:
10070         case GT_PINVOKE_PROLOG:
10071 #ifndef LEGACY_BACKEND
10072         case GT_JMPTABLE:
10073 #endif
10074             // Do nothing.
10075             break;
10076
10077         case GT_RET_EXPR:
10078
10079             chars += printf("t%d", tree->gtRetExpr.gtInlineCandidate->gtTreeID);
10080             break;
10081
10082         case GT_PHYSREG:
10083
10084             chars += printf("%s", getRegName(tree->gtPhysReg.gtSrcReg, varTypeIsFloating(tree)));
10085             break;
10086
10087         case GT_LABEL:
10088
10089             if (tree->gtLabel.gtLabBB)
10090             {
10091                 chars += printf("BB%02u", tree->gtLabel.gtLabBB->bbNum);
10092             }
10093             else
10094             {
10095                 chars += printf("BB?");
10096             }
10097             break;
10098
10099         case GT_IL_OFFSET:
10100
10101             if (tree->gtStmt.gtStmtILoffsx == BAD_IL_OFFSET)
10102             {
10103                 chars += printf("?");
10104             }
10105             else
10106             {
10107                 chars += printf("0x%x", jitGetILoffs(tree->gtStmt.gtStmtILoffsx));
10108             }
10109             break;
10110
10111         case GT_CLS_VAR:
10112         case GT_CLS_VAR_ADDR:
10113         default:
10114
10115             if (tree->OperIsLeaf())
10116             {
10117                 chars += printf("<leaf nyi: %s>", tree->OpName(tree->OperGet()));
10118             }
10119
10120             chars += printf("t%d", tree->gtTreeID);
10121             break;
10122     }
10123
10124     if (comp->dumpIRTypes)
10125     {
10126         chars += cTreeTypeIR(comp, tree);
10127     }
10128     if (comp->dumpIRValnums)
10129     {
10130         chars += cValNumIR(comp, tree);
10131     }
10132     if (hasSsa && comp->dumpIRSsa)
10133     {
10134         chars += cSsaNumIR(comp, tree);
10135     }
10136
10137     return chars;
10138 }
10139
10140 /*****************************************************************************
10141  *
10142  *  COMPlus_JitDumpIR support - dump out tree leaf node for linear IR form
10143  */
10144
10145 int dLeafIR(GenTree* tree)
10146 {
10147     int chars = cLeafIR(JitTls::GetCompiler(), tree);
10148
10149     return chars;
10150 }
10151
10152 /*****************************************************************************
10153  *
10154  *  COMPlus_JitDumpIR support - dump out tree indir node for linear IR form
10155  */
10156
10157 int cIndirIR(Compiler* comp, GenTree* tree)
10158 {
10159     assert(tree->gtOper == GT_IND);
10160
10161     int      chars = 0;
10162     GenTree* child;
10163
10164     chars += printf("[");
10165     child = tree->GetChild(0);
10166     chars += cLeafIR(comp, child);
10167     chars += printf("]");
10168
10169     return chars;
10170 }
10171
10172 /*****************************************************************************
10173  *
10174  *  COMPlus_JitDumpIR support - dump out tree indir node for linear IR form
10175  */
10176
10177 int dIndirIR(GenTree* tree)
10178 {
10179     int chars = cIndirIR(JitTls::GetCompiler(), tree);
10180
10181     return chars;
10182 }
10183
10184 /*****************************************************************************
10185  *
10186  *  COMPlus_JitDumpIR support - dump out tree operand node for linear IR form
10187  */
10188
10189 int cOperandIR(Compiler* comp, GenTree* operand)
10190 {
10191     int chars = 0;
10192
10193     if (operand == nullptr)
10194     {
10195         chars += printf("t?");
10196         return chars;
10197     }
10198
10199     bool dumpTypes    = comp->dumpIRTypes;
10200     bool dumpValnums  = comp->dumpIRValnums;
10201     bool foldIndirs   = comp->dumpIRDataflow;
10202     bool foldLeafs    = comp->dumpIRNoLeafs;
10203     bool foldCommas   = comp->dumpIRDataflow;
10204     bool dumpDataflow = comp->dumpIRDataflow;
10205     bool foldLists    = comp->dumpIRNoLists;
10206     bool dumpRegs     = comp->dumpIRRegs;
10207
10208     genTreeOps op = operand->OperGet();
10209
10210     if (foldLeafs && operand->OperIsLeaf())
10211     {
10212         if ((op == GT_ARGPLACE) && foldLists)
10213         {
10214             return chars;
10215         }
10216         chars += cLeafIR(comp, operand);
10217     }
10218     else if (dumpDataflow && (operand->OperIsAssignment() || (op == GT_STORE_LCL_VAR) || (op == GT_STORE_LCL_FLD)))
10219     {
10220         operand = operand->GetChild(0);
10221         chars += cOperandIR(comp, operand);
10222     }
10223     else if ((op == GT_INDEX) && foldIndirs)
10224     {
10225         chars += printf("[t%d]", operand->gtTreeID);
10226         if (dumpTypes)
10227         {
10228             chars += cTreeTypeIR(comp, operand);
10229         }
10230         if (dumpValnums)
10231         {
10232             chars += cValNumIR(comp, operand);
10233         }
10234     }
10235     else if ((op == GT_IND) && foldIndirs)
10236     {
10237         chars += cIndirIR(comp, operand);
10238         if (dumpTypes)
10239         {
10240             chars += cTreeTypeIR(comp, operand);
10241         }
10242         if (dumpValnums)
10243         {
10244             chars += cValNumIR(comp, operand);
10245         }
10246     }
10247     else if ((op == GT_COMMA) && foldCommas)
10248     {
10249         operand = operand->GetChild(1);
10250         chars += cOperandIR(comp, operand);
10251     }
10252     else if ((op == GT_LIST) && foldLists)
10253     {
10254         GenTree* list       = operand;
10255         unsigned childCount = list->NumChildren();
10256
10257         operand          = list->GetChild(0);
10258         int operandChars = cOperandIR(comp, operand);
10259         chars += operandChars;
10260         if (childCount > 1)
10261         {
10262             if (operandChars > 0)
10263             {
10264                 chars += printf(", ");
10265             }
10266             operand = list->GetChild(1);
10267             if (operand->gtOper == GT_LIST)
10268             {
10269                 chars += cListIR(comp, operand);
10270             }
10271             else
10272             {
10273                 chars += cOperandIR(comp, operand);
10274             }
10275         }
10276     }
10277     else
10278     {
10279         chars += printf("t%d", operand->gtTreeID);
10280         if (dumpRegs)
10281         {
10282             regNumber regNum = operand->GetReg();
10283             if (regNum != REG_NA)
10284             {
10285                 chars += printf("(%s)", getRegName(regNum));
10286             }
10287         }
10288         if (dumpTypes)
10289         {
10290             chars += cTreeTypeIR(comp, operand);
10291         }
10292         if (dumpValnums)
10293         {
10294             chars += cValNumIR(comp, operand);
10295         }
10296     }
10297
10298     return chars;
10299 }
10300
10301 /*****************************************************************************
10302  *
10303  *  COMPlus_JitDumpIR support - dump out tree operand node for linear IR form
10304  */
10305
10306 int dOperandIR(GenTree* operand)
10307 {
10308     int chars = cOperandIR(JitTls::GetCompiler(), operand);
10309
10310     return chars;
10311 }
10312
10313 /*****************************************************************************
10314  *
10315  *  COMPlus_JitDumpIR support - dump out tree list of nodes for linear IR form
10316  */
10317
10318 int cListIR(Compiler* comp, GenTree* list)
10319 {
10320     int chars = 0;
10321     int operandChars;
10322
10323     assert(list->gtOper == GT_LIST);
10324
10325     GenTree* child;
10326     unsigned childCount;
10327
10328     childCount = list->NumChildren();
10329     assert(childCount == 1 || childCount == 2);
10330
10331     operandChars = 0;
10332     for (unsigned childIndex = 0; childIndex < childCount; childIndex++)
10333     {
10334         if ((childIndex > 0) && (operandChars > 0))
10335         {
10336             chars += printf(", ");
10337         }
10338
10339         child        = list->GetChild(childIndex);
10340         operandChars = cOperandIR(comp, child);
10341         chars += operandChars;
10342     }
10343
10344     return chars;
10345 }
10346
10347 /*****************************************************************************
10348  *
10349  *  COMPlus_JitDumpIR support - dump out tree list of nodes for linear IR form
10350  */
10351
10352 int dListIR(GenTree* list)
10353 {
10354     int chars = cListIR(JitTls::GetCompiler(), list);
10355
10356     return chars;
10357 }
10358
10359 /*****************************************************************************
10360  *
10361  *  COMPlus_JitDumpIR support - dump out tree dependencies based on comma nodes for linear IR form
10362  */
10363
10364 int cDependsIR(Compiler* comp, GenTree* comma, bool* first)
10365 {
10366     int chars = 0;
10367
10368     assert(comma->gtOper == GT_COMMA);
10369
10370     GenTree* child;
10371
10372     child = comma->GetChild(0);
10373     if (child->gtOper == GT_COMMA)
10374     {
10375         chars += cDependsIR(comp, child, first);
10376     }
10377     else
10378     {
10379         if (!(*first))
10380         {
10381             chars += printf(", ");
10382         }
10383         chars += printf("t%d", child->gtTreeID);
10384         *first = false;
10385     }
10386
10387     child = comma->GetChild(1);
10388     if (child->gtOper == GT_COMMA)
10389     {
10390         chars += cDependsIR(comp, child, first);
10391     }
10392
10393     return chars;
10394 }
10395
10396 /*****************************************************************************
10397  *
10398  *  COMPlus_JitDumpIR support - dump out tree dependencies based on comma nodes for linear IR form
10399  */
10400
10401 int dDependsIR(GenTree* comma)
10402 {
10403     int  chars = 0;
10404     bool first = TRUE;
10405
10406     chars = cDependsIR(JitTls::GetCompiler(), comma, &first);
10407
10408     return chars;
10409 }
10410
10411 /*****************************************************************************
10412  *
10413  *  COMPlus_JitDumpIR support - dump out tree node in linear IR form
10414  */
10415
10416 void cNodeIR(Compiler* comp, GenTree* tree)
10417 {
10418     bool       foldLeafs    = comp->dumpIRNoLeafs;
10419     bool       foldIndirs   = comp->dumpIRDataflow;
10420     bool       foldLists    = comp->dumpIRNoLists;
10421     bool       dataflowView = comp->dumpIRDataflow;
10422     bool       dumpTypes    = comp->dumpIRTypes;
10423     bool       dumpValnums  = comp->dumpIRValnums;
10424     bool       noStmts      = comp->dumpIRNoStmts;
10425     genTreeOps op           = tree->OperGet();
10426     unsigned   childCount   = tree->NumChildren();
10427     GenTree*   child;
10428
10429     // What are we skipping?
10430
10431     if (tree->OperIsLeaf())
10432     {
10433         if (foldLeafs)
10434         {
10435             return;
10436         }
10437     }
10438     else if (op == GT_IND)
10439     {
10440         if (foldIndirs)
10441         {
10442             return;
10443         }
10444     }
10445     else if (op == GT_LIST)
10446     {
10447         if (foldLists)
10448         {
10449             return;
10450         }
10451     }
10452     else if (op == GT_STMT)
10453     {
10454         if (noStmts)
10455         {
10456             if (dataflowView)
10457             {
10458                 child = tree->GetChild(0);
10459                 if (child->gtOper != GT_COMMA)
10460                 {
10461                     return;
10462                 }
10463             }
10464             else
10465             {
10466                 return;
10467             }
10468         }
10469     }
10470     else if (op == GT_COMMA)
10471     {
10472         if (dataflowView)
10473         {
10474             return;
10475         }
10476     }
10477
10478     bool nodeIsValue = tree->IsValue();
10479
10480     // Dump tree id or dataflow destination.
10481
10482     int chars = 0;
10483
10484     // if (comp->compRationalIRForm)
10485     // {
10486     //   chars += printf("R");
10487     // }
10488
10489     chars += printf("    ");
10490     if (dataflowView && tree->OperIsAssignment())
10491     {
10492         child = tree->GetChild(0);
10493         chars += cOperandIR(comp, child);
10494     }
10495     else if (dataflowView && ((op == GT_STORE_LCL_VAR) || (op == GT_STORE_LCL_FLD)))
10496     {
10497         chars += cLeafIR(comp, tree);
10498     }
10499     else if (dataflowView && (op == GT_STOREIND))
10500     {
10501         child = tree->GetChild(0);
10502         chars += printf("[");
10503         chars += cOperandIR(comp, child);
10504         chars += printf("]");
10505         if (dumpTypes)
10506         {
10507             chars += cTreeTypeIR(comp, tree);
10508         }
10509         if (dumpValnums)
10510         {
10511             chars += cValNumIR(comp, tree);
10512         }
10513     }
10514     else if (nodeIsValue)
10515     {
10516         chars += printf("t%d", tree->gtTreeID);
10517         if (comp->dumpIRRegs)
10518         {
10519             regNumber regNum = tree->GetReg();
10520             if (regNum != REG_NA)
10521             {
10522                 chars += printf("(%s)", getRegName(regNum));
10523             }
10524         }
10525         if (dumpTypes)
10526         {
10527             chars += cTreeTypeIR(comp, tree);
10528         }
10529         if (dumpValnums)
10530         {
10531             chars += cValNumIR(comp, tree);
10532         }
10533     }
10534
10535     // Dump opcode and tree ID if need in dataflow view.
10536
10537     chars += dTabStopIR(chars, COLUMN_OPCODE);
10538     const char* opName = tree->OpName(op);
10539     chars += printf(" %c %s", nodeIsValue ? '=' : ' ', opName);
10540
10541     if (dataflowView)
10542     {
10543         if (tree->OperIsAssignment() || (op == GT_STORE_LCL_VAR) || (op == GT_STORE_LCL_FLD) || (op == GT_STOREIND))
10544         {
10545             chars += printf("(t%d)", tree->gtTreeID);
10546         }
10547     }
10548
10549     // Dump modifiers for opcodes to help with readability
10550
10551     if (op == GT_CALL)
10552     {
10553         GenTreeCall* call = tree->AsCall();
10554
10555         if (call->gtCallType == CT_USER_FUNC)
10556         {
10557             if (call->IsVirtualStub())
10558             {
10559                 chars += printf(":VS");
10560             }
10561             else if (call->IsVirtualVtable())
10562             {
10563                 chars += printf(":VT");
10564             }
10565             else if (call->IsVirtual())
10566             {
10567                 chars += printf(":V");
10568             }
10569         }
10570         else if (call->gtCallType == CT_HELPER)
10571         {
10572             chars += printf(":H");
10573         }
10574         else if (call->gtCallType == CT_INDIRECT)
10575         {
10576             chars += printf(":I");
10577         }
10578         else if (call->IsUnmanaged())
10579         {
10580             chars += printf(":U");
10581         }
10582         else
10583         {
10584             if (call->IsVirtualStub())
10585             {
10586                 chars += printf(":XVS");
10587             }
10588             else if (call->IsVirtualVtable())
10589             {
10590                 chars += printf(":XVT");
10591             }
10592             else
10593             {
10594                 chars += printf(":?");
10595             }
10596         }
10597
10598         if (call->IsUnmanaged())
10599         {
10600             if (call->gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
10601             {
10602                 chars += printf(":T");
10603             }
10604         }
10605
10606         if (tree->gtFlags & GTF_CALL_NULLCHECK)
10607         {
10608             chars += printf(":N");
10609         }
10610     }
10611     else if (op == GT_INTRINSIC)
10612     {
10613         CorInfoIntrinsics intrin = tree->gtIntrinsic.gtIntrinsicId;
10614
10615         chars += printf(":");
10616         switch (intrin)
10617         {
10618             case CORINFO_INTRINSIC_Sin:
10619                 chars += printf("Sin");
10620                 break;
10621             case CORINFO_INTRINSIC_Cos:
10622                 chars += printf("Cos");
10623                 break;
10624             case CORINFO_INTRINSIC_Sqrt:
10625                 chars += printf("Sqrt");
10626                 break;
10627             case CORINFO_INTRINSIC_Cosh:
10628                 chars += printf("Cosh");
10629                 break;
10630             case CORINFO_INTRINSIC_Sinh:
10631                 chars += printf("Sinh");
10632                 break;
10633             case CORINFO_INTRINSIC_Tan:
10634                 chars += printf("Tan");
10635                 break;
10636             case CORINFO_INTRINSIC_Tanh:
10637                 chars += printf("Tanh");
10638                 break;
10639             case CORINFO_INTRINSIC_Asin:
10640                 chars += printf("Asin");
10641                 break;
10642             case CORINFO_INTRINSIC_Acos:
10643                 chars += printf("Acos");
10644                 break;
10645             case CORINFO_INTRINSIC_Atan:
10646                 chars += printf("Atan");
10647                 break;
10648             case CORINFO_INTRINSIC_Atan2:
10649                 chars += printf("Atan2");
10650                 break;
10651             case CORINFO_INTRINSIC_Log10:
10652                 chars += printf("Log10");
10653                 break;
10654             case CORINFO_INTRINSIC_Pow:
10655                 chars += printf("Pow");
10656                 break;
10657             case CORINFO_INTRINSIC_Exp:
10658                 chars += printf("Exp");
10659                 break;
10660             case CORINFO_INTRINSIC_Ceiling:
10661                 chars += printf("Ceiling");
10662                 break;
10663             case CORINFO_INTRINSIC_Floor:
10664                 chars += printf("Floor");
10665                 break;
10666             default:
10667                 chars += printf("unknown(%d)", intrin);
10668                 break;
10669         }
10670     }
10671
10672     // Dump operands.
10673
10674     chars += dTabStopIR(chars, COLUMN_OPERANDS);
10675
10676     // Dump operator specific fields as operands
10677
10678     switch (op)
10679     {
10680         default:
10681             break;
10682         case GT_FIELD:
10683
10684         {
10685             const char* className = nullptr;
10686             const char* fieldName = comp->eeGetFieldName(tree->gtField.gtFldHnd, &className);
10687
10688             chars += printf(" %s.%s", className, fieldName);
10689         }
10690         break;
10691
10692         case GT_CALL:
10693
10694             if (tree->gtCall.gtCallType != CT_INDIRECT)
10695             {
10696                 const char* methodName;
10697                 const char* className;
10698
10699                 methodName = comp->eeGetMethodName(tree->gtCall.gtCallMethHnd, &className);
10700
10701                 chars += printf(" %s.%s", className, methodName);
10702             }
10703             break;
10704
10705         case GT_STORE_LCL_VAR:
10706         case GT_STORE_LCL_FLD:
10707
10708             if (!dataflowView)
10709             {
10710                 chars += printf(" ");
10711                 chars += cLeafIR(comp, tree);
10712             }
10713             break;
10714
10715         case GT_LEA:
10716
10717             GenTreeAddrMode* lea    = tree->AsAddrMode();
10718             GenTree*         base   = lea->Base();
10719             GenTree*         index  = lea->Index();
10720             unsigned         scale  = lea->gtScale;
10721             unsigned         offset = lea->gtOffset;
10722
10723             chars += printf(" [");
10724             if (base != nullptr)
10725             {
10726                 chars += cOperandIR(comp, base);
10727             }
10728             if (index != nullptr)
10729             {
10730                 if (base != nullptr)
10731                 {
10732                     chars += printf("+");
10733                 }
10734                 chars += cOperandIR(comp, index);
10735                 if (scale > 1)
10736                 {
10737                     chars += printf("*%u", scale);
10738                 }
10739             }
10740             if ((offset != 0) || ((base == nullptr) && (index == nullptr)))
10741             {
10742                 if ((base != nullptr) || (index != nullptr))
10743                 {
10744                     chars += printf("+");
10745                 }
10746                 chars += printf("%u", offset);
10747             }
10748             chars += printf("]");
10749             break;
10750     }
10751
10752     // Dump operands.
10753
10754     if (tree->OperIsLeaf())
10755     {
10756         chars += printf(" ");
10757         chars += cLeafIR(comp, tree);
10758     }
10759     else if (op == GT_LEA)
10760     {
10761         // Already dumped it above.
10762     }
10763     else if (op == GT_PHI)
10764     {
10765         if (tree->gtOp.gtOp1 != nullptr)
10766         {
10767             bool first = true;
10768             for (GenTreeArgList* args = tree->gtOp.gtOp1->AsArgList(); args != nullptr; args = args->Rest())
10769             {
10770                 child = args->Current();
10771                 if (!first)
10772                 {
10773                     chars += printf(",");
10774                 }
10775                 first = false;
10776                 chars += printf(" ");
10777                 chars += cOperandIR(comp, child);
10778             }
10779         }
10780     }
10781     else
10782     {
10783         bool hasComma     = false;
10784         bool first        = true;
10785         int  operandChars = 0;
10786         for (unsigned childIndex = 0; childIndex < childCount; childIndex++)
10787         {
10788             child = tree->GetChild(childIndex);
10789             if (child == nullptr)
10790             {
10791                 continue;
10792             }
10793
10794             if (child->gtOper == GT_COMMA)
10795             {
10796                 hasComma = true;
10797             }
10798
10799             if (dataflowView && (childIndex == 0))
10800             {
10801                 if ((op == GT_ASG) || (op == GT_STOREIND))
10802                 {
10803                     continue;
10804                 }
10805             }
10806
10807             if (!first)
10808             {
10809                 chars += printf(",");
10810             }
10811
10812             bool isList = (child->gtOper == GT_LIST);
10813             if (!isList || !foldLists)
10814             {
10815                 if (foldLeafs && (child->gtOper == GT_ARGPLACE))
10816                 {
10817                     continue;
10818                 }
10819                 chars += printf(" ");
10820                 operandChars = cOperandIR(comp, child);
10821                 chars += operandChars;
10822                 if (operandChars > 0)
10823                 {
10824                     first = false;
10825                 }
10826             }
10827             else
10828             {
10829                 assert(isList);
10830                 chars += printf(" ");
10831                 operandChars = cOperandIR(comp, child);
10832                 chars += operandChars;
10833                 if (operandChars > 0)
10834                 {
10835                     first = false;
10836                 }
10837             }
10838         }
10839
10840         if (dataflowView && hasComma)
10841         {
10842             chars += printf(", DEPS(");
10843             first = true;
10844             for (unsigned childIndex = 0; childIndex < childCount; childIndex++)
10845             {
10846                 child = tree->GetChild(childIndex);
10847                 if (child->gtOper == GT_COMMA)
10848                 {
10849                     chars += cDependsIR(comp, child, &first);
10850                 }
10851             }
10852             chars += printf(")");
10853         }
10854     }
10855
10856     // Dump kinds, flags, costs
10857
10858     if (comp->dumpIRKinds || comp->dumpIRFlags || comp->dumpIRCosts)
10859     {
10860         chars += dTabStopIR(chars, COLUMN_KINDS);
10861         chars += printf(";");
10862         if (comp->dumpIRKinds)
10863         {
10864             chars += printf(" ");
10865             chars += cTreeKindsIR(comp, tree);
10866         }
10867         if (comp->dumpIRFlags && (tree->gtFlags != 0))
10868         {
10869             if (comp->dumpIRKinds)
10870             {
10871                 chars += dTabStopIR(chars, COLUMN_FLAGS);
10872             }
10873             else
10874             {
10875                 chars += printf(" ");
10876             }
10877             chars += cTreeFlagsIR(comp, tree);
10878         }
10879         if (comp->dumpIRCosts && (tree->gtCostsInitialized))
10880         {
10881             chars += printf(" CostEx=%d, CostSz=%d", tree->GetCostEx(), tree->GetCostSz());
10882         }
10883     }
10884
10885     printf("\n");
10886 }
10887
10888 /*****************************************************************************
10889  *
10890  *  COMPlus_JitDumpIR support - dump out tree in linear IR form
10891  */
10892
10893 void cTreeIR(Compiler* comp, GenTree* tree)
10894 {
10895     bool       foldLeafs    = comp->dumpIRNoLeafs;
10896     bool       foldIndirs   = comp->dumpIRDataflow;
10897     bool       foldLists    = comp->dumpIRNoLists;
10898     bool       dataflowView = comp->dumpIRDataflow;
10899     bool       dumpTypes    = comp->dumpIRTypes;
10900     bool       dumpValnums  = comp->dumpIRValnums;
10901     bool       noStmts      = comp->dumpIRNoStmts;
10902     genTreeOps op           = tree->OperGet();
10903     unsigned   childCount   = tree->NumChildren();
10904     GenTree*   child;
10905
10906     // Recurse and dump trees that this node depends on.
10907
10908     if (tree->OperIsLeaf())
10909     {
10910     }
10911     else if (tree->OperIsBinary() && tree->IsReverseOp())
10912     {
10913         child = tree->GetChild(1);
10914         cTreeIR(comp, child);
10915         child = tree->GetChild(0);
10916         cTreeIR(comp, child);
10917     }
10918     else if (op == GT_PHI)
10919     {
10920         // Don't recurse.
10921     }
10922     else
10923     {
10924         assert(!tree->IsReverseOp());
10925         for (unsigned childIndex = 0; childIndex < childCount; childIndex++)
10926         {
10927             child = tree->GetChild(childIndex);
10928             if (child != nullptr)
10929             {
10930                 cTreeIR(comp, child);
10931             }
10932         }
10933     }
10934
10935     cNodeIR(comp, tree);
10936 }
10937
10938 /*****************************************************************************
10939  *
10940  *  COMPlus_JitDumpIR support - dump out tree in linear IR form
10941  */
10942
10943 void dTreeIR(GenTree* tree)
10944 {
10945     cTreeIR(JitTls::GetCompiler(), tree);
10946 }
10947
10948 #endif // DEBUG
10949
10950 #if VARSET_COUNTOPS
10951 // static
10952 BitSetSupport::BitSetOpCounter Compiler::m_varsetOpCounter("VarSetOpCounts.log");
10953 #endif
10954 #if ALLVARSET_COUNTOPS
10955 // static
10956 BitSetSupport::BitSetOpCounter Compiler::m_allvarsetOpCounter("AllVarSetOpCounts.log");
10957 #endif
10958
10959 // static
10960 HelperCallProperties Compiler::s_helperCallProperties;
10961
10962 /*****************************************************************************/
10963 /*****************************************************************************/