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